Chapter02

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

## 2. 概要

この章では、Open Shading Languageの主な概念について触れ、キーとなる専門用語を定義し、個々のシェーダを全体としてレンダラーのコンテキストに合わせる方法について説明していきたいと思います。

### シェーダは、個別にタスクを実行するコードです

シェーダは、入力と出力を持ったプログラムであり、シーンをレンダリングする時に、マテリアルやライトの見栄えの挙動を決定するといった特定のタスクを実行します。
プログラムコードは、Open Shading Languageで記述し、その仕様については、このドキュメントで説明しています。

例えば、単純なガンマ補正を実行する以下の単純な**gamma**シェーダの入力が**Cin**で、その結果を**Cout**出力に格納します:

このシェーダの入力と出力を**シェーダパラメータ**と呼びます。パラメータはデフォルト値を持ち、それをシェーダコード内で指定しますが、ランタイム時にレンダラーによって新しい値を与えることもできます。

### シェーダインスタンス

特定のシェーダをシーン内の色々なオブジェクトまたはシェーダグループ内の別のレイヤーに対して何度も使用することができます。
そのようにシェーダを別々に使用する方法のことを**シェーダインスタンス**と呼びます。
このシェーダのすべてのインスタンスは同じプログラムコードで構成されていますが、各インスタンスはそれぞれ独自の**インスタンス値**でデフォルトのパラメータ値を上書きすることができます。

以下の略図では、インスタンス固有の**2.2**の値で**gam**パラメータを上書きした**gamma**インスタンスを示しています。

### シェーダグループ、レイヤー、コネクション

**シェーダグループ**とは、**レイヤー**と呼ばれる個々のシェーダを表現した順列シーケンスのことで、その順番通りに実行されていきます。
先に実行されたレイヤーの出力パラメータは、それ以降に実行されるレイヤーの入力パラメータに"接続"することができます。
このように接続されたレイヤーネットワークのことを、**シェーダネットワーク**もしくは**シェーダDAG**(Directed Acyclic Graph:有向非巡回グラフ)と呼ぶこともあります。
もちろん、シェーダグループが単一のシェーダレイヤーで構成されていても構いません。

以下の略図では、どのようにシェーダインスタンスを繋げてシェーダグループを形成させているのかを示しています。

以下の疑似コードでは、レンダラーのAPIを使って上記のネットワークを組み立てる方法を示しています:

```
ShaderGroupBegin ()
Shader ("texturemap",              /* シェーダ名 */
        "tex1",                    /* レイヤー名 */
        "string name", "rings.tx") /* インスタンス変数 */
Shader ("texturemap", "tex2", "string name", "grain.tx")
Shader ("gamma", "gam1", "float gam", 2.2)
Shader ("gamma", "gam2", "float gam", 1) Shader ("wood", "wood1")
ConnectShaders ("tex1", /* レイヤー名 A */
                "Cout", /* Aの出力パラメータ */
                "gam1", /* レイヤー名 B */
                "Cin")  /* このレイヤーBをAのCoutに接続します */
ConnectShaders ("tex2", "Cout", "gam2", "Cin")
ConnectShaders ("gam1", "Cout", "wood1", "rings")
ConnectShaders ("gam2", "Cout", "wood1", "grain")
ShaderGroupEnd ()

```

*このドキュメントでは、シェーダインスタンス、グループ、コネクションを宣言するためのレンダラー固有のAPIについて説明しません。上記のコードは、それがどのように処理されているのかを示した例に過ぎません。*

また、シリアライゼーションしたテキストは以下のように表現されます(詳細は、第9章)

```
param string name "rings.tx" ;
shader "texturemap" "tex1" ;
param string name "grain.tx" ;
shader "texturemap" "tex2" ;
param float gam 2.2 ;
shader "gamma" "gam1" ;
param float gam 1.0 ;
shader "gamma" "gam2" ;
shader "wood" "wood1" ;
connect tex1.Cout gam1.Cin ;
connect tex2.Cout gam2.Cin ;
connect gam1.Cout wood1.rings ;
connect gam2.Cout wood1.grain ;

```

接続可能なデータタイプの規則は、一般的には、OSLソースコード内で変数をお互いに割り当てることができるかどうかの規則と同じです:

* **source**と**dest**が同じデータタイプである時。
* **source**と**dest**が種類にかかわらずどちらも**三成分**(color、point、vector、normal)である時。
* **source**が**int**で**dest**が**float**である時。
* **source**が**float**または**int**で**dest**が**三成分**である時(そのスカラー値は三成分のすべての値に複製されます)。

### ジオメトリプリミティブ

**シーン**は、主にジオメトリプリミティブ、光源、カメラで構成されています。

**ジオメトリプリミティブ**とは、NURBS、サブディビジョンサーフェス、ポリゴン、カーブなどの形状のことです。

実際に対応しているプリミティブは、レンダラーによって異なります。

各ジオメトリプリミティブには、名前の付いた**プリミティブ変数**(別名**補間値**または**ユーザーデータ**)があります。
ほぼすべての形状タイプには、プリミティブ変数間で補間処理する時に実際にその形状を定義するためのコントロールポイントポジションがあります。
いくつかの形状では、法線や他の形状固有のデータを指定することもできます。
任意のユーザーデータは、プリミティブ変数として形状に追加することもできます。
プリミティブ変数は色々な方法で補間することができます: プリミティブ毎の定数値、フェース毎の定数値、フェース上を補間する頂点毎の値。

