PavilionDV7の雑多なやつ

Qiitaから移行しました。UE4に関する記事から興味のあることまで色々書きます。

【UE4】簡単な3Dインジケーターの作り方

はじめに

第14回ぷちコン応募作品でも実装した超簡単な3Dインジケーターの実装を紹介します。 3Dインジケーターがどのように機能するかは次の動画をご覧ください。

youtu.be

プロジェクトはこちら

バージョン:UE4.25.3

https://1drv.ms/u/s!Au-8FqgREBKZjBUGMnDI4mqbBLIt?e=MCX1pf

インジケーターブループリント

いきなり今回の肝であるインジケーターブループリントから紹介します。インジケーターを構成するコンポーネントは次のようになっており、過去に投稿した第14回ぷちコン応募作品実装メモにて紹介されていた構成と同じです。

f:id:PavilionDV7:20200912183334p:plain

動作に必要なプロパティ(変数)は次の2つです。

f:id:PavilionDV7:20200912183603p:plain

Radius : ルートコンポーネントとStatic Meshコンポーネントの離れる距離(生成時に指定される) Target : インジケーターが指し示すターゲットの参照(生成時に渡される)

Begin Play

Begin Playでは指定されたRadiusの値に則ってルートコンポーネントとStatic Meshコンポーネントを離します。ローカルなコンポーネント同士で距離を取ったりする場合は、距離を取らせる対象に対してAdd Local Offsetすると簡単です。

f:id:PavilionDV7:20200912183936p:plain


Add Local Offsetの際にStatic Meshコンポーネントの前方ベクトルを使用したのは次の図を見ていただくとわかる通り、インジケーターメッシュは+X軸を前方としているからです。

f:id:PavilionDV7:20200912185808p:plain

DCCツールでモデリングしたメッシュをインジケーターとして使用する場合は出力時の軸を意識する必要があります。出力時にY軸を正面としてしまった場合はメッシュがZ軸に90度回転した状態で表示されてしまいます。UE4では前方はX軸なのでDCCツールからの出力時にX軸を前方とするよう設定してあげると余計な不具合を出さずに済みます。

Tick

Find Look at Rotationを使ってターゲットへ向くための回転を求めます。ロール回転(X軸)やピッチ回転(Y軸)は不要なのでZ軸の値だけを取り出しSet Actor Rotationへとセットします。

f:id:PavilionDV7:20200912191317p:plain

この時、回転させる対象はStatic Meshコンポーネントではなくルートコンポーネントとなります。これによってインジケーターはプレイヤーを中心に回転しターゲットを指し示します。

見やすくするためのひと工夫

動画を見てお気づきになられた方もいらっしゃると思いますが、インジケーターの指し示すターゲットがプレイヤーカメラの正面に来た時、インジケーターはプレイヤーの体に隠れてしまいます。動画のようにインジケーターが隠れた時、プレイヤーの正面にはターゲットがいるとわかるような画面構成になっていれば問題はありませんが、非常に遠い位置にターゲットが居る場合や複雑な地形でターゲットが視認できない場合にはプレイヤーは混乱してしまいます。

解決策として視認出来る位置まで対象となるインジケーターの角度をつける方法があります。

f:id:PavilionDV7:20200912211010p:plain


ターゲットが前方にいるかどうかを知るために内積を使用します。単位ベクトル同士で内積を取ることでベクトルが向いている方向の近似度合いを知ることが出来ます。ざっくりとした説明ですが単位ベクトル同士を内積した結果は次のようになります。

f:id:PavilionDV7:20200912212349p:plain

内積を取る対象となる2つのベクトルを決める必要があります。基準とするベクトルはプレイヤーカメラの前方ベクトルとします。カメラは常にプレイヤーが見たい方向を見ているので基準とするには最適です。もう一方のベクトルはインジケーターからターゲットへと向かう単位ベクトルです。 プレイヤーカメラの前方ベクトルとインジケーターからターゲットへ向かう単位ベクトル同士で内積を取ることで、あるターゲットはプレイヤーキャラクターの前方にいるかを知ることが出来ます。

欲しい数値を取れたので後は得られた数値に傾けたい角度を掛けて、ピッチ(Y軸)の回転としてセットしてあげるとインジケーターは無事カメラへと映るようになります。

f:id:PavilionDV7:20200912214116p:plain

インジケーターの生成

インジケーターの生成はプレイヤーブループリントで行っています。

f:id:PavilionDV7:20200912214357p:plain

第14回ぷちコン応募作品ではAdd Child Actor Componentを使用してプレイヤーにアタッチしていましたが、冷静になってみればノード数が少なくて済むSpawn Actor & Attach Actor to Actorの組み合わせが楽だと思います。

今回はBegin Playで一括で生成していますが、必ずしもBegin Playである必要はないです。何らかのアクションゲームであればバトルエリアに侵入したとき、オープンワールド的ゲームであれば敵とプレイヤーが戦闘状態に入った時に生成してもうまく機能すると思います。

制約

このインジケーターはカメラとインジケーターの間に何かしらの障害物(キャラクタの体や壁等)があると遮られて見えなくなってしまいます。プレイヤーの体であればインジケーターに角度をつけることで回避できますが、それ以外ではこの対処は通用しません。

思いつく解決策としてはCustomDepthとポストプロセスを用いたハイライトやアウトライン描画があります。今回のプロジェクトには組み込んでいませんがハイライトやアウトラインについては数多くの記事や動画、マケプレアセットがあるので特に解説はしません。

おわりに

3DインジケーターはUIを用いたインジケーター表示に比べると非常に簡単です。モデルやマテリアルによっては画面を彩るかっちょいい要素の1つとして活躍すると思います。

ただしオブジェクトに遮られてしまう弱点があるので視認性の確保には苦労すると思いますが、ここで紹介した角度をつけたりポストプロセスを使用したりすることで案外簡単に解決できそうな気もします。