[Omniverse] MaterialXを使う – その4 : Noise

[Omniverse] MaterialXを使う – その3」の続きです。
以下についてメモ書きです。

  • Noiseテクスチャを使用

Omniverse Create 2022.3.1を使用しました。

fractal3d

ノイズは"fractal3d"のNodeGraphが使用できそうです。
"standard_surface_marble_solid.mtlx"が参考になりそうでした。
https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/resources/Materials/Examples/StandardSurface/standard_surface_marble_solid.mtlx

以下は、Omniverse Createで配置した球(半径 50cm)で見栄えが良くなるように調整したmtlxファイルです。
standard_surface_marble_solid.zip
zipを解凍すると、mtlxファイルに展開されます。
Omniverse Create(RTX-Real-Time)では以下のように表示されました。

シンプルな例

"standard_surface_marble_solid.mtlx"はいくつかの要素が組み合わさっているため、もっとシンプルな実装から見ていきます。

"UseNoise.mtlx"というファイル名にしました。

<?xml version="1.0"?>
<materialx version="1.38" colorspace="lin_rec709">
  <nodegraph name="NG_noise">
    <input name="noise_scale" type="float" value="0.1" />
    <position name="obj_pos" type="vector3" space="object" />

    <multiply name="scale_pos" type="vector3">
      <input name="in1" type="vector3" nodename="obj_pos" />
      <input name="in2" type="float" interfacename="noise_scale" />
    </multiply>
    <fractal3d name="noise" type="float">
      <input name="octaves" type="integer" value="3" />
      <input name="lacunarity" type="float" value="0.5"  />
      <input name="position" type="vector3" nodename="scale_pos" />
    </fractal3d>
    <combine3 name="combine_color" type="color3">
      <input name="in1" type="float" nodename="noise" />
      <input name="in2" type="float" nodename="noise" />
      <input name="in3" type="float" nodename="noise" />
    </combine3>
    <output name="out_color" type="color3" nodename="combine_color" />
  </nodegraph>

  <standard_surface name="SR_NoiseTest" type="surfaceshader">
    <input name="base" type="float" value="1" />
    <input name="base_color" type="color3" nodegraph="NG_noise" output="out_color" />
    <input name="specular_roughness" type="float" value="0.5" />
  </standard_surface>

  <surfacematerial name="NoiseTest" type="material">
    <input name="surfaceshader" type="surfaceshader" nodename="SR_NoiseTest" />
  </surfacematerial>
</materialx>

NodeGraphの"NG_noise"はノイズを使ったcolor3を作成します。
図で表すと以下のような感じになるでしょうか。

Omniverse Create 2022.3.1に"UseNoise.mtlx"を読み込みました。

これは単純な黒と白のみのノイズを描画しています。

nodegraphのinput

nodegraphでinputを使用します。

<nodegraph name="NG_noise">
  <input name="noise_scale" type="float" value="0.1" />
</nodegraph>

ここでは"noise_scale"というfloat値を与えました。
これを使用する場合、以下の"in2"の指定のように"interfacename"で参照する必要がありました(この場合は"nodename"ではありません)。

<multiply name="scale_pos" type="vector3">
  <input name="in1" type="vector3" nodename="obj_pos" />
  <input name="in2" type="float" interfacename="noise_scale" />
</multiply>

position : オブジェクト座標の位置(vector3)を取得

"positon"ノードを使用することで、オブジェクト座標での位置を取得します。

<position name="obj_pos" type="vector3" space="object" />

書式は https://materialx.org/assets/MaterialX.v1.38.Spec.pdf で確認できます。
36ページ目の"Geometric Nodes"を参照。

space="world"指定でワールド座標位置の参照になるようですが、Omniverse Create 2022.3.1では反映されませんでした。

fractal3d : 3Dフラクタルノイズ

ノイズの作成は"fractal3d"ノードを使用します。
これは3Dフラクタルノイズになります。

