UE4でのインスタンシング
SV_instanceidが取れなかった
これまでUE4ではSV_instanceidがVRの用途でしか使われておらず、マテリアル上からは取得できませんでした。
したがって、インスタンス毎の違いを出すには、PerInstanceRandomノードを使ったり、インスタンスの初期位置をインデックスに見立てるなどの回りくどい処理をする必要がありました。
CustomDataの登場
最近InstancedStaticMeshにインスタンス毎のカスタムデータが設定できるようになり、ここにIDを突っ込む事で、これまでややこしかった処理が簡単に書けるようになりました。
### なにが楽になったのか
RenderTargetとInstancedStaticMeshをつかってUAV的な事をやる場合に、読み込むデータの位置や、書き込み先の割り出しが容易になりました。
特にエンジン改造やC++のコードが必要ではないので、CSなどのプラグイン作成をするほどではない部分や、ナイアガラだと実装しづらい部分の隙間を埋めることが出来ます。
実装例 リアルタイムヒストグラム実装
ここでは実際の実装例として、以下の動画にあるリアルタイムヒストグラムを解説します。
簡単なものなので、大まかに流れだけ説明します。こないだのは色がわかりにくかったから修正。最終的なヒストグラムの描画はポストマテリアル。
— おく/奥川 剛 (@t_oku) June 5, 2020
あとでQiita書くか pic.twitter.com/IrtiEqjhUB
準備するもの
①InstancedStaticMeshをもったBPアクター
②①のInstancedStaticMeshにアサインするためのマテリアル
③SceneCapture2D
④256*1でFP16のRenderTarget
⑤結果を描画するためのポストマテリアル
インスタンスにIDを振る
①のBPアクターにInstancedStaticMeshを追加します。
メッシュは1m*1mの正方形(/Engine/BasicShapes/Planeで構いません)をアサインし、マテリアルは②をアサインします。
追加InstancedStaticMeshComponentに、CustomDataを一つ追加します。
BPアクターのConstrutionScriptにて、サンプリング数分(今回は100*100の1万個)のインスタンスを作成し、同時にCustomDataを書き込んでいきます。
インスタンス用マテリアルの実装
まず、②のマテリアルはUnLitで”加算”設定にし、出力のエミッシブには1を設定します。書き込み先であるRenderTargetの値をインクリメントさせて行くためです。
次に、割り当てられたID(0~9999)から、シーンの画像中で自身がサンプリングすべき位置(UV)を算出し、フェッチします。
そして、その輝度(0~1.0)を256*100倍してWPOに渡します。これで書き込み先をどこにするか決定しています。
RenderTargetへの書き込み
①のアクターを(-12800,0,0)に配置します。
③のSceneCapture2DのモードをUse ShowOnlyListに設定し、ShowOnlyActorsに①のアクターだけを追加します。
③のSceneCapture2Dの設定を正射影にし、OrthoWidthを25600に設定します。
ターゲットには④の1Dターゲットを指定します。
ここまでで、以下のような描画結果になります。左端(0,0)が一番暗い所、右端(255,0)が一番明るい所に対応しており、シーン中使われてる輝度が多い所ほど値が大きくなっています。
結果の表示
出来上がった1Dテクスチャをポストマテリアルでフェッチして、グラフ表示すれば、CPUへの書き戻しなしで、ヒストグラムを描画する事ができました。
まとめ
実戦投入するにはいくつか整理日する必要がありますが、実装自体は半日かからずサクッとお手軽にできました。
次は、DOFなどで使われてるような、任意の形状にボケるスキャッターベースのブラーなどを時間あれば同様の手法で実装してみたいと思います。