タグ別アーカイブ: Unreal Engine

Unreal EngineのマテリアルエディタでVR表示時にもScreenAlignedUVs的な効果を実装する

まだ当サークルではUnreal EngineもVR(Oculus)も使い始めたところなので、
間違っていることもあるかもしれませんが、備忘録的に技術的なことを書いてみようと思います。

次回作の「マヨナカ・ガラン」は画面演出手段の一つとして、
一部の物体や人物に三次元空間上の位置ではなく二次元スクリーン中の位置に対して座標を固定するテクスチャ表現を使っています。
以下の映像では、煙のパーティクルや聖堂中の村人たちのテクスチャがそれにあたります。

Unreal Engineの場合、マテリアルのテクスチャ座標の決定にScreenAlignedUVsノードを使うことで
上記のようなスクリーン中の位置に対して座標を固定することができるようです。
(UEオンラインマニュアルのScreenAlignedUVsの解説

しかし、体験版をVRに移植しようとしたところテクスチャ座標の計算で問題が発生しました。
VR表示時にScreenAlignedUVsノードを利用すると、視差の問題で元のオブジェクト中のある点を
スクリーンに投影する位置が右目側と左目側で異なるため、テクスチャによる模様が両眼で矛盾を起こしてしまいます。
before
(テクスチャの矛盾の例)

そこで、矛盾を起こさないように両スクリーンとは異なる擬似的なスクリーンを想定して、そこに投影することにします。
具体的には、両眼の真ん中(単眼時と同じ位置)にあるカメラに紐付いたスクリーンを取得し、
その投影行列をテクスチャ座標の計算に利用します。
これにより、両眼での視野上で一定したテクスチャ座標への投影が可能になります。
after
(整合性のあるテクスチャの例)

両眼の真ん中にあるカメラに紐付いたスクリーンの投影行列は、レベルエディタ上のコードで取得することができます。
これは、もともとUEでは通常の描画とVRでは途中まで処理を共有しているため、
レベルエディタ上では通常の描画(単眼)用のカメラを保持していると考えられるためです。
具体的には、ULocalPlayer::GetProjectionData()で投影行列を取得することができます。

取得した行列は、マテリアルエディタのBlueprintに渡したいのですが、
行列をそのままの形を受け渡す方法が見つからなかったので以下の方法を利用しました。
マテリアルエディタはMaterial Parameter Collection というベクトルの集合を大域変数的に利用でき、レベルエディタからもアクセスできるため、
4×4のViewProjection行列を4×1のベクトル4つに分解し、Material Parameter Collections にそれぞれのベクトルをセットします。
(UEオンラインマニュアル中のMaterial Parameter Collectionsの解説)

(C++ソースコード例)
FMatrix ProjMat;
ULocalPlayer *lP = GWorld->GetFirstLocalPlayerFromController();
FSceneViewProjectionData ProjData;
lP->GetProjectionData(GEngine->GameViewport->Viewport, EStereoscopicPass::eSSP_FULL, ProjData);
ProjMat = ProjData.ComputeViewProjectionMatrix();

後は、マテリアルエディタ側で投影行列を受け取り、WorldPositionを掛けあわせます。
(実際はベクトルで受け取っているので、それぞれの行ベクトルとの内積をとっています)
あとはスケールを調整すると、スクリーン上の座標に従うテクスチャが表示できます。
BluePrintは以下のようになります。
material-2
(マテリアルBluePrint例)

また、UEのanswerhubで同様の試みをしている記事を見つけました。
これも投影行列をレベルエディタ上のコードで取得し、Material Parameter Collectionsで行列を受渡しています。
マテリアルエディタ側では、Custom UVでHLSLを書いて投影行列の掛け算を実行しているようです。

これで目的を達成することができたのですが、もっと簡単な方法があるかもしれませんので、
その場合はコメント欄などで教えていただけると嬉しいです。