Chapter06

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

シェーダの本体は個々の**文**の連なりです。
この章ではOpen Shading Languageにおける文の種類と制御フローのパターンについて説明します。
Open Shading Languageにおける文は次のような構成です：

* スコープ付き文
* 変数宣言
* 式
* 代入
* 制御フロー： **if**、**else**、**while**、**do**、**for**、**break**、**continue**
* 関数宣言

参照された変数または関数は、常にその使用に対して最も内側のスコープで一致する名前に解決されます。例:
```
float a = 1;      // これを「外側の」aと呼ぶ
float b = 2:
{
    float a = 3;  // これを「内側の」aと呼ぶ
    float c = 1;
    b = a;        // aは内部スコープに解決されるので、このbには3が代入される
}
b += c;           // エラー：cは内部スコープ内にのみ存在する
```

複数の変数名をカンマで区切ることで、1つの宣言で同じ型の変数を複数宣言することができます：
```
type name1, name2 ...
type name1 [=value1], name2 [=value2] ...
```
変数宣言の幾つかの例：
```
float a;            // 宣言; 現在の値は未定義
float b = 1;        // 宣言と定数の初期化子の代入
float c = a*b;      // 算出初期化子
float d, e = 2, f;  // 同一型の複数の変数宣言
```

構造体型の宣言の構文：
```
struct structname {
    type1 fieldname1;
    ...
    typeN fieldnameN;
};
```
そして、その構造体タイプの名前を使用することで、ビルトインタイプの時と同様に、構造体変数を宣言することができます:

```
structname variablename ;
structname variablename = { initializer1 , ... intializerN } ;

```

初期化子を指定すれば、その構造体の各フィールドが、それに呼応する位置の初期化子で初期化されるので、その初期化子がそれに適切なタイプである必要があります。
構造体の要素は、他のC言語系の言語と同様に**ドット**演算子を用いてアクセスすることができます:

```
variablename.fieldname

```

構造体の宣言と使用方法の例:

```
struct ray {
    point pos;
    vector dir;
};

ray r;//構造体を宣言します。
ray s = { point (0,0,0), vector(0,0,1) } ;//初期化して宣言します。
r.pos = point (1,0,0);//一つのフィールドへ割り当てます。

```

構造体フィールドには配列を持たせることができ、さらに構造体を配列にすることもできます。ただし、構造体が他の構造体のフィールドを持つことはできません。
構造体の使い方に関する詳細は、セクション5.9を参照してください。

* 定数:整数(例えば1,42)、浮動小数点(例えば1.0,3,-2.35e4)または、文字列リテラル(例えば、"hello")
* **point**, **vector**, **normal**, **matrix**のコンストラクタ。例:

```
    color (1, 0.75, 0.5)
    point ("object", 1, 2, 3)

```

コンストラクタに渡す引数すべてが定数であれば、そこから構築されるポイントは、定数と同様に扱われるので、実行時の負荷がありません。
つまり、**color(1,2,3)**は単一の定数エンティティとして扱われるので、実行時にビット単位でのアセンブル化が行なわれません。

* 変数またはパラメータの参照
* (**[ ]**を用いた)配列の個々の要素
* (**[ ]**を用いた)**color**,**point**,**vector**,**normal**または(**[ ][ ]**を用いた)matrixの個々のコンポーネント
* 前置/後置形式のインクリメント/デクリメント演算子:

 **-- varref** | (前置形式のデクリメント)

後置形式のインクリメントやデクリメント(例えば、**a++**)は、古い値を返してから、その変数をインクリメントまたはデクリメントします。
前置形式のインクリメントやデクリメント(**++a**)は、先に変数をインクリメントまたはデクリメントしてから、その新しい値を返します。

* 他のエクスプレッションにおける単項と二項の算術演算子:

演算子の**+**,**-**,**\***,**/**,**-**(否定)はほとんどの数値型で使用することができます。
複数コンポーネント(**color**,**point**,**vector**,**normal**,**matrix**)に関しては、これらの演算子はコンポーネント単位でそれらの引数を組み合わせます。
**matrix**に適用できる演算子は**\***と**/**のみで、それぞれ**matrix**間の乗算と他の**matrix**の逆行列による乗算を示します。
整数とビット演算子の**%**,**<<**,**>>**,**&**,**|**,**^**,**~**は整数タイプのエクスプレッションのみに使用することができます。
どの演算子が許可されているかについての詳細は、第5章の各種のオペレータテーブルを参照して下さい。

* 比較演算子(算術演算子よりも完全に優先度が低いです):

 **expr >= expr** | (以上)

**==**と**!**の演算子は、同じタイプの2つの値に対して実行したり、複数コンポーネントタイプに関してはコンポーネント毎に実行することができます。
**<**, **<=**, **>**, **>=**は、複数コンポーネントタイプの比較に使用することはできません。

**int**エクスプレッションは**float**と比較することができます(この場合は、どちらも**float**として扱われます)。
**float**エクスプレッションは複数コンポーネントタイプと比較することができます(この場合は、単一**float**から複数コンポーネントタイプが構築されて比較されます)。

比較演算子はブール値(true/false)を返します。これは**int**値として実装されており、falseが0、trueが1です。

* 論理単項/二項演算子:

