Zenn
🦍

[UE5][習作]「オブジェクトを常にカメラの方に向かせるマテリアル」を作ってみました(解説&ファイル配布あり)

2025/01/23に公開
1

UE5のマテリアルの勉強の一環で、「オブジェクトを常にカメラの方に向かせるマテリアル」を作成してみました。
挙動の様子や機能説明などを動画にまとめましたので、まずはそちらをご覧ください。

紹介動画

https://youtu.be/K5WN0Nd5R_Y

解説

以下が今回のマテリアルノードの全体図です。


メッシュの頂点を移動させているため、WorldPositionOffsetNormalの2つのフェーズがあります。

考え方の流れ

それぞれのフェーズのノード説明の前に、まずは基本的な考え方から示しておきます。


例として、↓のようなワールド空間に、カメラと被写体となるオブジェクトが任意の位置と向きで置かれているとします。


まず、「原点がオブジェクトのピボットポイントにあり、カメラからオブジェクトに向かうベクトルをX軸」とするカスタム座標系を想定します。(X軸:ピンク、Y軸:イエロー、Z軸:シアン)

これはカメラからだと、↓のように見えています。


次に、オブジェクトをいったんワールドの原点に置いたと仮定します。


そうしたら、このオブジェクトをワールド座標系からカスタム座標系へ変換する、ということを考えます。(= 変換行列を適用する、ということ。)

これで、オブジェクトをカメラの方に向かせることができます。

では上記の考え方の流れをもとに、各フェーズのノード説明をしていきます。

WorldPositionOffsetフェーズ


まず、「カメラからオブジェクトに向かうベクトル」を算出します。


次に、そのベクトルをX軸とした座標軸を算出します。

この「MF_MakeCoordSystemFromXZ」ノードは、ファイル配布に含まれているMaterialFunctionです。これは、「基準となるX軸と、補助となるZ軸を引数にして、両者が直交する座標軸を作成する」ノードです。
「MF_MakeCoordSystemFromXZ」ノードの中身
【返り値の説明】

  • 「X」:入力の「BaseX」のまま正規ベクトルとして返ってきます。
  • 「Y」:入力の「BaseX」と「OptionalZ」に直交する正規ベクトルとして返ってきます。
  • 「Z」:「X」と「Y」に直交する正規ベクトルとして返ってきます。

次に、「ワールドの原点に置かれた想定のオブジェクト」に対して、変換行列を適用します。

「ワールドの原点に置かれた想定のオブジェクト」というのは、「LocalPosition」ノードのことを指します。このノードは「オブジェクトのローカル空間内の頂点の位置」を返しますので、Transformをかけずにそのまま使えば、それは「ワールドの原点に置かれた場合の位置」と同じになります。

また、「変換行列を適用」するには「Transform3x3Matrix」ノードを使います。これが前述のカスタム座標系への変換となります。入力の「BasisX」「BasisY」「BasisZ」 には、カスタム座標系の軸として、前述の「MF_MakeCoordSystemFromXZ」ノードの返り値の「X」「Y」「Z」を入れます。入力の「BasisPosition」 には、カスタム座標系の原点としてオブジェクトのピボットポイントを入れます。
(BasisX:ピンク、BasisY:イエロー、BasisZ:シアン、原点:オブジェクトのピボットポイント)で構成されるカスタム座標系

これら4つの入力によってカスタム座標系への変換行列を定義し、第1入力の「VectorToTransform」 に入れた「変換前の位置」にそれを適用することで、「変換後の位置」が返ってきます。


「Transform3x3Matrix」ノードで返ってくるのは、「ワールド空間における頂点の移動先の位置」になります。WorldPositionOffsetフェーズで最終的に必要なのは「ワールド空間における頂点の移動分」なので、差分を作るために元の位置で引いてあげます。

最後は「WorldPositionOffset」という名のOutputノードを作ってあげます。
これでWorldPositionOffsetフェーズは完了となります。続いて、Normalフェーズの方に移ります。

Normalフェーズ

「MF_MakeCoordSystemFromXZ」ノードで座標軸を作ることろまではWorldPositionOffsetフェーズと共通です。

そこからも同様に、「Transform3x3Matrix」ノードを使って法線ベクトルをカスタム座標系に変換するわけですが、2️つ注意点があります。

まず1つは、「VectorNormalWS」ノードで取得できる法線ベクトルをローカル空間に変換してあげる、ということです。WorldPositionOffsetフェーズのときは「LocalPosition」ノードを使ってローカル空間内の頂点位置を取得しましたが、「VectorNormalWS」ノードが返すのは「ワールド空間内の法線ベクトル」であるため、「Transform3x3Matrix」ノードに入力するためにまずローカル空間に変換してあげる必要があります。

