【UE4】Instanced Static Meshに対し個別のマテリアルにランダム値を渡したい
スポーンする度に違う色のボールが飛んできてほしい・・・みたいなことってよく思いつくことだと思いますが、ゲームエンジンだと結構ハードルが高い。私のように和風住宅ビジュアライゼーションをやっていると結構ランダマイズはしたくなってくるものです。特に屋根瓦なんかは地域によりますが、年季が入っている屋根瓦だと劣化の差もそこそこあるので、そういうのをランダム値で表現してほしいなあ、なんて思ってしまう。
例えば、1つのとあるメッシュをランダムカラーで並べたいと思うと、次のような手段があることはあります。
実現方法 | 懸念点 |
---|---|
Actorブループリントクラスを作って、コンポーネントにStatic Meshを追加して、メッシュのマテリアルをDynamic Materialにすることで一応は実現する。 | FPSがめっちゃ重い。100個くらい置くだけでFPS=15になってしまう。 |
Instanced Static Meshに対してDynamic Materialを与える。 | 1種類のランダム色で統一されてしまう。でもFPS=60は維持。 |
Instanced Static Meshに対して個別にランダム色を与える。 | こんな都合の良い方法ってないものか? |
っていう話になりますよね。きっとFPS=60出るでしょうし。
マテリアルエディタ内のランダムノード
マテリアルエディタに[Per Instance Random]というランダム値を与えるノードってあるんですね。知らなかった。少なくとも4.19くらいまではこんなの無かったような??? まあいいか。
でも、これでは今回の目的は達成できません。
![]()
2021/4/12 12:30追記
ナスヴィッチ様からよりよい情報をご提供いただいています。誠にありがとうございます! UE4.25から可能とのことで、私の方でも動作確認は取れております。
近日中にこちらの機能を踏まえた内容に再編集予定ですはじめまして、いつもWebサイトの記事拝見させていただいております
ISMのインスタンスごとマテリアルにランダムな数値を与えたい時、PerInstanceCustomDataを使う方法もありかもしれません (4.25から追加の機能) pic.twitter.com/W9lwDQLOIF— ナスヴィッチ (@nasuvic) April 12, 2021
やってみよう
情報源はこちらの方より。んー、とにかくすごい。天晴。
[UE4]InstancedStaticMeshのInstanceIDを何とかしてマテリアルで取得する – Qiita
1.ブループリント側の設定
今回は「ブループリントクラスで複製配列Arrayが出来ること」前提で進めます。
なのでまずはXとY方向にArray出来るようにします。
次に、Add InstanceしたInstancedStaticMesh 1つ1つに対しておまじないをかけます。
これが参考サイト様の考えられた手法の1つで、シェーダーで閲覧できるパラメータであるTansformの一部分にこっそりと渡したい数値を乗っけちゃえば良いじゃないと。非正規な手段だということになりますが、実にすごい、よく思いつくなあ。
なんか10年くらい昔にHDR処理の数値保持のテクニックでこんなのがあったので、知識として持っておくのはよいかもしれないですね。
ゲーム制作者になるための3Dグラフィックス技術
7章 HDRレンダリング Column プレイステーション3におけるHDRレンダリングのトレンド メタルギアソリッド4の場合
の説明でも似たようなテクニック使っているのを思い出しました。
ということで参考サイト様のやり方と同じで、InstancedStaticMeshのTransformのScaleに、マテリアルに渡したい値を1/1000倍にして足し合わせておきます。
今回渡したい値はランダム値で、いっぺんに3つの値をマテリアルに渡したいので、[Random Unit Vector]で3つのランダム値を生成させてみる。例えば
Random Unit Vectorが生成した3値が X=0.123、Y=0.456、Z=0.789 だったとします。
これを1/1000すると X=0.000123、Y=0.000456、Z=0.000789 になりますね。
こいつをScaleに足します。すると、
Scaleは X=1.000123、Y=1.000456、Z=1.000789 になります。
こんなことすると、インスタンス毎に大きさが変わってしまうじゃん――っていう話ですが、そうです変わっちゃいます。でもすごい小さい値だったらばれないよね・・・(なんだったら屋根瓦みたいな個性が出る商品だったら”いい味”が出るよねえ(誤魔化す)・・・みたいな妥協ができるパラメータを探します。
最後に[Update Instance Transform]します。
さらに、InstancedStaticMeshの数を[Get Instanced Count]ノードで得て、全部のインスタンススタティックメッシュに対して処理を行います。つまり[For Loop]を使います。
これで出来ました。
2.マテリアル側の設定
さっき保存した値をカスタムシェーダーで取得する必要があります。[Custom]ノードを置いて、[詳細]の[Code]という箇所に以下のソースをコピペします。
length(Parameters.LocalToWorld[0].xyz),
length(Parameters.LocalToWorld[1].xyz),
length(Parameters.LocalToWorld[2].xyz)
);
Scale -= 1f; // スケールは1倍なので、1引いてやります ⇒ X=0.000123、Y=0.000456、Z=0.000789 になった
Scale *= 1000f; // ブループリントで1/1000倍したので、1000倍してやります ⇒ X=0.123、Y=0.456、Z=0.789 になった
return Scale;
さらに[Vertex Interpolator]ノードをかませるとPixelShader用に変換されて、float3値としてちゃんと得られます。
最終的にはこんな感じにしました。[Break Out Float3 Components]ノードを噛ませれば値がR、G、Bの3つにバラすことが出来ます。
完成
テストとして、じゃあこれをBaseColorに接続してみましょう。
お、できましたね。
じゃあこれを過去に作成した屋根瓦で試してみます。
X、Y、Zのランダム値を、BaseColor、Metallic、Roughnessに与えて、不規則にしてみましょう。
できました。グーだね。
参考サイト
・[UE4]InstancedStaticMeshのInstanceIDを何とかしてマテリアルで取得する – Qiita
1 thought on “【UE4】Instanced Static Meshに対し個別のマテリアルにランダム値を渡したい”