UE5のマテリアルへの動的パラメータ設定

# はじめに
この記事はUnreal Engine (UE) Advent Calendar 2023 シリーズ4 12/16(金)としての投稿です

https://qiita.com/advent-calendar/2023/ue

# 動的パラメータについて

https://docs.unrealengine.com/5.3/ja/unreal-engine-materials/

マテリアル内のパラメータやテクスチャをプレイ中に動的に変更する機能がいくつか用意されているのでまとめてみました

UE5.3.2準拠

# 機能一覧

||扱える要素|変更影響範囲|備考|
|:--|:--:|:--:|:--|
|Material Instance Dynamic (MID)|Scalar, Vector, DoubleVector, Texture|インスタンス単体|別途インスタンス生成が必要|
|Material Parameter Collection|Scalar (1024個), Vector (1024個)|参照している全マテリアル|1マテリアルが参照できるのは2アセットまで|
|Custom Primitive Data|Scalar, Vector (Scalar 36個相当まで)|PrimitiveComponent単体||
|Per-Instance Custom Data|Scalar, Vector|InstancedMeshComponent内の各インスタンス単体|InstancedMesh専用|
|Dynamic Parameter|Vector (4個)|パーティクル単体|Niagara専用|

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624395/67484832-00f0-f69b-b812-edea33e9f0b8.png" width=50%>


# Material Instance Dynamic (MID)
https://docs.unrealengine.com/5.3/ja/instanced-materials-in-unreal-engine/#マテリアルインスタンスダイナミック
* 変更できるものの種類が一番多い
  * 参照Textureを動的変更できるのはMIDのみ
  * Doubleを扱えるのもMIDのみ
* 逐次インスタンス作成が必要なのが面倒

一番基礎的な方法だと思います。
インスタンス作成と管理が面倒。なのでまずは下記のMaterialparameterCollectionやCustomPrimitiveDataでやりたいことが可能かを検討してダメそうならMIDを使うというという事になるかと思います。

# Material Parameter Collection
https://docs.unrealengine.com/5.3/ja/using-material-parameter-collections-in-unreal-engine/

* 値を変更すると参照しているすべてのマテリアルで値が変化
* 1マテリアル内で参照できるMaterialparameterCollectionは2アセットが上限

>1 つのマテリアルは、最大 2 つの異なる MaterialParameterCollections を参照することができます。1 つは通常、ゲーム全体の値として使用され、 もう 1 つは、レベル固有のパラメータとして使用できます。

すべてのマテリアルに影響を与えることができるため、主な用途はシーン全体に関わる要素（天候関連や場面演出など）になると思います。
MIDの様なインスタンス作成や管理が不要なので扱いやすいですが、上記の通り1マテリアルから参照できる数に制限があるので設計で注意が必要になります。

他の用途として、シーケンサからポストプロセスマテリアルのパラメータ変更したい場合はMaterialparameterCollectionを介して扱うことになるかと思います（シーケンサはポストプロセスマテリアルのMID作成をしてくれないため）。

# Custom Primitive Data
https://docs.unrealengine.com/5.3/ja/storing-custom-data-in-unreal-engine-materials-per-primitive/

* PrimitiveComponent単位で値を設定
* 名前ではなくインデクスでの管理
  * 同じインデクスを別用途のパラメータに設定していると不具合の原因になる

PrimitiveComponent(StaticMeshComponentやSkeletalMeshComponent)に設定されているマテリアル全部に影響します。
各キャラクターやオブジェクトの全マテリアルへ演出用の値を設定するなどの場面で使用しやすいと思います（例えばバフによる発光の強度を設定するとか）。

インデクスでの管理となるためメッシュに複数マテリアルある場合はマテリアル間でインデクス割当を共通化しておく必要があります。

# Per-Instance Custom Data
https://unrealcommunity.wiki/using-per-instance-custom-data-on-instanced-static-mesh-bpiygo0s

* InstancedStaticMeshComponent用
  * インスタンスごとに異なる値を設定できる
* 名前ではなくインデクスでの管理
  * 同じインデクスを別用途のパラメータに設定していると不具合の原因になる

CustomPrimitiveDataのInstandeStaticMesh版です。インスタンスごとに任意の値を設定することが出来ます。
CustomPrimitiveDataと同じくインデクスでの管理となるため同様にメッシュ内のマテリアル間でインデクス割当を共通化しておく必要があります（インデクスの管理はCustomPrimitiveDataとは別）。

また、インスタンスごとの乱数については後述の専用ノードが用意されています

## Per-Instance Random
https://docs.unrealengine.com/5.3/ja/constant-material-expressions-in-unreal-engine/#perinstancerandom

* InstancedStaticMeshComponent用
  * インスタンスごとに異なる値が取得できる
  * 変動はしない
* マテリアル外からの値設定は不要

インスタンスごとの乱数を取得できる専用ノードです。
ブループリントなどの設定処理不要で使用できます。

>この出力値は、0 からターゲット プラットフォームの RAND_MAX 値との間の整数となります。

上記のような記載がありますが、実際に渡ってくる値は0から1の間の浮動小数点数でした。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624395/ab60a16c-5671-3b51-fa93-2d9738f03b28.png" width=50%>

# Dynamic Parameter
https://docs.unrealengine.com/5.3/ja/quick-start-for-niagara-effects-in-unreal-engine/

* Niagara専用
  * パーティクルごとに値設定
* インデクスでの管理
* 扱えるパラメータ数が少ない
  * Vector 4個（Scalar 16個相当）まで

Niagara専用のパラメータです。Niagara向けマテリアル作成時は多用することになると思います。
扱えるパラメータ数が少ないため凝ったことをしてくると足りなくなります。Particle系ノードと役割分担が必要になります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624395/4d63ef61-fcec-c181-1933-e88b6c7c7550.png" width=50%>

エミッタ単位でのパラメータならバインディングのMaterialParameters経由でMIDを使えるため、こちらの使用も検討してみてください。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624395/85a5581a-b988-3279-6c60-9de212f41c5e.png" width=50%>

# 後記
実現したいゲーム仕様の実現方法は何通りも存在しますが、適した機能を使用することでより楽になるかと思いますのでこの情報が役に立てれば幸いです。

今回初めてのAdvent Calendar参加だったので無難な題目でやらせていただきました。
次回以降はもっと尖った内容になるかも

# 参考

https://historia.co.jp/archives/33401/

https://www.docswell.com/s/Namiton/KGXVLP-2023-11-18-123203

より詳しい解説がされており参考になります

https://www.docswell.com/s/EpicGamesJapan/ZQ41RK-UE_UFE22S_TangoGameworks#p69

MaterialParameterCollectionの運用例あり