はじめに
最初から読む: 【OSL入門】MayaでArnoldのシェーダーを書く①
前回の記事: 【OSL入門】MayaでArnoldのシェーダーを書く③~テクスチャ~
前回に引き続き、Maya の aiOslShader による OSL の使い方を解説していきます。
今回は、光の反射や拡散の仕方を表す closure についてです。
これまでの記事では、計算結果を主に color 型で出力してきました。
closure を使用すると、単なる色ではなく、”ライトを受けたときに表面がどのように見えるか”を OSL から Arnold へ渡すことができます。
closureとは
OSL における closure は、単なる色ではなく、光がサーフェスでどのように散乱するかを表すデータです。
例えば、光をさまざまな方向へ拡散する、鏡のように反射する、表面を通過するといった性質を closure で表すことができます。
まずは closure を使用したコンパイル可能なシンプルな例を見てみましょう。
shader sample_shader(
output closure color outClosure = 0
){
outClosure = diffuse(N);
}
出力アトリビュートの outClosure をオブジェクトに割り当て済みのShadingGroupノードの surfaceShaderにつなぎます。

これをレンダリングすると、シンプルなグレーの陰影がついた見た目になります。

- closure を出力する場合、aiFlat のcolor等、ほかのマテリアルの入力カラーではなく Shading Group の Surface Shader へ接続する必要があります。
- closure はライト計算を行うため、結果を確認するときはシーンにライトを用意してください。
closure 自体はレンダリング後の RGB 値ではありません。
今までは出力する色を OSL で完全に決めていましたが、closure を出力する場合、OSL シェーダーは、シェーディングポイントにおける光の扱い方の情報を作成し、実際のライト計算やレイのサンプリングは Arnold が行います。
OSL では、サーフェス用の closure を closure color 型として扱います。
名前に color と入っていますが、通常の color 型とは別の型です。
| 型 | 表すもの | 主な接続先 |
|---|---|---|
| color | RGBなどの数値 | マテリアルの色入力、aiFlat、Shading Group の Surface Shader 等 |
| closure color | 光の散乱・反射モデル | Shading Group の Surface Shader |
color 型の出力は、ライトが当たったときの見え方をそれだけで決めるものではありません。
一方、closure color 型の出力は、拡散反射や鏡面反射を含むサーフェスシェーダーとして使用できます。
color と closure color は、作りたいノードの役割によって使い分けます。
色補正、マスク、ノイズ、テクスチャなど、別のマテリアルへ渡す値を作る場合は color 出力を、拡散反射、鏡面反射、透過など、サーフェスの最終的な見え方を作る場合は closure color 出力を使用します。
closure はシェーダーの実行中にはまだ値が確定していないため、具体的な数値を確認することができません。
そのため、closure の計算結果を clamp() や step() 等の関数に渡して計算に使用するといった処理は書けません。
代表的なclosure
OSL には、closure を作成するための関数が用意されています。
代表的なものをいくつか示します。
| closure | 用途 |
|---|---|
| diffuse() | 均一に近い拡散反射 |
| oren_nayar() | 粗い表面を考慮した拡散反射 |
| reflection() | 鏡面反射 |
| refraction() | 屈折 |
| transparent() | 光をそのまま通過させる |
| microfacet() | 表面の細かな凹凸をモデル化した鏡面反射・屈折 |
最もシンプルなものの一つが先ほどの例でも使用した diffuse() です。
法線を渡すことで、拡散反射の closure を作成できます。
closure color diffuseClosure = diffuse(N);
microfacet() は、表面にある非常に細かな凹凸を仮定し、その向きの分布から反射を求めるモデルです。
金属やプラスチックなどのハイライトを表現したいときに使用されます。
shader sample_shader(
float roughnessX = 0.2,
float roughnessY = 0.2,
float ior = 1.5,
output closure color outClosure = 0
){
outClosure = microfacet("ggx", N, normalize(dPdu),
roughnessX, roughnessY, ior, 0
);
}

closureの演算
closureは組み合わせることができます。
shader sample_shader(
output closure color outClosure = 0
){
outClosure = color(1.0, 0.0, 0.0) * diffuse(N);
}

closure color に color を掛けるとその結果も closure になります。
この例では拡散反射に赤色を掛け合わせることで、新たなclosureを作成しています。
通常の色同士の乗算とは異なり、baseColor が closure の重みとして使用されます。
colorの代わりにfloatを重みとして使用することもできます。
shader sample_shader(
output closure color outClosure = 0
){
outClosure = 0.5 * diffuse(N);
}

また、複数の closure を加算して、複数の性質を組み合わせることも可能です。
例えば、拡散反射と microfacet による鏡面反射を組み合わせる場合は以下のように書けます。
shader sample_shader(
color baseColor = color(1.0, 0.0, 0.0);
output closure color outClosure = 0
){
closure color diff = baseColor * diffuse(n);
closure color spec = microfacet("ggx", N, normalize(dPdu), 0.2, 0.2, 1.5, 0);
outClosure = diff + spec;
}
これで、1つの出力に拡散反射と鏡面反射の両方が含まれます。

まとめ
今回は、OSL の closure と closure color 型について解説しました。
- color はRGBなどの値、closure color は光の散乱や反射の性質を表す
- diffuse() や microfacet() といった関数で closure を作成する
- closure は加算でき、float や color を掛けて重みを調整できる
- closure color の出力は、ほかのマテリアルに色として渡せないため、Shading Group の Surface Shader アトリビュートへ接続する
これまで color として計算していた値を closure の重みとして使用することで、テクスチャやマスクを実際の反射へつなげられるようになります。
次回に続きます。
次回の記事: 未公開


コメント