Chapter05

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

## 5. データ型

Open Shading Languageには、シェーダ内で計算を実行するための組み込みの単純なデータ型がいくつか備わっています：

 float
 pointvectornormal
 color
 matrix
 string
 void

さらに、(C言語同様に)配列と構造体を作成することができ、Open Shading Languageには**クロージャ**と呼ばれる新しい型のデータ構造体があります。

この章の残りの部分では、Open Shading Languageで利用可能な単純なデータ型と集合体データ型について説明します。

### 5.1 int

離散数値の基本の型は**int**です。**int**型のサイズはレンダラー依存ですが、最低でも32ビットが保証されています。

整数定数はC言語と同じ方法で構築します。次の値は**int**定数の例です： **1**, **-32**, など。
整数定数には、**0x01cf**といった16進数を指定することができます。

C言語とは違い、unsigned、bool、char、short、longの型がありません。これは、シェーダを書く過程(とシェーディングシステムの実装)を単純化するためです。

以下の演算子を**int**値と一緒に使用することができます(優先度の高い順で表示しており、同じ優先度の演算子はボックス内に収めています)：

**not**、**and**、**or**キーワードは、それぞれ**!**、**&&**、**||**と同じ意味です。

### 5.2 float

スカラー浮動小数点値の基本の型は**float**です。**float**型のサイズはレンダラー依存ですが、最低でもIEEE 32ビットfloat(標準のC **float**データ型)が保証されています。
レンダラー側の実装によっては、より精度の高い**float**(例えば、C **double**を基本表現として使用)を実行できるように選択することができます。

浮動小数点定数はC言語と同じ方法で構築します。次の値は**float**定数の例です： **1.0, 2.48**, **-4.3e2**。

有効な**float**演算子と一緒に使用する時は**float**の代わりに**int**を使用することができます。そうした場合、その**int**は**float**に昇格されて、その結果の式が**float**になります。
また、**float**パラメータを必要とする関数に**int**を渡すこともでき、**int**は自動的に**float**に昇格されます。

以下の演算子を**float**値と一緒に使用することができます(優先度の高い順で表示しており、同じ優先度の演算子はボックス内に収めています)：

 **++ float****-- float****- float** | floatfloatfloat
 **float \* float****float / float** | floatfloat
 **float + float****float - float** | floatfloat
 **float < float****float <= float****float > float****float >= float** | floatfloatfloatfloat
 **float == float****float != float** | floatfloat

### 5.3 color

**color**型は、3成分(RGB)のスペクトル反射率や光エネルギーの表現に使用します。
3つのfloatを用いてRGBの三つ組あるいはレンダラーが認識できる他の色空間を表すことでcolorを構築することができ、さらに単一floatからも構築することができます(3つのチャンネルすべてに複製)。
以下にその例をいくつか載せています：

```
color (0, 0, 0)            // ブラック
color ("rgb", .75, .5, .5) // ピンク系
color ("hsv", .2, .5, .63) // "hsv"空間で指定
color (0.5)                // color (0.5, 0.5, 0.5)と同じ

```

これらの式すべてが**rgb**空間のcolorを返します。
3つ目の例でも**rgb**空間のcolorを返します。具体的には、色相0.2、彩度0.5、明度0.63に相当する色のRGB値です。
つまり、この方法で指定した色空間を基準に与えた成分からcolorを構築すると、暗黙的に**rgb**空間に変換されます。
テーブル5.1では、組み込みの色空間のリストを載せています。

テーブル5.1： 色空間の名前
 **xyY** | CIE **xyY**座標

**color**には他の**color**や**float**の値を代入することができます(**float**を代入すると、その値が3つの成分すべてに設定されます)。例：

```
color C;
C = color (0, 0.3, 0.3);
C = 0.5;                // C = color (0.5, 0.5, 0.5)と同じ

```

colorは、**[ ]**(配列アクセス記法)を使用することで、個々の成分を調べて設定することができます。例：

```
color C;
float g = C[1]; // 緑成分を取得
C[0] = 0.5;     // 赤成分を設定

```

成分0、1、2はそれぞれ赤、緑、青です。
[0...2]範囲外のインデックスで色成分にアクセスするとエラーになります。

以下の演算子を**color**値と一緒に使用することができます(優先度の高い順で表示しており、同じ優先度の演算子はボックス内に収めています)：

 **- color** | color
 **color \* color****color \* float****float \* color****color / color****color / float****float / color** | colorcolorcolorcolorcolorcolor
 **color + color****color - color** | colorcolor
 **color == color****color != color** | intint