<fractal3d name="noise" type="float">
  <input name="octaves" type="integer" value="3" />
  <input name="lacunarity" type="float" value="0.5"  />
  <input name="position" type="vector3" nodename="scale_pos" />
</fractal3d>

書式は https://materialx.org/assets/MaterialX.v1.38.Spec.pdf で確認できます。
27ページ目の"Standard Procedural nodes"を参照。

"octaves"でオクターブを整数値で指定(デフォルト3)。
"lacunarity"は、octaveの間の指数関数的なスケール値の指定(デフォルト2.0)。
"position"は位置をvector3で指定。
outputはfloat値になります。

PerlinNoiseを使用する場合は、"noise2d"や"noise3d"を使用できます。

combine3 : 複数のチャンネルを1つに結合

"combine3"は、前回の「[Omniverse] MaterialXを使う – その3 : separate」で解説した"separate"の逆の操作を行います。

<combine3 name="combine_color" type="color3">
  <input name="in1" type="float" nodename="noise" />
  <input name="in2" type="float" nodename="noise" />
  <input name="in3" type="float" nodename="noise" />
</combine3>

書式は https://materialx.org/assets/MaterialX.v1.38.Spec.pdf で確認できます。
40ページ目の"Channel Nodes"を参照。

"combine3"はoutputとして"color3"または"vector3"を返します。
この場合、inputとして"in1","in2","in3"を指定でき、それぞれにfloat値を渡します。
ここでは、"fractal3d"からのfloat値を渡しています。
これでグレイスケールのカラーがノイズとして取得できました。

後は、今までと同じ流れになります。
"fractal3d"の値を加工していくと、冒頭であった"standard_surface_marble_solid.mtlx"の大理石のような表現になります。
乗算(multiply)、加算(add)、べき乗(power)、sin、合成(mix)の組み合わせで大理石模様にしています。
multiplyは説明済みなので、addとpower、sin、mixについてノード構成だけ書いておきます。

add

"in1"と"in2"の値を加算します。

<add name="add1" type="float">
  <input name="in1" type="float" value="0.1" />
  <input name="in2" type="float" value="0.3" />
</add>

参考 : https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/resources/Materials/TestSuite/stdlib/math/math_operators.mtlx

power

"in1"の"in2"乗の値を加算します。

<power name="power" type="float">
  <input name="in1" type="float" value="2.0" />
  <input name="in2" type="float" value="3.0" />
</power>

参考 : https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/resources/Materials/TestSuite/stdlib/math/math_operators.mtlx

sin

三角関数のsinの値を計算します。
"in"はラジアンで指定します。
1.5707の場合は、π/2で90度相当。

<sin name="sin" type="float">
  <input name="in" type="float" value="1.5707" />
</sin>

参考 : https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/resources/Materials/TestSuite/stdlib/math/trig.mtlx

mix

2値を合成します(lerp)。
"bg x (1.0-mix) + fg x mix"の計算になります。

<mix name="color_mix" type="color3">
  <input name="bg" type="color3" value="0.8, 0.8, 0.8" />
  <input name="fg" type="color3" value="0.5, 0.3, 0.9" />
  <input name="mix" type="float" nodename="0.2" />
</mix>

"UseNoise.mtlx"でmixを使う

例として前述の"UseNoise.mtlx"にて、"combine3"を"mix"に置き換えてみます。
nodegraphのコードだけ記載します。

<nodegraph name="NG_noise">
  <input name="noise_scale" type="float" value="0.1" />
  <position name="obj_pos" type="vector3" space="object" />

  <multiply name="scale_pos" type="vector3">
    <input name="in1" type="vector3" nodename="obj_pos" />
    <input name="in2" type="float" interfacename="noise_scale" />
  </multiply>
  <fractal3d name="noise" type="float">
    <input name="octaves" type="integer" value="3" />
    <input name="lacunarity" type="float" value="0.5"  />
    <input name="position" type="vector3" nodename="scale_pos" />
  </fractal3d>
  <mix name="color_mix" type="color3">
    <input name="bg" type="color3" value="1.0, 0.1, 0.0" />
    <input name="fg" type="color3" value="0.0, 0.1, 0.2" />
    <input name="mix" type="float" nodename="noise" />
  </mix>

  <output name="out_color" type="color3" nodename="color_mix" />
