Chapter04

1. イントロダクション
2. 概要
3. 字句構造
4. **全体的な構文...**
5. データ型
6. 言語構文
7. 標準ライブラリ関数
8. 形式言語文法
9. シェーダグループの記述
10. 用語集
11. Light Path Ex...

シェーダの全体的な構造は以下のとおりです:

```
任意の関数/構造体の宣言

シェーダタイプ シェーダ名 ( 任意のパラメータ )
{
    ステートメント
}

```

*ステートメント*には、関数、構造体定義、ローカル変数宣言、パブリックメソッド、さらには(割り当てなどの)通常の実行命令を含めることができます。

一部の処理は、特定のタイプのシェーダからでないと実行することができません(例えば、**displacement**シェーダのみが**displace()**をコールして**P**を変更することができます)。
そして、いくつかのグローバル変数も特定のタイプのシェーダからでないとアクセスすることができません(例えば、**volume**シェーダでは**dPdu**は定義されません)。

以下では、基本的なシェーダのタイプについて簡潔に説明しています:

#### surfaceシェーダ

**surface**シェーダは、サーフェスの基本的なマテリアル特性と光の反応の仕方を決定します。
このシェーダは、マテリアルを記述したクロージャカラーの計算と、オプションで他のユーザー定義の出力変数を設定する役割を担っています。
このシェーダは、サーフェスの位置を変更することができません。

**surface**シェーダでは、プリミティブ上の単一ポイントの挙動について記述し、レンダラーは、そのシェーダを評価すべきサーフェス上の位置を決めます。

**surface**シェーダは、発光オブジェクト、つまり光源を記述するのにも使用します。OSLでは、ライトを記述するのに別のシェーダタイプを必要としません。

#### displacementシェーダ

**displacement**シェーダは、位置とシェーディング法線(または意図的にシェーディング法線だけ)を変更させて、一部のジオメトリを変形、シワ、窪みの外観にします。
このシェーダは、プリミティブの位置を変更することが可能な唯一のシェーダタイプです。

#### volumeシェーダ

volumeシェーダは、透過媒体(空気、煙、ガラスなど)が光に反応して、その媒体の向こう側のオブジェクトの外観に影響を与える方法を記述します。
このシェーダは、特定のプリミティブ上に乗っていない(そのプリミティブに関連している必要もありません)位置からコールすることができる事を除いて**surface**シェーダと同様です。

#### generic shaderシェーダ

**generic shader**(汎用シェーダ)は、ユーティリティコード、シェーダグループ内のそれぞれのレイヤーとしてコール可能な汎用ルーチンに使用します。
**generic shader**(汎用シェーダ)では、シェーダタイプを指定する必要がないので、**surface**、**displacement**、**volume**のシェーダグループ内から再利用することができます。
しかし、結果として、**generic shader**(汎用シェーダ)には、すべてのシェーダタイプからは実行できないような機能性を含めることができません(例えば、**generic shader**は**P**を変更することができません。これは**displacement**シェーダからでないと実行することができないからです)。

### 4.2 シェーダパラメータ

それぞれのシェーダは、単一シェーダでも異なるオブジェクトに対して使用した時に別々の挙動や別々の外観になるように、いくつかの方法で値を設定することができる**パラメータ**を(任意で)たくさん持たせることができます。

#### 4.2.1 シェーダパラメータの構文

シェーダパラメータは、シェーダ宣言内のシェーダの名前の後の括弧内で指定します。
これは、シェーダパラメータには必ず(パラメータにデフォルト値を与える)**initializer(初期化子)**がなければならない事を除いてC言語系の関数のパラメータと同様です。
シェーダパラメータのデフォルト初期化子には、エクスプレッションを使用することができます(つまり、数値定数に制限されることなく計算が可能です)。
そして、そのエクスプレッションはそれらのパラメータが宣言された順番で評価され、その前に宣言されているパラメータの参照を含めることができます。
形式的には、単純なパラメータ宣言の文法は以下のようになります:

```
type parametername = default-expression

```

**type**は、第5章で説明しているデータタイプのどれかです。
**parametername**は、パラメータの名前、**default-expression**は有効なエクスプレッション(セクション6.2を参照)。
複数パラメータは、単にカンマで区切ります:

```
type1 parameter1 = expr1 , type2 parameter2 = expr2 , ...

```

固定長1次元配列のパラメータは以下のように宣言します:

```
type parametername [ array-length ] = { expr0 , expr1 ... }

```