2つめは、「Transform3x3Matrix」ノードの入力の「BasisPosition」には(0,0,0)を入れる、ということです。WorldPositionOffsetフェーズのときは「位置」でしたが、こちらは「ベクトル」ですので基点は無用です。逆に(0,0,0)以外を入力してしまうと誤った結果となってしまいます。


「Transform3x3Matrix」ノードによって「カスタム座標系に変換した後の法線ベクトル」が得られました。Normalフェーズで最終的に必要なのは「Tangent空間における法線ベクトル」なので、(念のため正規化したうえで)Trangent空間に変換します。

最後は「Normal」という名のOutputノードを作ってあげます。
これでNormalフェーズも完了となります。

作ったMaterialFunctionを使ってみる

使い方はとても簡単です、
LookAtCamera機能を導入したいオブジェクトのマテリアルを開いて作ったMaterialFunctionを出したら、出力の「Normal」と「WorldPositionOffset」をそれぞれメインマテリアルノードのピンにつなぐだけです。

Viewportで動作を確認してみましょう。↓のGIF動画のようにカメラを動かしてもオブジェクトがカメラの方を向き続けていれば成功です。

オプション機能

ファイル配布しているバージョンには以下の2つのオプション機能が実装されています。

「Lock Pitch」:上下方向には向かなくする


こちらは「左右(Yaw)には向くけど上下(Pitch)には向かなくする」(= Pitchにロックをかける)
機能です。

型はスカラー値で、0または1を入力します。

  • 0: アンロック(デフォルト)
  • 1: ロック

「1」を入力したときは、↓のGIF動画のように動きます。

「Rotation Offset」:オブジェクトに回転のオフセットをかける


こちらは「オブジェクトに回転のオフセットをかける」機能です。
この機能で、カメラに向かせたい角度を微調整したり、メッシュアセットの座標軸がもともとX-Frontではないオブジェクトに対して向きを調整したり、というようなことに使えます。

型はベクター値で、(X, Y, Z)の順で (Roll, Pitch, Yaw) に対応します。(↑の画像では、Roll=20°、Pitch=30°、Yaw=40° となります。)

デフォルト(0, 0, 0)のときはオブジェクトの[+X方向]がカメラの方を向き、[+Z方向]がワールドの上方向を向きます。

↓のGIF動画は、入力ベクター値の[X, Y, Z]をそれぞれInputパラメータ[RollOffset, PitchOffset, YawOffset]にして、マテリアルインスタンスから値を変えてみたときの様子です。

ファイル配布

Googleドライブからダウンロード

↓のリンクから「MF_LootAtCamera_UE5_5.zip」をダウンロードしてください。
https://drive.google.com/file/d/1fXauvryR5rqHC4UANNNNz4-q993Sx_Cc/view?usp=sharing

内容物

「MF_LootAtCamera_UE5_5.zip」を解凍すると、中には以下の8つのMaterialFunctionのアセットファイルが入っています。

  • 「MF_LookAtCamera.uasset」が、本体のMaterialFunctionです。
  • 「MF_MakeCoordSystemFrom〇〇.uasset」というファイルが6つありますが、実際に使っているのは「~XZ」だけです。(内容説明は「解説」の「WorldPositionOffsetフェーズ」の項目に記載しています。)他の5ファイルは今回の機能では使っていませんが、「~XZ」の亜種で便利なノードなので入れておきました。
  • 「MF_MultiplyRotationMatrix.uasset」は解説しておりませんが、こちらはオプション機能の「Rotation Offset」のために使っています。これは、「ベクトルにオイラー角指定のRotationをかける」というものです。

プロジェクトへの導入

導入したいプロジェクトのContentフォルダをエクスプローラで開き、解凍した「MF_LootAtCamera」フォルダをコピペしてください。

その後、UEエディタを開き、コンテンツブラウザ内で「MF_LootAtCamera」フォルダ下のMaterialFunctionアセット(8個)が正しく認識されていれば導入完了です。

あとは、LookAt機能を入れたいマテリアル内で、「MF_LookAtCamera」ノードを出して、出力の「Normal」と「WorldPositionOffset」をそれぞれメインマテリアルノードのピンにつないでください。(入力ピンの説明については「オプション機能」の項目をご確認ください。)

BoundsScaleの調整を忘れずに!

本機能は、マテリアルでメッシュの頂点を移動させているため、StaticMeshComponent(またはSkeletalMeshComponent)のBoundsScaleを調整する必要があります。詳細は以下のページに記載しておりますので、こちらも併せてご確認ください。
https://zenn.dev/h_sasaki/articles/d3a4c2e1f2bbc7

1

Discussion

ログインするとコメントできます