すべての二項演算子は、スカラー値(**float**または**int**)と**color**を組み合わせることができ、そのスカラー値は3つ同じ成分の**color**と見なされます。

### 5.4 Point系型： point, vector, normal

points, vectors, normalsは、同一の構造体の類似したデータ型ですが、意味合いが少し異なります。
私達は、これら3つの型を適用した文を作成する時には、それらの型をまとめて**point系**データ型と呼ぶことが多いです。

**point**は3D空間の位置です。**vector**は長さと方向を持っていますが特定の位置に存在しません。
**normal**は、サーフェスに**垂直**な特別な型のベクトルなので、サーフェスの向きを表現します。
そのような垂直なベクトルは、以下で説明するように、通常のベクトルとして使用するというよりも色々なトランスフォームのルールに使用します。

これらのpoint系型すべてが内部的には3つの浮動小数点で表現されていて、何かしらの座標系を基準に固有な位置や方向を定義します。

どの**point**、**vector**、**normal**も何かしらの座標系を基準に定義します。
シェーダに指定するすべてのデータ(サーフェス情報、グラフィックスステート、パラメータ、頂点データ)は、**common(共通)**座標系と呼ばれる特定の座標系が基準になっています。
**common(共通)**座標系は、レンダラーのシェーディング計算にとって都合の良い座標系です。

コンストラクタを使用することで、3つのfloatからpoint系型を**構築**することができます：

```
point (0, 2.3, 1)
vector (a, b, c)
normal (0, 0, 1)

```

これらの式は、3つの成分が**common**空間を基準としたfloatとして与えられたpoint、vector、normalとして解釈されます。

colorと同様に、他の座標系を基準に座標を指定することもできます：

```
Q = point ("object", 0, 0, 0);

```

この例では、**object**空間の原点におけるpointをQに代入しています。
とはいえ、この文はQのコンポーネントを(0,0,0)に設定**しません**！
むしろ、Qには**object**空間の原点と同じ位置のpointの**common**空間座標が含まれます。
つまり、暗黙的に空間名を指定したpointコンストラクタでは、**common**空間でのトランスフォームが指定されます。この型のコンストラクタは、vectorやnormalにも使用することができます。

**common**空間の選択はレンダラー依存ですが、通常では、**camera**空間または**world**空間のどれかに相当します。

一部の計算では、**common**空間以外の座標系の方が簡単なことがあります。
例えば、**ソリッドテクスチャ(3Dテクスチャ)**を移動オブジェクトに適用する時は**common**空間よりも**object**空間の方が非常に都合が良いです。
そういった理由で、OSLには異なる座標系間でpoint、vector、normalを変換することができる組み込みのトランスフォーム関数が備わっています(セクション7.2を参照)。
しなしながら、Open Shading Languageは、どのpoint変数がどの座標系なのかを把握しません。
これを把握するのはシェーダプログラマーの役割であり、例えば、ライティング計算は必ず**common**空間での量を使って実行しなければなりません。

いくつかの座標系は、テーブル5.2のリストに挙げている名前によって事前に定義されています。
さらに、レンダラーによっては、シーン記述において名前の付いた座標系を追加することができ、それらの名前をシェーダ内で参照してトランスフォームを指定することもできます。

テーブル5.2： 事前に宣言されているジオメトリ空間の名前
 **NDC** | 2D Normalized Device Coordinates(2D正規化デバイス座標)。raster空間と同様ですが、画像全体のxとyが0と1に正規化されていて、(0,0)が画像の左上コーナー、(1,1)が右下コーナーです。

point型は、**[ ]**(配列アクセス記法)を使用することで、個々の成分を調べて設定することができます。例：

```
point P;
float y = P[1]; // y成分を取得
P[0] = 0.5;     // x成分を設定

```

成分0、1、2はそれぞれx、y、zです。
[0...2]範囲外のインデックスでポイント成分にアクセスするとエラーになります。

以下の演算子をpoint系の変数と一緒に使用することができます(優先度の高い順で表示しており、同じ優先度の演算子はボックス内に収めています)：

 **- ptype** | vector
 **ptype \* ptype****float \* ptype****ptype \* float****ptype / ptype****ptype / float****float / ptype** | ptypeptypeptypeptypeptypeptype
 **ptype + ptype****ptype - ptype** | ptypevector
 **ptype == ptype****ptype != ptype** | intint

