概要
WidgetComponentでDynamicMaterialInstanceを使おうとしたら詰まったので、解決策のメモとして。
環境はUE4.24。
やろうとしたこと
Widgetの見た目の変更を、Widgetのアニメーションや表示切り替えを使わずに、WidgetComponentのMaterialだけでやろうとした。
※Materialで見た目を変えた場合、Widgetの見た目をRenderTargetに再描画する処理が入らない為、パーツの多いWidgetの場合軽量化が見込める。
今回はサンプルとして、テキストのColorを変える。
取り敢えずWidgetでテキストを配置して、赤いMaterialをWidgetComponentに割り当てた。
問題発生
ここまでは順調だったのだが、いざパラメーターをMaterialに渡そうとしたところで問題が発生した。
UE4でMaterialにパラメーターを渡し、動的に見た目を変える場合、DynamicMaterialInstanceを作成する必要がある。
StaticMeshComponentなどで使う時と同様に、BeginPlayでWidgetComponentのDynamicMaterialInstanceを作成した。
すると、先程まで表示されていたテキストが、デフォルトマテリアルの見た目になってしまった。
原因
もしかして未対応なのかと考えながらログを見てみると、下記のようなログが出力されていた。
LogMaterial: Warning: MaterialInstanceDynamic MaterialInstanceDynamic_2 is not a valid parent for MaterialInstanceDynamic MaterialInstanceDynamic_3. Only Materials and Material InstanceConstants are valid parents for a material instance.
これだけだとなんのこっちゃといった感じだが、ログを出力している箇所から処理を追ってみると、原因が分かった。
WidgetComponentは、RenderTargetに描画する為に元々DynamicMaterialInstanceを変数に保持していて、それがUWidgetComponent::SetMaterial
が呼ばれる度に更新される。
DynamicMaterialInstanceを作った場合SetMaterialも呼ばれる為、保持していた描画用のDynamicMaterialInstanceも更新されるが、ここで問題が発生する。
現在のMaterialを元にDynamicMaterialInstanceを作成し、描画用の変数を更新しようとするが、現在のMaterialは自分で作ったDynamicMaterialInstanceになっているので、DynamicMaterialInstanceを親にしてDynamicMaterialInstanceを作ることになる。
これには対応していないようで、結果的に上に貼ったログが出力される。(DynamicMaterialInstanceはDynamicMaterialInstanceの有効な親ではありません)
結論
WidgetComponentでDynamicMaterialInstanceを使いたい場合は、描画用にDynamicMaterialInstanceが勝手に作られているので、それを参照するだけでいい。
UWidgetComponent::GetMaterialInstance
で参照出来、Blueprintからも呼ぶことが出来る。