マテリアルノードの解説 その1

微妙に需要がありそうなので今回から何回かに分けてマテリアルノードの解説を行っていこうと思います。

特によく使うマテリアルノードの解説を行いますので、あまり使わないものは軽い解説で済ませるか、悪い場合はスルーします。

各ノード解説の前に、少しばかりわかりにくい部分を少しでも明確にしておこうと思います。

それは、マテリアルで利用する数値です。

Blueprintでは数値は整数、小数点数、ベクトルなどがそれぞれ明確に別の型として存在しています。

ue113.jpg

出力ピンの色が明確に違うのがわかりますよね。

しかし、マテリアルノードではこのような違いが存在しません。

ue114.jpg 

マテリアルによって生成されるシェーダは、この辺の処理が明確な場合はコンパイラが勝手にそれっぽい計算をしてしまいます。

例えば、float4のvectorValueとfloatのfloatValueがあったと仮定し、これを加算した場合、結果は以下のようになります。

resultValue = {vectorValue.x + floatValue, vectorValue.y + floatValue, vectorValue.z + floatValue, vectorValue.w + floatValue};

ちなみに、明確でない場合はコンパイラがエラーを返します。

実際、UE4のマテリアルでも明確ではないと判断されるものについてはエラーが出ることがあるようですね。

LinearInterpolateのAlphaピンにfloat4を入力したりするとエラーが出ますね。

まあ、この辺は慣れないとほんとにわかりにくいかと思います。

シェーダに慣れてない方は、とにかくやってみてエラーが出たらエラーの内容に従って修正を行う、という形で対応するしかないように感じます。

これを機にシェーダコードを書いてみる、ってのもありかとは思いますが。

では、本題のノード解説に進もうと思います。

今回はMathカテゴリのノードの中で、特によく使うものを解説しようと思います。

・Add, Subtract, Multiply, Divide, Fmod

ue115.jpg

いわゆる四則演算と剰余算、プログラムっぽく書くと、+, -, *, /, %です。

特に四則演算はよく使うってレベルではないですね。剰余はそれほど使用頻度は高くないですが。

ちなみに、検索する際に各記号でも検索が可能です。

注意点としてはVectorとScalarの計算はできるのですが、Vector2とVector4などの異なる要素数Vector同士ではエラーになります。

まあ、たいていのノードで異なる要素数Vector同士は計算できなかったりします。

・LinearInterpolate

ue116.jpg

個人的に四則演算以外でよく使うノードNo1がこれ。いわゆる線形補間です。

AとBのピンは同じ要素のVectorVectorとScalar、もしくはScalarとScalarを入力します。

AlphaはScalarのみ有効です。

計算式は以下のようになります。

A * (1 - Alpha) + B * Alpha

Alphaが0なら結果はAとなり、1に近づくにつれて数値がBに近づいていきます。

なお、0~1の範囲以外もAlphaに入力することができますが、クランプされないので注意してください。

・OneMinus

ue117.jpg

意外とバカにならない使用頻度のOneMinusくん。

SubtractでAに定数1.0、Bに変数を入れればこれと同じ動作になります。

なぜ独立しているのかというと、昨今のGPUはこの計算をフリーで行えるからじゃないかと思います。

・Floor, Frac

ue118.jpg

Floorは小数部を切り捨てる命令、Fracは逆に整数部を切り捨てる命令です。

Floorは整数値を取得したい場合によく使われ、Fracは1.0を超えたところで0.0にループさせたい場合によく使います。

Ceilという完全に切り上げる命令もあるんですが、シェーダ書いてて使った記憶がないですね…

Clamp, Max, Min

ue119.jpg

Clampは入力された数値(一番上)をMinとMaxの間にクランプ(整地?)します。

つまり、Minより小さくなったらMinを選択、Maxより大きくなったらMaxを選択、Min~Maxの間ならそのままの数値を出力します。

ClampモードとしてClamp、Min、Maxを選択でき、ClampモードならMinとMaxの両方が有効、MinモードとMaxモードはそれぞれの数値しか有効になりません。

