[Omniverse] マテリアルの割り当て その6 (Material Graph)

前回で、Material Graphを使ったノードベースのマテリアルのカスタマイズが見えてきました。
今回はMaterial Graphが必須の表現を追いかけていきます。

Omniverse Create 2021.3.8を使用しました。

タイリングを目立たなくする

前回はMaterial Graphを使用してOmniPBRでも表現できるマッピングまで行いました。
この場合は、タイリングが目立ちます。

Perlin Noise Texture

BaseColor(Albedo)に対して、ノイズを加えてみます。
Perlin Noiseを使ってみましょう。
「Texturling, high level」から「Perlin noise texture」ノードをGraphに追加します。

いったんPlasticノードのColorにつないでいたテクスチャをDisconnectして解除します。
「Perlin noise texture」のColorをPlasticノードのColorにつなぎました。

ここでMDLのコンパイルが行われます。
しばらく待つと以下のように表現されました。

Perlin Noiseはグレイスケールの濃淡を返します。
いわゆる「プロシージャルテクスチャ」として処理されるため、タイリングの繰り返しは出てきません。

「Perlin noise texture」ノードを選択し、Propertyでパラメータを調整します。
「Upper threshold」を1.0から0.5に変更しました。

ノイズがくっきり出ました。
「Levels」を3から5に変更しました。

ノイズがより細かくなりました。

テクスチャを合成 (Multiply color)

元のBase ColorのテクスチャとPerlin Noise Textureを合成してみます。
「Math functions」で「Multiply color」ノードをGraphに追加します。
この「Multiply color」ノードは2つの色を乗算する機能になります。

「Multiply color」の「a」にBase Colorのテクスチャのcolor、「b」にPerlin Noise テクスチャのcolorをつないでいます。
この場合は、Perlin Noiseテクスチャの白部分にBase Colorのテクスチャが反映されることになります。

「Perlin noise texture」の「Upper threshold」の値を上げると、黒い箇所が少なくなります。
以下は「Upper threshold」を0.5から0.7に変更しました。

この黒い部分に別のテクスチャを当てはめると、テクスチャのタイリングは目立たなくなるのが分かりますでしょうか。
Perlin Noiseテクスチャをマスクとして使用するわけですね。

2つのテクスチャを合成 (Perlin Noiseテクスチャをマスクとして使用)

2つのテクスチャをマスクを使って混ぜる操作は、一般的なShaderでは「Lerp」を使うことが多いです。
Material GraphでもこのLerpは存在し「Lerp color」ノードが色を混ぜ合わせるものになります。
以下の書式になります。

colorC = lerp(colorA, colorB, v)

これをプログラムで書くと以下のようになります。

colorC = colorA * (1.0 - v) + colorB * v

「Bitmap texture」ノードを追加し、別の土模様のテクスチャを与えました。
UVのTilingは(3, 3)を指定しました。
なお、元のテクスチャのUVのTilingは(5, 5)を指定しています。
UVのTilingによる繰り返し数が合成するテクスチャで異なる、というのが大切な条件になります。
「Math functions」で「Lerp color」ノードを追加し、以下のように「a」に新しいテクスチャのcolor、「b」に以前のテクスチャのcolorをつなぎました。

1つ前で追加した「Multiply color」は不要になったので削除します。
「Lerp color」ノードの「l」はfloat値となり、0.0-1.0の数値を指定します。
lを0.0/1.0/0.5に変化させた場合は以下のようになりました。

0.5を指定した場合は両方のテクスチャが合成されて(ColorC = (ColorA + ColorB) * 0.5の計算)タイリングが目立たなくなっています。

「Lerp color」ノードの「l」にPerlin Noiseテクスチャの「mono」をつなぎます。

こうすると、Perlin Noiseテクスチャをマスクにして2つのテクスチャが合成されることになります。
規則性を出さないようにするため、2つめのテクスチャのRotationとOffsetを与えてわずかにずらしました。

「Perlin noise texture」ノードの「Upper threshold」を0.7としたときは以下のようになりました。


土や壁など規則性がないテクスチャの場合は、このような合成がタイリングをごまかす有効な手段になります。
これはMDL/Material GraphといったShader相当の機能がないと、実現できない表現になります。