汎用**ptype**は、**point**、**vector**、**normal**が使用可能であることを意味しています。

すべての二項演算子は、スカラー値(**float**または**int**)とpoint系型を組み合わせることができ、そのスカラー値は3つ同じ成分のpoint系型と見なされます。

### 5.5 matrix

Open Shading Languageには、ポイントやベクトルを座標系間で変換するのに必要となる変換行列を表す**matrix**型があります。
行列は内部的に16個のfloatで表現されています(4x4の同次変換マトリックス)。

**matrix**は、1個のfloatまたは16個のfloatから構築することができます。例：

```
matrix zero = 0;  // すべて0のmatrixを作成
matrix ident = 1; // 単位行列を作成

// 16個のfloatからmatrixを構築
matrix m = matrix (m00, m01, m02, m03, m10, m11, m12, m13,
                   m20, m21, m22, m23, m30, m31, m32, m33);

```

1個の浮動小数点値**x**をmatrixに代入すると、対角線上の成分がすべて**x**で、それ以外が0のmatrix(つまり**x**倍した単位行列)になります。
16個のfloatでmatrixを構築すると、行優先順でそれらのfloatで構成されたmatrixが作成されます。

point系型と同様に、名前の付いた空間を参照して**matrix**を構築することができます：

```
// "common"以外のいずれかの空間を基準にmatrixを構築
matrix q = matrix ("shader", 1);
matrix m = matrix ("world", m00, m01, m02, m03, m10, m11, m12, m13,
                            m20, m21, m22, m23, m30, m31, m32, m33);

```

1番目の形式は、ポイントを**shader**空間から**common**空間に変換するmatrixを作成しています。
このmatrixによるポイント変換は、transform(**shader**, **common**, ...)を呼び出すことと同じです。
2番目の形式は、成分

m

0
,
0

.
.
.

m

3
,
3

{\displaystyle m\_{0,0} ... m\_{3,3}}

からなる4 x 4 matrixの上に現行空間からworld空間への変換行列を前置します。
この例では**shader**と**world**の空間を使用していますが、どの名前の空間でも対応可能です。

matrixは、2つの座標系の名前から構築することもでき、1番目の名前の空間から2番目の名前の空間に座標を変換するmatrixを生成することもできます：

```
matrix m = matrix ("object", "world");

```

この例では、*objectからworldへの*変換行列を返します。

matrix変数は、**==**や**!=**のブール演算子を使って等価、不等価をテストすることができます。
また、matrix間に**\***演算子を使用することでmatrixの乗算を意味し、**m1 / m2**は**matrix m1**を**matrix m2**の逆行列で乗算することを意味します。
そのため、**1/m**と記述することで**matrix**の逆行列を表現することができます。さらに、セクション7で説明しているように、一部の関数ではmatrix変数を引数として受け取ります。

matrix変数の各成分は、配列記法で設定またはアクセスすることができます。例：

```
matrix M;
float x = M[row][col];
M[row][col] = 1;

```

有効なインデックスは、[0...3]までの整数です。この範囲外の行または列でmatrix成分にアクセスするとエラーになります。

以下の演算子をmatrixと一緒に使用することができます(優先度の高い順で表示しており、同じ優先度の演算子はボックス内に収めています)：

 **- matrix** | matrix
 **matrix \* matrix****matrix \* float****float \* matrix****matrix / matrix****matrix / float****float / matrix** | matrixmatrixmatrixmatrixmatrixmatrix
 **matrix == matrix****matrix != matrix** | intint

### 5.6 string

**string**型は文字列を保持することができます。この文字列の主な用途は、テクスチャが置かれている場所のファイルの名前を指定することです。
文字列は、**==**や**!=**を使って比較することができます。

文字列定数は、"I am a string literal"のように文字列をダブルクォーテーションで囲んで表現します。
C言語と同様に、文字列リテラルには、**\n**(改行)、**\r**(キャリッジリターン)、**\t**(タブ)、**\"**(ダブルクォーテーション)、**\\**(バックスラッシュ)などのエスケープシーケンスを含めることができます。

ホワイトスペース(スペース、タブ、改行)だけで区切られた引用符で閉じられた2つの文字列リテラルは、自動的に1つの文字列リテラルに連結されます。つまり、

```
"foo" "bar"

```

は、"foobar"とまったく同じです。

### 5.7 void

**void**型は、値を返さない関数を指定するために使用します。型が**void**の変数がありません。

### 5.8 配列