**array-length**は、配列の大きさを指定したプラスの整数定数。
配列の初期化は、初期化するエクスプレッションを中括弧内に並べて記述します。
最初の初期化するエクスプレッションは、配列の1番目の要素に対して初期化され、2番目のエクスプレッションは配列の2番目の要素に対して初期化され、それ以降も同様です。
初期化するエクスプレッションの数が配列の大きさよりも少なかった場合、その余った配列要素の値は未定義になります。

配列は、大きさを指定しなくても宣言することができます:

```
type parametername [ ] = { expr0 , expr1 ... }

```

大括弧内には配列長がありません。
これは、その配列長が中括弧内に渡された内容、例えばグループ内の他のシェーダの出力からのコネクション(その出力の長さを受け取ります)、インスタンス値(そのインスタンス値の宣言によって指定された長さを受け取ります)、プリミティブ変数(そのプリミティブ上の宣言で決まった長さ)に応じて決まります。
インスタンス値、プリミティブ値、コネクションを指定しなかった場合、初期化するエクスプレッションの数で配列の長さが決まり、さらにその配列のデフォルト値が決まります。

構造体パラメータも宣言するのが簡単です:

```
structure-type parametername = { expr0 , expr1 ... }

```

**structure-type**は、前に宣言されている**struct**タイプの名前で、**expr**初期化子は、その構造体内のそれぞれのフィールドに呼応します。
その構造体のすべてのフィールドに対して、それぞれ適切なタイプの初期化子を必要とします。

#### 4.2.2 シェーダ出力パラメータ

シェーダパラメータは、デフォルトではシェーダのボディー内で読み込み専用になっています。
とはいえ、シェーダの実行によって、それを特別な \_出力パラメータ\_ に変更することができます。
パラメータは、そのパラメータのタイプ宣言の直前に**output**キーワードを使用することで、そのパラメータを出力パラメータとして指定することができます:

```
output type parametername = expr

```

(出力パラメータを配列や構造体にすることができますが、ここではそのわかりきった構文を説明するのを省略します。)

出力パラメータは、シェーダグループ内の後で実行されるシェーダレイヤーの入力に接続することができ、メッセージを渡せば(つまり、**getmessage()**をコールすれば)そのグループ内の後で実行されるシェーダでその出力パラメータを照会することができます。
また、(レンダラー側のAPIを使うことで)出力パラメータを出力画像チャンネルとしてレンダラーで使用することができます。

#### 4.2.3 シェーダパラメータの例

ここでは、いくつかのパラメータを使ったシェーダ宣言の例を載せています:

```
surface wood (
        /* 定数初期化子を使った単純なパラメータ */
            float Kd = 0.5,
            color woodcolor = color (.7, .5, .3),
            string texturename = "wood.tx",
        /* 上記のパラメータから計算 */
            color ringcolor = 0.25 * woodcolor,
        /* 固定長配列 */
            color paintcolors[3] = { color(0,.25,0.7), color(1,1,1),
                                     color(0.75,0.5,0.2) },
        /* 可変長配列 */
            int pattern[] = { 2, 4, 2, 1 },
        /* 出力パラメータ */
            output color Cunlit = 0
          )
{
    ...
}

```

#### 4.2.4 シェーダパラメータがその値を取得する方法

シェーダパラメータは、以下の優先順で以下の方法で値を取得します:

* レンダラー側でそのパラメータがシェーダグループ内の前に実行されたシェーダレイヤーの出力パラメータに接続するように指定されていれば、シェーダパラメータが取得する値は、その出力パラメータの値です。
* シェーディングされる特定のジオメトリ上のプリミティブ単位、フェース単位、頂点単位の*プリミティブ変数*の名前とタイプにそのパラメータが合致すれば、シェーディングしなければならない位置毎にそのプリミティブ変数を補間することによって、そのパラメータの値が計算されます。
* コネクションもプリミティブ変数もなかった場合、レンダラーがシェーダを参照した時点において、そのパラメータに明示的にインスタンス毎の値が与えられていれば(インスタンスがオブジェクトまたはオブジェクトセットと関連付けられていれば)、そのパラメータはその*インスタンス値*を受け取ります。
* それらのオーバーライドがなにも存在しなかった場合、シェーダ内のパラメータ初期化コードを実行することで、そのパラメータの値が決定されます。