シェーダ入力パラメータの名前とタイプがオブジェクト上のプリミティブ変数の名前とタイプに合致した場合(且つ、その入力パラメータがまだ明示的に他のレイヤーの出力に接続されていない場合)、その補間されたプリミティブ変数がインスタンス値またはデフォルト値を上書きします。

### アトリビュートステートとシェーダ割り当て

すべてのジオメトリプリミティブには、トランスフォームマトリックス、照明するライトのリスト、片面/両面の情報、シェーダ割り当てなどを含んだ一連の**アトリビュート**(別名**グラフィックスステート**)があります。
さらに、各オブジェクトに関連したレンダラー固有またはユーザー指定のアトリビュートのリストを含めることもできます。
特定のアトリビュートステートをほとんどのジオメトリプリミティブ間で共有させることができます。

アトリビュートステートには、シェーダ割り当て(いくつかの**シェーダ用途**毎のシェーダまたはシェーダグループ)も含みます。
例えば、形状上の各ポイントからの光の反射や発光の方法を表現したサーフェスシェーダ、ポイント単位で形状にディテールを加えるディスプレイスメントシェーダ、空間の領域内を光が散乱する方法を表現したボリュームシェーダがそれです。レンダラーによっては、そのレンダラーが対応しているシェーダタイプを追加することができます。

### シェーダ実行ステート: パラメータのバインドとグローバル変数

それぞれのシェーダのコードのボディが実行されようとした時、そのすべてのパラメータが**バインド(紐付け)**されます。
つまり、(他のレイヤーとの接続の順番通りに、補間されたプリミティブ変数やインスタンス値またはデフォルト値といった)具体的な値を受け取ります。

シェーディングが行なわれたサーフェス上の位置における特定のステート(状態)が、いわゆる**グローバル変数**に格納されます。
このグローバル変数には、シェーディングされるポイントの3D座標、そのポイントにおけるサーフェス法線や接線などの役立つデータが含まれます。

さらに、シェーダはプリミティブに追加されたアトリビュートステートの他の要素に関する他の情報と、全体のレンダラーに関する情報(レンダリングオプションなど)を照会することができます。

### サーフェス/ボリュームシェーダはクロージャを計算します

サーフェスシェーダ(ボリュームシェーダ)は、それ自体でサーフェスから(またはボリュームに沿って)放射される光の最終カラーを計算しません。
むしろ、それらのシェーダは**クロージャ**を計算します。このクロージャとは、サーフェスの外観を表わした象徴的表現のことであり、後で完全に評価されます。
実際には、クロージャはパラメータ化された数式になっており、一部の入力の数値は確定していますが、それ以外の数値は(例えばサーフェスを見る方向やサーフェスに到達する各光源からの光の量によって決まる)未確定の量に依存しています。

例えば、サーフェスシェーダは以下のような結果を計算することができます:

```
color paint = texture ("file.tx", u, v);
Ci = paint * diffuse (N);

```

この例では、**paint**変数は(テクスチャマップから検索することで)具体的な数値を取得します。
しかし、**diffuse()**関数は明確な数値カラーではなく**closure color**を返します。
サーフェスの外観を表現した**Ci**出力変数も**closure color**であり、**paint**とランバート反射の乗算であること以外はその数値はまだ未確定です。

サーフェス/ボリュームシェーダから出力されたクロージャは、単なる数値ではできないような面白い数値を表現することができます:

* Evaluate(評価): 入力と出力のライト方向を与えて、入力から出力へ伝搬する光の比率を計算します。
* Sample(サンプル): 入力(または出力)の方向だけを与えて、光の量に比例した確率分布によって散乱方向を決定し、最終的に光が色々な方向に発散します。
* Integrate(積分): すべてのライトとビュー方向を与えて、ビュー方向から見てサーフェスから出ていく光の総量を計算します。
* Recompute(再計算): 複数ライト(または1個のライト)だけの変化を与えると、他のライトやクロージャ内で定数を構成する何かしらの計算(例えばテクスチャルックアップやノイズ関数)を再計算させることなく、その積分された結果を再計算します。

### インテグレータ

レンダラーには、(レンダラーのAPIを通じて選択可能な)**インテグレータ**が含まれています。
このインテグレータは、サーフェスやボリュームで計算されるカラークロージャと、光源やビュー依存情報を組み合わせて、カメラから見える光の量を計算します。

### ユニット

シーンが距離と時間に使用している単位を(グローバルオプションを通じて)レンダラーに伝えることができます。
シェーダには、**transform()**に非常に似た**transformu()**というビルトイン関数がありますが、これは座標系を変換するのではなく、単位を変換します。例えば、

```
displacement bumpy (float bumpdist = 1,
                    string bumpunits = "cm")
{
    // convert bumpdist to common units
    float spacing = transformu (bumpunits, "common", bumpdist);
    float n = noise (P / spacing);

displace (n);

}

```

これで、実際のワールド単位で何かしらの効果を表現したシェーダを記述することができ、そのシェーダは、モデリング単位が異なる他の表示でも再利用することができます。

**transformu()**関数は、**cm**、**in**、**km**などの標準的な名前にすべて対応しており、その単位を変換したり、座標系を変換することもできます。例えば、

```
float x = transformu ("object", "mm", 1);

```

この**x**は、そのプリミティブにおける**object**空間のユニット単位でのミリメートルの大きさです。