【UE4】Instanced Static Meshで部分的に色を変える

f:id:Nasvic:20190408021700g:plain

この記事について

先日第11回UE4ぷちコンへ作品を応募した際、大量に並べたInstancedStaticMeshの特定の箇所のみ色を変えたり、カーソルがオーバーラップしている箇所のみ点滅させたりする方法を模索していたので参考までにその方法を紹介します。



※ 2020/09/04追記

同一スタティックメッシュを大量に描画する際、記事ではInstanced Static Meshを使用していますが、UE4.22から「Auto Instancing」が利用可能になっているため、そちらに置き換えることで大量の同一スタティックメッシュ個別の情報を簡単に得られるようになり、現在ではマテリアルBPにカスタムノードを追記しなくても「Custom Primitive Data」機能で個別にマテリアルのパラメータを変更するが可能になっています。


Epic Games Japan篠山さんのAuto Instancing機能とCustom Primitive Dataの活用法記事。
(公式ドキュメントにはモバイル向けAuto Instancingの解説しか無かったため、こちらの記事を参考に貼らせていただきました)
qiita.com


それでもInstanced Static Meshを利用する必要に迫られた時のため、以下の記述は残しておきます。

Instanced Static Meshについて

f:id:Nasvic:20190408023608j:plain

今回の作品はキューブを大量に描画する必要があるため、当初キューブは一つずつアクターで処理していましたが、沢山のキューブを描画する場面ではFPSが30以下に落ち込むなど無理があったため、同一のスタティックメッシュを大量に描画することに向いているInstanced Static Meshに置き換えることにしました。

しかし、Instanced Static Meshでは個別にキューブのDynamic material instanceを変更することができず、カーソルとオーバーラップした箇所のみを点滅させたり、Zスケールを変更したキューブのスケール値に応じて色を変えることが通常の方法ではできませんでした。そのため、下記の方法をとりました。


Instanced Static Meshのスケールの値をマテリアル側で読込む

今回ちょうど下記のcom04さんの記事がぴったりで、大変助けられました。マテリアルにカスタムノードを追加して、Instanced Static MeshのZスケール値を読み込んだり、Xスケール値の小数点以下第二位に書き込んだ数値をマテリアルのカスタムノードで読み込み、その数値に応じて点滅させています。
qiita.com


マテリアルでは以下のようにノードを組んでいます

f:id:Nasvic:20190408034010j:plain

左上のカスタムノードAのコードは下記のとおり

(com04さんの記事のコードを改変して利用させていだきました)

#if USE_INSTANCING
/* 行列からスケール値を復元 */
float1 Scale = float1(
length(Parameters.InstanceLocalToWorld[2].xyz));

return Scale;
#else
return -1;
#endif

カスタムノードBのコードは下記のとおり

#if USE_INSTANCING
/* 行列からスケール値を復元 */
float1 Scale = float1(
length(Parameters.InstanceLocalToWorld[0].xyz));

/* 要素を少数第二桁から整数化 */
int3 InstanceIDElements = int1(Scale * 100.0) % 10;

return InstanceIDElements;
#else
return -1;
#endif



Instanced Static Mesh側のBPは下記のとおりです

全景
f:id:Nasvic:20190408033732j:plain

上半分
f:id:Nasvic:20190408142147j:plainf:id:Nasvic:20190408142153j:plain

下半分
f:id:Nasvic:20190408142158j:plainf:id:Nasvic:20190408142141j:plain

Instanced Static Mesh各種Transformの値をマテリアルで取得する方法について、詳細はcom04さんの記事を参考にしていただくとして、点滅の処理はプレイヤーのキャラクターBP(上記BPではキャストしているCursor)の位置を取得し、「Get Instance Overlapping Sphere」の基点としてそこから任意の球径でオーバーラップしているInstanced Static Mesh達を取得し、それらのXスケールの小数点第二位を変更し、マテリアル側の上記カスタムノードBのコードで読み取っています。

また、スケールが変更されたInstanced Static Meshの色の変更も同じように、マテリアル側の上記カスタムノードAでInstanced Static MeshのZスケールの値を読み取ってそれを色の情報に変換しています。


おわりに

f:id:Nasvic:20190408035120j:plain

(上記の画像ではスクショを撮る際にFPSが低下してしまったが、エディタウィンドウでは60FPS以上をキープしている)
以上、Instanced Static Meshで部分的に色を変える方法でした。この方法なら融通が効かないと思っていたInstanced Static Meshでもいろいろできるようになりました。com04さんに感謝…!