Maxはクランプとは違いますが、入力された2つの数値のうち大きな方を、Minも同様に入力値の小さい方を取得します。

入力がVectorの場合は各要素ごとに処理されます。

・Abs, Power, SquareRoot

ue120.jpg

数学系の3つですが、Absは特によく使うかと。

Absは絶対値です。負の値なら-1を積算して正の値にするものですね。

Powerは累乗です。Base^Expの計算が行われます。シェーダでガンマ計算する際によく使います。

SquareRootは√です。PowerのExpを0.5にしても同じ結果が得られるはずですが、誤差はあるかもしれません。

・DotProduct, CrossProduct

ue121.jpg

ベクトル計算の内積外積です。ベクトルとか覚えてないよ、という人でもこれらは覚えておいて損はないですのでしっかり勉強しましょう!

特に内積はライティング計算で非常によく使います。

AとBにはどちらもベクトルを入力するのが基本です。

内積は、AとBが正規化されたベクトル(長さ1のベクトル)の場合に、2つのベクトルのなす角のcos値となります。

これがなぜよく使われるのかというと、AとBが同じ方向を向いている時に1.0、直角なら0.0、逆向きなら-1.0という、非常にわかりやすい数値になるからです。

外積は2つのベクトルに対して直角なベクトルが返ってきます。

使いどころがそれほど多くないのですが、クリティカルに必要な場面がたまにあります。

詳しい計算式や定義については各自ググって調べておきましょう。

・Normalize, SafeNormalize

ue122.jpg

ベクトルの正規化命令です。正規化とは、ベクトルの長さを1.0にすることです。

この命令が2つあるのには理由があります。

ベクトルというのは方向を持った力、とよく言われます。ある方向に長さn、というのがベクトルの正体です。

正規化前のベクトルの長さが100だろうが0.1だろうが、方向はわかっているので、方向を変えずに長さを1にすることが可能です。

しかし、方向を持っていないベクトルの場合は正規化できません。

方向を持っていないベクトルとは何か?もちろん、長さが0のベクトルです。

この場合、長さ1のベクトルを計算することが不可能になってしまい、無理やり正規化すると非数という、数値ではない数値を返してきます。

Normalize命令はまさにこの計算が行われてしまうのですが、SafeNormalizeは正規化不可能な場合にDefaultの値を返します。

・AppendVector

ue123.jpg

シェーダ言語にはこのような命令はないと思いますが、似たようなことはよくやります。

この命令は、VectorやScalarを用いて要素を増やす命令です。

わかりにくいので例を示します。

A:Vector2(0.5, 0.2)

B:Scalar(0.8)

結果:Vector3(0.5, 0.2, 0.8)

このようにして要素を増やすことができます。

ただし、要素が増やせるのはVector4までです。Vector4を超えるとどうやら正常な値は返ってこないようです。

・If

ue124.jpg

UE4のマテリアルにはBPのBranchのような分岐命令はありません。

昨今のシェーダ言語は分岐やループといった命令が存在しているのですが、不用意に使用すると速度が極端に下がったりします。

そのためか、UE4のマテリアルでは分岐といえる命令がこのくらいしかないように見受けられます。

入力値は5つですが、AとBの値を比較し、その比較結果によって3つの数値のどれかが選択される、という内容です。

個人的には出来れば使いたくない命令です。

というのも、直感的にわかりにくいから!

しかし、使わなければ難しい場面も出てきそうですし、その場合は我慢して使用します。

というわけで、今回はMathカテゴリの解説でしたが、いかがでしたでしょうか?

Mathカテゴリはよく使うノードが多いので、とにかく使って覚えるようにした方がよいでしょう。

何かわかりにくい部分などがあるようでしたら、メールなりコメントなりTwitterなりで質問してください。

追記させていただきます。

なお、より詳しい解説は英語ですがこちらが参考になります。

https://docs.unrealengine.com/latest/INT/Engine/Rendering/Materials/ExpressionReference/index.html