基本的な型の配列は、1次元で静的なサイズである限り、C系言語の通常の構文を使用することができます：

```
float d[10];                     // 初期化されていない配列を宣言
float c[3] = { 0.1, 0.2, 3.14 }; // 配列を初期化

float f = c[1];                  // 1つの要素にアクセス

```

組み込み関数の**arraylength()**は、配列内の要素の数を返します。例：

```
    float c[3];

    int clen = arraylength(c);   // 3を返す

```

配列に対して長さを宣言する必要がない状況が2通りあります。それは、関数に渡す配列パラメータと配列のシェーダパラメータがそれです。
これは、以下のように空の配列の括弧で指定します：

```
float sum (float x[])
{
    float s = 0;
    for (int i = 0; i < arraylength(x); ++i)
        s += x[i];
    return s;
}

```

OSLでは**=**演算子を使って配列全体を一度にコピーすることが許容されており、配列が同じ型の要素を含み、コピー先の配列長が最低でもコピー元の配列長以上であれば可能です。例：

```
float array[4], anotherarray[4];
...
anotherarray = array;

```

### 5.9 構造体

構造体は、異なる型の可能性がある複数のフィールドを、名前で参照できる1つのオ ブジェクトにグループ化するために使用されます。
組み込み型の時と同様に、その構造体型の名前を使用することで構造体変数を宣言することができます。
構造体の要素にアクセスするには、**ドット**演算子を使用します。構造体の宣言と使い方の構文は、CまたはC++と同様です：

```
struct RGBA {                       // 構造体型を定義
    color rgb;
    float alpha;
};

RGBA a;                             // 構造体を宣言
a.rgb = color(1, 0, 0);             // 1つのフィールドに代入
color c = a.rgb;                    // 構造体フィールドから読み込み

RGBA b = { color(.1, .2, .3), 1 };  // メンバーごとの初期化

```

colorやpointのような組み込み型を構築するのと同じように、構造体型に「コンストラクタ式」を使用することができます：

```
struct_name ( first_member_value, ... )

```

例：
```
RGBA c = RGBA(col, alpha);           // コンストラクタ構文

RGBA add(RGBA a, RGBA b)
{
    return RGBA(a.rgb+b.rgb, a.a+b.a); // リターン式
}

// コンストラクタ式を引数として渡す:
RGBA d = add(c, RGBA(color(.3, .4, .5), 0));

```
どの複合型が必要かが文脈から推定できる場合、**複合初期化子リスト**構文を使って型を構築することもできます。例えば、これは先の例と同じです：
```
RGBA c = {col, alpha}; // 何に割り当てられているかで推定

RGBA add(RGBA a, RGBA b)
{

```
   return {a.rgb+b.rgb, a.a+b.a};   // 関数の戻り値の型で推定

```

}

RGBA d = add(c, {{.3, .4, .5}, 0}); // 期待される引数の型から推定

```
構造体フィールドには配列を持たせることができ、さらに構造体を配列にすることもできます。しかし、現在のところ、配列を「ネスト」すること（つまり、配列であるメンバを含む構造体の配列を持つこと）は許可されていません：

```
struct A {
    color a;
    float b[4];  // OK: 構造体が配列を含む
};

RGBA vals[4];    // OK: 構造体の配列を作る
vals[0].a = 0;

A d[5];          // NO: 配列を含む構造体で配列を作る

```

### 5.10 クロージャ

**closure**とは、後に評価されるのに必要なコンテキスト情報とともに保持される式または関数呼び出しのことです。

一般的には、**closure gentype**は、通常の**gentype**とまったく同じように振る舞いますが、シェーダの実行中はその数値を調べたり使用することができません。
例えば、**closure color**はほとんど**color**のように振る舞います。つまり、スカラーで乗算したり、**closure color**変数に代入することができます。
ただし、**closure color**を通常の**color**に代入することも、各成分の数値を調べることもできません。

クロージャに0を代入することは正当で、これはクロージャを**null closure**に設定するという意味に解釈されます(他のどの状況においても、floatをクロージャに代入することは許可されていません)。
現在のところ、Open Shading Languageでサポートされている唯一のクロージャの型は**closure color**であり、許可されている演算は**closure color**との線形結合のみです。
さらなるクロージャ型と演算は将来的な使用のために予約されています。

**closure color**との可能な演算は以下のとおりです：

 **color \* closure color****closure color \* color****float \* closure color****closure color \* float** | closure colorclosure colorclosure colorclosure color
 **closure color + closure color** | closure color