【OSL入門】MayaでArnoldのシェーダーを書く⑤~ディスプレイスメント~

OSLコードとシェーダーノード、グレースケールの3D球体を並べた「OSL入門⑤」のアイキャッチ Tech

はじめに

最初から読む: 【OSL入門】MayaでArnoldのシェーダーを書く①

前回の記事: 【OSL入門】MayaでArnoldのシェーダーを書く④~closure~

前回の記事まではOSL を、色や closure を出力するのに使用していました。

この記事では、Maya の aiOslShader から float 値を出力し、Arnoldでディスプレイスメントとして使用し、レンダリング時にメッシュを変形させる手順を解説します。

UV に沿った波形と画像テクスチャの2例を作成し、形状ががたついたり欠けてしまう場合に必要な Subdivision と Bounds Padding の設定まで確認します。

OSL のコンパイルと aiOslShader への読み込み方法は第1回の記事を、テクスチャを使用する方法については第3回の記事を参照してください。

displacement とは

displacement は、シェーディングポイントを法線方向へ移動して、メッシュの表面に凹凸を作る仕組みです。

バンプやノーマルマップでも凹凸を表現できますが、こちらは基本的に法線を変えて陰影を作る方法なので、オブジェクトの輪郭は変わりません。

Maya Arnoldでバンプを適用した球体。陰影は変わるが輪郭は円形のまま
バンプを使用した場合は輪郭が変わらない

一方、displacement はレンダリング時にサーフェスの位置を移動するため、オブジェクトの輪郭や影にも凹凸が反映されます。

Maya Arnoldでディスプレイスメントを適用し、表面と輪郭がノイズにより凹凸がついた球体
displacement を使用すると、実際に形状が変わる

OSL で displacement を適用する手順

Maya Arnoldでディスプレイスメントを適用し、表面と輪郭が波打った球体

ディスプレイスメント値の出力

displacement に渡す値は、シンプルな float 型で作成できます。

まずは、UV の U 方向に波模様を作る以下のコードをコンパイルすると、aiOslShader に outDisplacement という出力アトリビュートが作成されます。

shader displacement_shader(
    float frequency = 8.0,
    float amplitude = 0.1,
    output float outDisplacement = 0.0
){
    float wave = sin(u * frequency * 6.28318530718);
    outDisplacement = wave * amplitude;
}

接続

プリミティブの Sphere を作成し、 aiStandardSurface を割り当てます。
その aiStandardSurface の Shading Group の Displacement Shader に outDisplacement をつなぎます。

aiOslShaderのoutDisplacementをShading GroupのDisplacement Shaderへ接続したノード構成

displacement の強さなどを調整できて便利なので、間に displacementShader を作成して挟むつなぎ方を推奨します。

aiOslShaderとShading Groupの間にaiDisplacementを挟んだノード構成

レンダリングすると、単純な球体が displacement によって、波打ちます。

Subdivision設定前のディスプレイスメント結果。球体表面が角ばっている

Subdivision の設定

ただし、このままだと、ポリゴンの細かさが足りず、角ばって見えたり表面が汚く見えます。

オブジェクトを選択し、Attribute Editor でその shape の Arnold タブの Subdivision タブの Type を catclark に変更します。

iterations を大きくするほど滑らかになりますが、レンダリング時に使用するメモリや計算時間が急激に増えるので、値を大きくしすぎないように注意してください。

輪郭の角張りが目立たなくなるまで、1ずつ値を大きくしてください。

Maya Attribute EditorのArnold Subdivision設定でTypeをCatclarkへ変更する画面
Subdivision Iterationsを増やし、ディスプレイスメント表面を滑らかにした球体

frequency は波の繰り返し数、amplitude は凹凸の大きさです。

sin() の結果は-1.0から1.0の範囲で変化します。
そこへ amplitude を掛けることで、出力は -amplitude から amplitude の範囲になります。

6.28318530718 は円周率の2倍です。U 座標の0~1を sin() の1周期へ変換し、frequency の回数だけ繰り返しています。

Bounds Paddingの設定

Arnold は、レンダリングを効率化するためにオブジェクトが存在する範囲をあらかじめ見積もっています。

displacement によって、その範囲より外側までメッシュが移動すると、バウンディングボックスの形に、形状の一部が欠けてレンダリングされる場合があります。

Bounds Padding不足によりバウンディングボックスの境界で形状が欠けた例

その場合は Shape ノードの Arnold にある Bounds Padding を、想定する変位量に合わせて大きくします。

今回のコードでは outDisplacement が-amplitudeからamplitudeまで変化します。amplitude を1.0としている場合は、まず Bounds Padding も1.0以上を目安に設定します。

Maya ShapeノードのArnold設定にあるBounds Padding入力欄

値を必要以上に大きくするとレンダリング効率が落ちるので注意してください。

欠けるはずなのに欠けてなかったり、正しく設定したのに形状の一部が削れたままの場合は、Arnold RenderView メニュー > Render > Update Full Scene (ctrl+U) で更新してください。

テクスチャをdisplacementに使用する

【OSL入門】MayaでArnoldのシェーダーを書く③~テクスチャ~で解説した関数 texture() と組み合わせることで、画像ファイルの明るさを displacement に使用することもできます。

shader texture_displacement_shader(
    string fileName = "",
    float amplitude = 0.1,
    output float outDisplacement = 0.0
){
    color texColor = texture(fileName, u, 1.0-v);
    float height = luminance(texColor);
    outDisplacement = (height - 0.5) * amplitude;
}

このコードはmeshのUV座標を使用しているため、UVが0~1の範囲に展開されていることを確認してください。

画像テクスチャの明るさを使ってディスプレイスメントしたレンダリング結果

luminance() でテクスチャを1つの float 値へ変換しています。

テクスチャの値が0.5の場所を移動しない基準とし、暗い場所は内側、明るい場所は外側へ移動します。

このコードでは、テクスチャが0.0から1.0の範囲であれば、出力は-amplitudeの半分からamplitudeの半分までです。

まとめ

今回は、OSL で displacement を作成し、メッシュの表面に凹凸を作成しました。

  • aiOslShader の float 出力を Shading Group の Displacement Shader または displacementShader の Displacement へ接続する。
  • 細かな凹凸には Arnold の subdivision を使用する。
  • 形状が欠ける場合は Bounds Padding を確認する。
  • 画像やノイズを高さ情報として扱うこともできる。

次回に続きます。

次回の記事: 未公開

コメント

タイトルとURLをコピーしました