</nodegraph>

mixは以下のように記載しました。

<mix name="color_mix" type="color3">
  <input name="bg" type="color3" value="1.0, 0.1, 0.0" />
  <input name="fg" type="color3" value="0.0, 0.1, 0.2" />
  <input name="mix" type="float" nodename="noise" />
</mix>

fractal3dのfloat値を"mix"に指定しています。
なお、色についてはUSDやOmniverseのMDLと同じくLinear(raw)で指定します。

Omniverse Createでこのmtlxファイルを使用すると以下のようになりました。

ここで疑問点が出て来ると思います。
mixで2つの色を指定したのに黒が見えてますね。

fractal3dの値をクランプする

"RTX-interactive(Path Tracing)"に切り替えてみました。

黒は見えません。
どうやらこれは、fractal3dを使用するにあたって0.0-1.0の範囲にclampができていないのが原因のようです。
具体的にはfractal3dはマイナス値も返します。
これを修正してみます。

<multiply name="scale_v" type="float">
  <input name="in1" type="float" nodename="noise" />
  <input name="in2" type="float" value="1.0" />
</multiply>

<clamp name="clamp_v" type="float">
  <input name="in" type="float" nodename="scale_v" />
  <input name="low" type="float" value="0.0" />
  <input name="high" type="float" value="1.0" />
</clamp>

<mix name="color_mix" type="color3">
  <input name="bg" type="color3" value="1.0, 0.1, 0.0" />
  <input name="fg" type="color3" value="0.0, 0.1, 0.2" />
  <input name="mix" type="float" nodename="clamp_v" />
</mix>

まず"multiply"でfractal3dのfloat値の倍率を変えることができるようにしました。
ただ、ここでは倍率は1.0で値は変更していません。
"clamp"で"low"と"high"を指定することで、0.0-1.0の範囲に収まるようにしました。

これをOmniverse Createに読み込みました。

"RTX-Real-Time"

"RTX-interactive(Path Tracing)"

これで同じになりました。
"scale_v"の"in2"を4.0にしてみました。

Omniverseに読み込まれた段階でmtlxはMDLに変換されるため、パラメータはOmniverseで変更して確認できます。

fractal3dの値が0.0以下の場合は黒にしたい

上記の"UseNoise.mtlx"では、fractal3dの値が0.0以下の場合に黒にした方がカッコいい感じだったので、
"RTX-interactive(Path Tracing)"でもあえてそうしてみましょう。

"noise"はfractal3dのoutput値(float)、これはマイナス値も含みます。
"color_mix"にクランプされた色(color3)が入っているとします。

<multiply name="scale_v2" type="float">
  <input name="in1" type="float" nodename="noise" />
  <input name="in2" type="float" value="10.0" />
</multiply>
<clamp name="clamp_v2" type="float">
  <input name="in" type="float" nodename="scale_v2" />
  <input name="low" type="float" value="0.0" />
  <input name="high" type="float" value="1.0" />
</clamp>
<multiply name="m_color" type="color3">
  <input name="in1" type="color3" nodename="color_mix" />
  <input name="in2" type="float" nodename="clamp_v2" />
</multiply>

<output name="out_color" type="color3" nodename="m_color" />

"scale_v2"で"noise"の値を10倍と大きくすることで、値を大きくしてます(0.0付近の値を飛ばしている)。
"clamp_v2"でこの値をクランプします。結果的に、0.0か1.0に近い値が入ることになります。
その間は緩やかにグラデーションします。
これを"color_mix"に乗算することで、"noise"がマイナスになる場合は黒になるようにしています。

Omniverse Createで見てみました。
上が"RTX-Real-Time"、下が"RTX-interactive(Path Tracing)"。

これで同じ結果になりました。
最終的なmtlxファイルです。 UseNoiseMix2.zip

今回はここまでです。