[UE4] Material Editorで行列計算をしたい


Material Editorでは、行列を表すようなデータ型を隠蔽している。標準的なシェーディング言語では当然のように組み込まれているので、GLSLなどを書いてきたプログラマは少々とまどう。以下、行列を利用するときのワークアラウンド。

Vector4とCustomノードを用いる

結論としては、Vector4を4つ用意し行列をつくり、演算にはCustomノードを用いる。

ここでは、Material Parameter Collectionで定義された4つのVector4(RGBA)を使っている。Constant Vector4Parameterももちろん使える。

Customノードでは任意のHLSLが書けるので、この中で行列を宣言し、計算も行っててしまう。罠としては、行列の宣言で一部制約がある。floatNxN{}をもちいた宣言はコンパイルエラーになるので、matrix<float, N, N>{}で宣言と初期化を行う。
UE4にはこうした初見殺しの罠が散りばめられているが、Material Editorは単にHLSLを吐き出すのではなく、中間言語からプラットフォームに応じたシェーダ言語を生成する高機能なツールなので、このような細かいトランスパイル不備は目を瞑る…。


// floatNxN と {} をもちいた宣言はコンパイルエラーになる
float4x4 IMatrix = {
    1.f, 0.f, 0.f, 0.f,
    0.f, 1.f, 0.f, 0.f,
    0.f, 0.f, 1.f, 0.f,
    0.f, 0.f, 0.f, 1.f
};

// コンパイルエラーにならない
matrix<float, 4, 4> shadowTrans = {
    1.f, 0.f, 0.f, 0.f,
    0.f, 1.f, 0.f, 0.f,
    0.f, 0.f, 1.f, 0.f,
    0.f, 0.f, 0.f, 1.f
};

以下、自分が実現したかったことをメモ的に残す。

例: WorldPositionから特定のカメラ視野のUVを求める

いわゆるピクセルシェーダー内で、ShadowMap法でLightCameraのデプスマップを参照するときの方法であり、これができると影を自作したりプロジェクターのシミュレーションができたりする。精緻なプロジェクションマッピングのエミュレータ的なツールを作りたかったが、そのためにはプロジェクターキャリブレーションをしてIntrinsicParameterを求めたりが必要そうだったので未来の自分か誰かに託すことにした。

Material Editor

Customノード

ピクセルの絶対座標とカメラのViewProjection行列(4つのVector4で代用)を引数にとり、そのカメラ内での正規化されたUV座標を返す。ベクトルと行列をかけて、座標を補正するだけ。

パラメータを渡すBlueprint

こういうノードマップは見てもナンノコッチャという感じではあるが、やっているのは、複数のScene Capture 2Dコンポーネントから、

  1. ViewProjection行列を取り出し(Make MinimalViewInfo -> Get View Projection Matrix
  2. 4つのRGBA(4次元ベクトル)をつくって、MaterialParameterCollectionにセット(Break Matrix -> Break Plane -> Make Color -> Set Vector Parameter Value

をしている。行列を取得してからそれをパラメータに食わせられるような型にするまで遠かったりする…。

ちなみに Scene Capture 2D はカメラとして機能しながら、生成されるカメラ空間の法線マップ、デプスマップ、色情報などにアクセスできるため非常に便利。