地面に近いほど汚す、浸食表現

土の汚れやコケなど、地面に近いほど汚すというのもMDL/Material Graphを使用します。
まずはレンガ模様のBaseColorと法線マップテクスチャを用意し、Material Graphでマテリアルを与えました。
ColorはsRGB、法線マップはrawのColor Spaceを与えています。

以下のようになりました。

Hit position : ワールド座標位置を取得

「Hit position」ノードは、ワールド座標上の位置を返します。
Material Graphの左よりpositionで検索すると出てきます。

これのY値を使って、Y値が0.0に近づくほど汚れが強くなるようにします。
この汚れは、前述と同じようにPerlin Noiseテクスチャを使用し別途コケのテクスチャを与えることにしました。

Y float : float3からY値を取り出す

「Hit position」のoutputは「float3」です。
これからY値を取り出します。
「Y float」で検索すると、複数の同一ノードが出てきます。
これらは引数が異なります。しばらくマウスオーバーしているとツールチップが出ます。
「float y(float3)」のものをGraphに追加します。

「Hit position」のoutから「float y」の「a」につなぎます。

「float y」のoutはfloat値になります。

Clamp float : float値を指定の範囲内に収める

「Clamp float」を探し、Graphに追加します。

これは指定のfloat値をmin-maxの範囲内に収めるようにします。
Clamp floatのPropertyでminを0.0、maxを100.0としました。

この場合は、Y値は0.0~100.0(cm)の範囲となるようにしています。

Divide float : floatの割り算

「Constant float」をGraphに追加して、Propertyで100.0の入力値を与えました。
「Divide float」をGraphに追加して、「Y値 / 100.0」の計算を行うようにしました。

これで出力は0.0 – 1.0の値になります。Y=0に近づくほどこの値は0.0に寄ります。

Lerp color

「Lerp color」を配置し、「a」にColor(0, 0, 0)、「b」にレンガのテクスチャのColorを入れます。
「l」にdivideした値(0.0 – 1.0)を入れます。

この時の色は、地面に近づくほど黒くなる表現です。
以下のようになりました。

Pow float : aのb乗の計算

もう少し濃淡を調整しやすいようにするため、DivideとLerpの間に「Pow float」を入れました。
これは「pow(a, b)」のようにすると、「aのb乗」の計算を行うものです。

「b」に1.5を入れました。

黒の影響がもう少し広範囲になりました。

Perlin Noise Texture

PowとLerpの間にPerlin Noiseを入れて不規則さを加えます。
Powのoutputに対して、「Perlin Noise Texture」の「mono」を加算します。
加算は「Add float」で行います。
Perlin Noise Textureの「Upper threshold」を0.5に変更しました。
「Add float」のoutputをClampで0.0-1.0に補正します。

結果は、以下のように黒い部分でノイズの不規則さが加わりました。

最後に、Plasticのノードの1つ前の「Lerp」の「a」を定数のColor(0, 0, 0)から、
「Bitmap texture」ノードのコケのテクスチャに置き換えます。

これで、以下のように地面に近づくにつれてコケに浸食される感じになりました。

Material Graphはこんな感じです。

ノードベースはぱっと見は分からないですよね。
Omniverseに限らず、ノードベースのUIは説明しづらいのに加えて見ても速読が難しいかなと。

もちろんマテリアルに対してのカスタマイズであるので、他の形状に対しても適用できます。

今回はここまでです。
今のところ、Material Graphは以下が対応されていないように感じました(機能がすでに存在していたらすみません)。

  • 複数ノードのグループ化
  • Inputパラメータをまとめる
  • Graphの描画がViewportのレンダリングにひっぱられる

2つめは値を変更したりテクスチャを変えたい場合、各ノードのPropertyから変更する必要があるようで、1か所にまとまってればなと。
3つめはGraphのノードが増えて、シーンも複雑になるとGraph操作が重くなります。
Graph操作が重すぎて使えないレベルにはなります。

この3つをなんとかするため、次回はMDLをSubstance Designerで作りOmniverseにインポートして使うようにします。
たぶん、マテリアルのカスタマイズはMDLを外部ツールで作って運用するのがベストかと思います。