注:**not**、**and**、**or**のキーワードはそれぞれ**!**、**&&**、**||**と同義です。

論理演算子において、数値表現(**int**または**float**)はゼロでないならば**true**、ゼロならば**false**と考えられます。
複数コンポーネントタイプ(**color**など)は、どれかのコンポーネントがゼロでなければ**true**、すべてのコンポーネントがゼロならば**false**と見なされます。
文字列は記述があるならば**true**、文字列の記述がない("")ならば**false**と見なされます。

* 括弧**( )**で閉じた他の表現。括弧を使用することで、演算の関連性を明確にすることができます。
* 値の頭に括弧でタイプ名を付ける方法による型変換(C言語スタイルの型変換)、コンストラクタの形式による型変換(C++スタイルの型変換):

```
(vector) P    /*vectorへpointを加える*/
(point) f     /*pointへfloatを加える*/
(color) P     /*colorへpointを加える*/

vector (P)    /*vectorへpointを加える*/
point (f)     /*pointへfloatを加える*/
color (P)     /*colorへpointを加える*/

```

3コンポーネントタイプ(**color**,**point**,**vector**,**normal**)は、他の3コンポーネントタイプに変換することができます。
**float**は3コンポーネントタイプ(3つのコンポーネントすべてにその**float**を格納)または**matrix**(対角線上のコンポーネントがその**float**のmatrixを作成)に変換することができます。**point**を**float**へ、**string**を数値タイプに変換するようなことは意味をなさないので、それらの型変換は明白に許可されていません。

* 関数コール
* 割り当てエクスプレッション:**var = var OP expr**と同じ事です:

 **int-var >>= int-expr** | (整数右シフト)

整数と論理演算子は、'*int**変数と**int*エクスプレッションにのみ許可されています。一般的に、**var OP = expr**は**var = var OP expr**が許可されている時のみ許可され、まったく同じことを意味します。第5章の各種のオペレータテーブルを参照して下さい。
* C言語とまったく同じ三項演算子:

```
    condition ? expr1 : expr2

```

このエクスプレッションは、**condition**が**true**(ゼロでない)ならばexpr1、**false**(ゼロ)ならばepxr2の値を取得します。
各データタイプで使用可能なタイプに関する完全な補足は、第5章を参照してください。Open Shading Languageでの演算子の優先順位はC言語の演算子の優先順位と同じです。
### 6.3 コントロールフロー:if, while, do, for

Open Shading Languageにおける条件はまさにC言語やC++と同じです:

```
    if ( condition )
        truestatement

```

と

```
    if (condition )
        truestatement
    else
        falsement

```

ステートメントは、ブロック全体を中括弧で閉じることもできます。例えば、

```
    if (s > 0.5) {
        x = s;
        y = 1;
    } else {
        x = s+t;
    }

```

**condition**には、以下のような有効なエクスプレッションを指定することができます:

* 比較演算子(例えば、**<**、**==**)の結果。
* ゼロでない場合は**true**、ゼロである場合は**false**と見なす数値エクスプレッション(**int**、**color**、**point**、**vector**、**normal**、**matrix**)。
* 記述がある文字列ならば**true**、記述のない文字列("")ならば**false**と見なす文字列エクスプレッション。
* 空っぽ(割り当てられていないか**=0**で初期化された)ならば**true**、他の何かがクロージャへ割り当てられたならば**false**と見なす**closure**。

**condition**がtrueである限り、**while**ステートメントによってステートメントを繰り返して実行することが可能です:

```
    while ( condition )
        statement

```

または、**do/while**ループによって、ボディ部分を一度ループさせた後でテストを実行することができます:

```
    do
        statement
    while ( condition );

```

さらに、**for**ループも使用することができます:

```
    for ( initialization-statement ; condition ; iteration-statement )
        body

```

C++と同様に、**for**ループ自体でローカルスコープでの変数宣言と変数の初期化をすることができます:

```
    for (int i = 0; i < 3; ++i) {
        ...
    }

```

**if**ステートメントと同様に、ループ条件には、関係や数量(ゼロでないならば**true**、ゼロならば**false**と見なされます)または文字列(空っぽでない場合は**true**、空っぽの文字列""の場合は**false**と見なされます)を使用することができます。

ループのボディ内では、**break**ステートメントはループを終了し、**continue**ステートメントはボディの最後へスキップして、次のループに進みます。

### 6.4 関数

関数コールはC言語系のプログラミング言語と非常に似ています:

```
    functionname ( arg1, ..., argn )

```

関数が('*void*でない)値を返す場合、その値をエクスプレッションとして使用することができます。**void**でない関数であっても、その値を完全に無視することができます。

Open Shading Languageでは、すべての引数が**参照**で渡されます。
これは、一般的にC言語スタイルの"値渡し"の意味合いと大きく違いませんが、同じ変数を別々の関数の引数に渡すと、その変数の値が変更されます。

セクション4.4にて詳細に関数定義について述べられています。

### 6.5 グローバル変数

**グローバル変数**(**グラフィックステート変数**とも呼びます)には、シェーディングされたポイントに関してレンダラーが知っている基本的な情報(例えば、ポジション、サーフェスの向き、デフォルトのサーフェスカラーなど)が含まれています。グローバル変数は、宣言する必要がありません。つまり、シェーダ内でデフォルトでそのまま利用することができます。