PolySpatialでの簡易ポータル表現
概要
visionOSのRealityKitにはPortalMaterialという、奥に別の空間があるような表現ができる機能があるのですが、PolySpatialでは使用できるようになっていません。
そのため、今回はPortalMaterialの代わりにインテリアマッピングを使用して、Unityでも簡易的に奥行き感が出るような表現を行なっていきたいと思います。
インテリアマッピングとは
インテリアマッピングとは視線位置から擬似的に奥行きのある空間を描画する方法です。
スパイダーマンのゲームで使用されており話題になっていました。
描画しているのは平面ポリゴンのみなので、ポリゴン数が削減できつつ、部屋の中の表現もテクスチャを切り替えることで違った見た目にすることができます。
詳しいインテリアマッピングの実装につきましてはコポコポさんの記事を参考にさせていただきました。
インテリアマッピングについてわかりやすく解説されています。
窓から見える面を計算
インテリアマッピングはカメラから奥に見える面を求めて表示しています。
視線方向から奥に見える面は、窓となる面から視線方向へ伸ばした時に、一番最初に壁に当たる部分となります。
奥の面が1立方メートルの大きさだとすると、窓の位置から視線方向へ伸ばした時のX, Y, Z 成分のベクトルが一番早く1に到達する面が窓の位置から見える面になります。
下記の部分ではX成分は3つ分で面に到着し、Z成分は6つで面に到着するため、この場合はX成分の面が一番近い面になります。
X,Y,Z軸の各面までの距離は開始位置によって異なってきます。
視線ベクトルがプラスの時、X座標の位置が 0.6 の位置では、残りの距離が 1 - 0.6 = 0.4になるため、0.4に到着するまでのベクトルの長さが最短距離となります。
視線ベクトルがマイナス方向に進んでいる場合は、マイナス方向の面が当たる位置を求める必要があるため、マイナス方向に進む場合とプラス方向に進む場合で残り距離の計算を変える必要があります。
0.4 の位置では 0.4 が残りの距離になります。
視線ベクトルのX成分がプラスの時は1から引くことで距離が求められるため、このような計算式になります。
視線ベクトルのX成分がマイナスの時は、0から引くことでStartDistanceをマイナスとして、視線ベクトルで割る時に マイナスとマイナスで割ることでプラスとなり 必要な距離を求めることができます。
これを視線ベクトルをStep関数を使用して 0以下だったら0、0以上だったら1となるようにまとめます。
求めた MinDistance を 視線ベクトルにかけることで 一番近い面に到達した時のポイントがわかるようになります。
複数の面からの対応
上記の計算をワールドスペースで行うと正面を向いている面が窓の時は正しく計算ができるのですが、ビルのように正面以外の面にも窓をつけたい場合は、軸が変わってしまうのでうまくいきません。
これをどの面から見ても計算できるように、タンジェント空間(TangentSpace)での計算にしていきます。
TangentSpaceは法線方向をZ軸とした座標系で、ポリゴンの面に沿ってX軸とY軸が存在します。
ポリゴンのX,Y軸がポリゴンの面に沿うため、テクスチャを貼るUV座標を計算する時に使用されます。
視線方向のベクトルをTangetSpaceへ変換を行い、開始地点をUV座標の位置を使用することで、TangentSpaceで一番近い面の計算を行います。
カメラへの向きである ShaderGraphではViewDirection
ノードのSpace
をTangentに変更することでTangentSpaceでのカメラ方向へのベクトルを取得することができます。
しかし、ViewDirectionはポジションからカメラへのベクトルになるので逆向きにして視線方向のベクトルに変換する必要があります。
この時、TangentSpaceでは右手座標系でUnityの左手座標系とはZ軸の方向が反対になるため、Z軸だけは向きを変えずに使用します。
CubeMapへの対応
TangentSpaceでの一番近い面との交点を求めたら、CubeMapの向きに変換していきます。
CubeMapはこのような構造のテクスチャになっており、各面の情報が割り当てられています。
+Zの方向が正面、-Zが背面、+Yが上面などに割り当てられているため、交点の位置のベクトルの成分の大きさが 1となっている面を選択し、それ以外の成分をUVとして使用することで、テクスチャの色を選択していきます。
ShaderGraphではDirection
を渡すことでサンプリングすることができるので、交点のベクトルを渡してテクスチャを拾います。
TangentSpaceで計算したものは 0〜1 の範囲で計算しているので、-1〜1 となるようにRemapを行い、Direction
として使用します。
ShaderGraphの構築
それではインテリアマッピングのShaderGraphを構築していきます。
まずは、UVをタイリングして複数の部屋を作れるようにします。
Fraction
は少数部分を取得することができるため0~1を繰り返すことができるようになります。
次に視線方向のベクトルを取得します。
ViewDirection
のSpace
をTangent
に変更して、視線方向となるようにX
,Y
軸を反転させます。
次に開始地点から視線方向のベクトルが面に到達するまでの距離を求めています。
UV座標を開始地点として使用して、視線方向のベクトルの向きに合わせて計算方法をStep
によって切り替えています。
次に一番近い面までの距離を求めていきます。
Split
によってX
,Y
,Z
成分に分解を行いその中で、一番低い値を取得します。
次に面にヒットする位置のポイントを求めます。
次にCubeMapのサンプリングを行います。
Remap
ノードを使用して0〜1の範囲から-1〜1に変換しています。
サンプリングの結果をFragmentのBase Color
に入れることで完成です!
ビルのように見せるために、窓枠のテクスチャをつけたり、タイルごとに色合いやテクスチャを変えたりすることでより自然になってきます。
まとめ
これでPortalMaterialがなくても奥行きがある表現が作成できました!
visionOS2 のPortalMaterialでは空間から飛び出てくるような表現も使えるようになっているので、PolySpatialでも使用できるようになってくれると嬉しいですね。
エンジニア絶賛募集中!
MESONではUnityエンジニアを絶賛募集中です! XRのプロジェクトに関わってみたい! 開発したい! という方はぜひご応募ください!
また最近ではAIの活用も積極的に進めており、XR x AIに興味があるエンジニアの方もぜひご応募ください!
MESONのメンバーページからご応募いただくか、TwitterのDMなどでご連絡ください。
書いた人
佐藤 寿樹
株式会社コナミデジタルエンタテインメントに入社し5年間ウイニングイレブンのオンライン実装に携わる。
その後、株式会社コロプラで9年間エンジニアとしてアプリ開発・運用を行い、位置情報やARを使用したARゲーム開発、OculusRiftやPSVRなどのVRゲーム開発を経験しMESONへ入社。
MESON Works
MESONの制作実績一覧もあります。ご興味ある方はぜひ見てみてください。
Discussion