この順序決定は、宣言の順番通りにパラメータ毎に実行されます。
そのため例えば、上記のサンプルコードでは、**ringcolor**のデフォルト値は**woodcolor**にスケールを乗算した値になっており、**woodcolor**がデフォルト、インスタンス値、補間されたプリミティブ値、他のレイヤーの出力に接続されているかどうかにかかわらず、この関係性が維持されます。**ringcolor**自体にインスタンス、プリミティブ、コネクション値のどれかを与えない限りは、その関係性が使われます。

### 4.3 シェーダメタデータ

シェーダには任意で**メタデータ**(これは、シェーダで*使用される*データとは対照的にシェーダに*関する*データです)を含めることができます。
メタデータを使用すれば、シェーダや個々のパラメータに関するヒントや情報を付け加えることができるので、それをシェーダ内にコンパイルさせてアプリケーション側で照会できるようにすることができます。
メタデータの一般的な用途は、シェーダパラメータに関するユーザーインターフェースのヒント(例えば、特定のパラメータが整数値のみを受け取るようにしたり、on/offのチェックボックスを持つようにしたり、ファイル名を指定するようにしたりするなど)を指定することです。

メタデータは、メタデータ項目のリストをカンマで区切り、それを二重大括弧の**[ [**と**] ]**で閉じます。
各メタデータは、パラメータ宣言と同様にデータタイプ、名前、初期化子を持ちます。
とはいえ、メタデータは、単純なタイプまたは単純なタイプの配列(構造体やクロージャではなく)にしか対応しておらず、その値の初期化子は数値または文字列の定数でなければなりません(エクスプレッションは計算されません)。

シェーダ全体に関するメタデータは、シェーダ名とパラメータリストの間に配置します。シェーダパラメータに関するメタデータは、パラメータの初期化エクスプレッションの直後、且つ、カンマまたはパラメータの記述を終了する閉じ括弧の前に配置します。

以下は、シェーダとパラメータのメタデータの使い方を示したシェーダ宣言の例です:

```
surface wood
            [[ string help = "Realistic wood shader" ]]
  (
    float Kd = 0.5
        [[ string help = "Diffuse reflectivity",
           float min = 0, float max = 1 ]] ,
    color woodcolor = color (.7, .5, .3)
        [[ string help = "Base color of the wood" ]],
    color ringcolor = 0.25 * woodcolor
        [[ string help = "Color of the dark rings" ]],
    string texturename = "wood.tx"
        [[ string help = "Texture map for the grain",
    string widget = "filename" ]],
    int pattern = 0
        [[ string widget = "mapper",
           string options = "oak:0|elm:1|walnut:2" ]]
  )
{
  ...
}

```

メタデータは、意味的には意味を持ちません。つまり、メタデータは実際のシェーダの実行には影響を与えません。
ほとんどのメタデータは、コンパイルされたシェーダ内に埋め込むためだけに存在し、他のアプリケーションからそのメタデータを照会することができます。
これによって例えば、使用方法のTipsを表示したり、各パラメータの設定に適切なタイプのウィジェットを用意できるので、シェーダ割り当て用のユーザーインターフェースを構築することができます。

メタデータとその意味合いの受け取り方は、完全にシェーダ作成者やモデリングシステム次第です。
とはいえ、私たちは以下の慣習を提案しています。
これらの慣習は、すべてに当てはまるものではなく、あなたのニーズに完全に応えるものではありません。
要するに、最も一般的なメタデータの使用方法に対して共通の命名規則を制定するためだけのものです。

メタデータの使用方法は、完全にシェーダ作成者の自由であり、シェーダメタデータを照会するアプリケーションは、そのメタデータを評価するのも無視するのも自由です。

**string label**

このパラメータのUIに表示するショートラベル。存在しなければ、パラメータ名そのものがウィジェットラベルとして使用されます。
**string help**

目的やシェーダ/パラメータの使い方を記述したヘルプテキスト。
**string page**

**page**によって関連ウィジェットをグループ化するためのヘルプ
**string widget**

