はじめに
こんにちは、クライアントエンジニアの下野です。
今回はマテリアルパラメータコレクション(以下MPC)の、実行中の値を確認できるようにする処理を行います。
MPCとは
複数のマテリアルで共有できる変数群みたいなものです。

ScalarとVectorの2種類が選べます

通常マテリアルの値を変えるにはScalarParameterなどを使用しますが、マスターマテリアルが異なる場合は同じ用途同じ値を使用したい場合でも、別のパラメータとして出す必要があります。変更する際も全てのマテリアル確認する必要があり面倒です。
MPCを使えば値を1つ書き換えるだけで、参照している全てのマテリアルに変更が走るため、複数の異なるマスターマテリアルを管理する場合に優れています。
シーケンサーで値を変える
作成したMPCの値はシーケンサーやBP、C++で変更できます。
今回はシーケンサーで行ってみます。

MPC用のトラックがあるので、先ほど作ったMPCを指定します。

適当にキーを打ってあげればその通りに見た目が変わります。

本題
シーケンサー再生中にMPCをエディターで表示してみると、シーケンサーの値は動いているのに、MPC内の値は変わっていません。

これはデフォルトの値を変更しないように、値が変更される場合はインスタンスを作成してそちらの値だけを変えるような処理になっており、本体の値が変わっていないため起きています。
C++でコード書いたことある人ならわかると思いますが、MPCのインスタンスはUMaterialParameterCollectionInstanceという名前で、これをしないと値が変更できません。
// UPROでパラメータ出しておいて、MPCをセットする必要がある TObjectPtr<UMaterialParameterCollection> MPC; // セットされたMPCからInstanceを作成 UMaterialParameterCollectionInstance* MPCInstance = GetWorld()->GetParameterCollectionInstance(MPC); // 値の変更 MPCInstance->SetScalarParameterValue(TEXT("Name"), 0.0f);
本体の値が変わらないようにインスタンス作るのは理解できましたが、PIEやシーケンサーでランタイムの値が見れないというのはかなり不便です。
シーケンサーやBPなど複数個所でMPCを動かしていて、想定されている値か確認ができないのです。
BPではGetScalarParameterValueとかで値を取ることができ、PrintStringとかのノードに繋げば値を確認することはできます。
しかし、見た目が変になってると思った際にわざわざブレークポイントとったりPrintStringしたりするのは手間が掛かるので、MPCクリックで直接値を確認したいです。
そのための修正を加えていきます。
エンジン改造で解決
コードはGitHubのリンクを貼り付けています。(Epicの規則的に)
URLをクリックした際に下画像が出る場合は、UnrealEngineのEULAの同意をしないといけないため、リポジトリ取得の手順を踏んでからお試しください。

変数追加
MPC内にランタイム用の変数が無いので追加します。
Engine/Source/Runtime/Engine/Public/Materials/MaterialParameterCollection.h
エディター以外で使うことないので、WITH_EDITORONLY_DATAで括ってパッケージではビルド外れるようにします。
値にアクセス出来てしまうと元の値が分からなくなるので、VisibleAnywhereにしておきます。
セッターを追加
値セット用の関数を作ります。
Engine/Source/Runtime/Engine/Public/Materials/MaterialParameterCollection.h
こっちは関数なのでWITH_EDITORで括ってあげてください。
MPCの実装部分はParameterCollection.cppにあります。
Engine/Source/Runtime/Engine/Private/Materials/ParameterCollection.cpp
余談ですが、UE5.6だとMaterialParameterCollection.cppが中身ほとんど無いですが一応存在はしているので、今後のアップデートでコードの場所変わるかもです。
値変わったらセット
MaterialParameterCollectionInstanceのセット処理で、先ほど作成したセッターを呼び出します。
Engine/Source/Runtime/Engine/Private/Materials/ParameterCollection.cpp
別になくてもいいですが、MPC本体の値が変更された場合も値セットしておくと初期値も値そろって丁寧です。
Engine/Source/Runtime/Engine/Private/Materials/ParameterCollection.cpp
MPCはインスタンスの参照持ってないですが、インスタンス側はMPCの参照持っているので関数の呼び出しとても楽です。
ここまで出来たら終わりです。
デバック
MPCを選択するとDefaultValueの下にRuntimeValueが出来ています。

シーケンサーなどで値が変わった際にも動くので確認も楽です。

余談
今回エンジン改造でやりましたが、インスタンスの中身を見ればいいだけなのでEditorUtilityWidgetとかでも実装できます。
EditorUtilityWidgetの方が別プロジェクトに持ってく場合に楽なんですが、インスタンスのクラスや、GetParameterCollectionInstanceがBPに公開されてないため、結局C++弄ることになりますし正味エンジンコードいじる方が変更少ないので妥協しました。
EditorUtilityWidgetでやる場合は、UMaterialParameterCollectionInstanceに値の変更検知用のデリゲート○○ParameterUpdateDelegate(○○はScalar, Vector)があるので、関数作って引っかけてあげれば、値の変更検知にTick使わなくて済むので軽くなります。
終わり
いかがでしたか?
この程度ならデフォルトであって欲しいですが、無いなら作ればいいという脳筋思考で解決です。
細々していますが、デバック効率は上がるので雑に作っておいてもいいと思います。
もっとエンジン改造したら、変更したBPとかシーケンサーの名前とかを文字列で取ったり参照とったり出来そうですが、さすがに要らんので割愛します。