このパラメータの調整に使用するウィジェットのタイプ。利用可能なウィジェットタイプ:
**number**:
スライダ/数値入力を備えています。
これは、float/intパラメータのデフォルトのウィジェットタイプです。
数値入力は、次のメタデータの影響も受けます: **min**, **max**, **sensitivity**, **digits**, **slider**, **slidermin**, **slidermax**, **slidercenter**, **sliderexponent**。
**string**:
テキストエントリーウィジェットを備えています。これは、文字列パラメータのデフォルトのウィジェットタイプです。
**boolean**:
**Yes**と**No**のオプションを持ったポップアップメニューを備えています。文字列または数値に対して動作します。文字列に関しては**Yes**と**No**の値が使用され、数値に関しては0と1が使用されます。
**checkBox**:
チェックボックスとして表示するブーリアンウィジェット。文字列または数値に対して動作します。文字列に関しては**Yes**と**No**の値が使用され、数値に関しては0と1が使用されます。
**popup**:
リテラル選択肢のポップアップメニュー。
このウィジェットでは、さらにパラメータメタデータ**options**(対応しているメニュー項目を**|**文字で区切った文字列)と
オプションの**editable**(整数。ゼロ以外の値はウィジェットがテキストフィールドを直接編集可能であることを意味します)を必要とします。例:

```
        string wrap = "default"
            [[ string widget = "popup",

```

**mapper**:
関連性のある選択肢(値が整数なら列挙タイプ)のポップアップ。このウィジェットでは、さらにパラメータメタデータ**options**(**キー:値**ペアを**|**で区切った文字列)を必要とします。例:

```
        int pattern = 0
            [[ string widget = "mapper",
               string options = "oak:0|elm:1|walnut:2" ]]

```

**filename**:
ファイル選択ダイアログ。
**null**:
非表示ウィジェット。
**float min**

**float max**

**int min**

**int max**

パラメータが受け取ることができる最小/最大値。
**float sensitivity**

**int sensitivity**

(適切なmin/max範囲内で)値を増減させる時の精度またはステップサイズ。
**int digits**

表示する桁数(フル精度は-1)。
**int slider**

ゼロ以外の値であれば、スライダサブウィジェットの表示が有効になります。
さらに、これは特にスライダを制御する次のメタデータも評価します: **slidermin** (スライダの最小値), **slidermax** (スライダの最大値), **slidercenter** (スライダの初期値), **sliderexponent** (非線形スライダオプション)。
**string URL**

シェーダ/パラメータのフルドキュメントのURLを備えています。
**string units**

パラメータに対して必要に応じて想定した単位(例えば、**cm**, **sec**, **degrees**)を与えます。
この想定で問題が検出されたときにコンパイラやレンダラーが警告を発することができます(例えば、**degrees**変数が**cos**の引数として渡されたときにコンパイラが警告を出すことができます)。
### 4.4 関数

CやC++に非常に似たように関数を定義することができます。

```
return-type function-name ( optional-parameters )
{
    ステートメント
}

```

関数に渡すパラメータは、初期化子が許可されていない事を除いてシェーダパラメータと同様です。
関数コールは、仮引数すべてに対して値を渡さなければなりません。
Open Shading Languageの関数パラメータは、すべて*参照によって引き渡され*、それらのパラメータを**output**として指定しない限り、関数のボディ内では読み込み専用です(出力シェーダパラメータと同様)。

シェーダと同様に、関数内部のステートメントには、実際の実行(割り当て、関数コールなど)、ローカル変数宣言(関数のボディ内でのみ可視)、ローカル関数宣言(関数のボディ内でのみコール可)を記述することができます。

**return-type**には、単なるデータタイプ、**struct**、**closure**のどれかを指定します。関数は配列を返すことができません。
**return-type**に**void**を指定することもできます。これは関数が値を返さないことを意味します(関数には**return**ステートメントを含めてはいけません)。
関数のボディ内の**return**ステートメントは、その時点で関数の実行を停止し、(その関数が**void**でない場合は)そこで返す値を指定します。

関数を*オーバーロード(多重定義)*させることができます。つまり、関数をコールしたときに、引数のリストからどのバージョンの関数が望ましいのかが明確にできるほどにパラメータのタイプが異なっている限り、複数の関数を同じ名前で定義することができます。

### 4.5 パブリックメソッド

シェーダ内の通常(非パブリック)の関数は、シェーダ内からでしかコールすることができません。これらの関数は、レンダラー側が認識できるエントリーポイントを生成しません。

**パブリックメソッド**は、レンダラー側で直接コール可能な関数です。
シェーダのトップレベルの関数のみ、つまり、シェーダのローカルスコープを定義した中括弧内に宣言された関数(それ以外の関数を除く)のみがパブリックメソッドに指定することができます。
関数宣言の直前に**public**キーワードを使用することで、関数をパブリックメソッドとして指定することができます:

```
shader-type shader-name ( params )
{
    public return-type function-name ( optional-parameters )
    {
        ステートメント
    }
    ...
}

```