アンリアル エンジン 4 を使って行った一般的な Gear VR アプリケーションと VR 体験の開発に関する助言をさせて頂きます。ゲームの中でいくつかのエフェクトを実現するために使ったちょっとしたトリックをこっそり教えちゃいます。
教訓
素晴らしい Gear VR 体験をつくる基本は、早期の最適化
Samsung Galaxy S6 (我々のターゲット プラットフォーム) に使用されている Mali-T760 MP8 GPU の理論上で宣伝されているパフォーマンスは 210 GFLOPS と 5.2 GTexels/s 前後です。VR 用に推奨される PC GPU の Nvidia GeForce GTX 970 と互換性があります。RAW パフォーマンスは 3494 GFLOPS、フィルレートは 109.2 GTexels/s です。UE4 は、Oculus DK2 (2.097M vs 2.073M) よりも Gear VR デバイス上の方が多くのピクセルをレンダリングするので、利用可能な演算パワーと帯域幅がかなり減ることは明らかです。若干有利な点は、フレームレートです。Gear VR アプリケーションは 60 fps を維持し、Oculus Dks は 75 fps が期待され、Crescent Bay で 90 fps が求められます。
この数字を目指してパフォーマンスを改善するならば、アップフロントでの開発が唯一賢明なアプローチです。パフォーマンスを改善したいなら「最適化パス」に任せるのが一番、という考えは正しくありません。 なぜならその場合、かなり多くのアセットと機能を削除することになるからです。
VR の場合、開発の各ステップでパフォーマンスの検討を行うと良いでしょう。機能またはシーンをデザインする時、レンダリング対象の異なるオブジェクト数、必要とされるエフェクト、すべてのグラフィックス忠実度について考えてください。同じレンダリング設定で、プレースホルダー アセットをプロトタイプします。何かが原因でフレームレートが許容範囲に達しない場合、リバートし、ドロップするか、または別のブランチの性能にしてください。
Escape Velocity の開発を始めるまでは PC 上でしか UE4 を使った経験がありませんでした。後の開発段階では、ゲームは 60 fps 以上を一定に保つことができるものだ単純に考えていました。その考えは見事に外れ、作業は徹夜つづき、そして多くの機能を無駄にしました。 この経験から開発メソッドを調節したので、それ以降のプロジェクトではパフォーマンス上の問題に困ることはなくなりました。新なアイデアが生まれたら、まずパフォーマンス上の問題を抱えてないか精査して、完全にプロトタイプしました。
ドローコールについて
開発中は、フレームごとのドローコール数をしっかり注意して見ておくべきだと分かりました。異なるマテリアルのオブジェクトのドローコールによってドライバ ステートの変更があまりに多い場合、プッシュできても変な挙動をするトライアングル数を考えると、モバイル GPU は非常にパワフルです。
そこで我々は、ステーションを真っ二つに分けてから作業を開始し、最後に 1 つの大きなメッシュにすべてのテクスチャとマップをマージしました。すべてのモジュールをブロックアウト モデル(それぞれ ~30 tris) で置き換えても、Galaxy S6 の Mali-T760 MP8 は、必要とされる 60 fps を保つ管理をしないので、LOD は訳に立たないことがテストで分かりました。
オクルージョンもあまり役に立ちませんでした。EV でユーザーに与えられる自由度により、ステーション全体が画面上に表示できる状態になるからです。
またその当時、UE4 は Galaxy S6 上はインスタンス化ができなかったので、パーティクル エフェクトは使えず、ドローコールに白羽の矢が立ちました。ただし、現在は 4.11 でサポートされています。
リリースされたばかりの Vulkan API を今後のプロジェクトでモバイル GPU で使えるようになることを心待ちにしています。Epic’s Zen Garden のデモでは、Metal (できれば Vulkan も) といったローレベルの API がこれらのデバイスの真の潜在性が開花し、デベロッパーを制約のいくつかから解き放つことが分かります。
乗り物酔い
2012 年に最初の Oculus プロトタイプが開始して以来、乗り物酔いの課題は近代の VR 関連の討論で必ず取り上げられてきました。ゲームプレイ要素を犠牲することになっても、可能な限り減らしたいという意見でおおむね一致していました。
しかし EV の開発に実際に関わると、そんなに簡単ではないことを学びました。 乗り物酔いの原因が、技術的な欠陥でななくて、体験の本質そもそものに端をを発している限り、ユーザーにとっては大丈夫なようです。
Setapp では、EV に合わせて別の Gear VR アプリケーションをリリースしました。パズルゲームの Neverout です。タイトルからは「気持ちが悪くなる」ようなイメージは全くわきませんが、かなりゆっくりした動きでも具体が悪くなったという報告がユーザーからありました。
一方、Escape Velocity には、「なんてことだ、そこら中に吐いてしまったが楽しかった!」というコメントが多数寄せられました。
EV では、現実の世界でもそうであるように、人々は気持ちが悪くなることを期待しています。ただし、ユーザーは持ちこたえることができるように、気持ち悪さが最高に達した (ジェットパックで高速の回転がかかる) 直後に止まる方法にしてあります。
トリック
Postprocess box
4.10 では、モバイル HDR は Gear VR ではサポートされていません。つまり、ほとんどのポストプロセス エフェクトがないので、画面が明らかに色あせています。
イントロムービー シーケンスからフェードするには、このエフェクトが他のどれよりも必要でした。そこで、small hack を使いました。
法線をフリップさせたスタティクメッシュ (ボックス) をカメラ ポイントで固定しました。Unlit (ライティング無し) で Depth Test が無効の特別なマテリアルなので、他のジオメトリの上に描画できると確信していました。
通常、このオブジェクトは画面上には表示されません。オパシティがタイムラインでアニメートされた時のみ、簡潔に表示されます。
ボックスを小さくしすぎないでください。HMD 用の HeadModel はアイカメラごとにオフセットしてボックスを通してクリップします。
ただし、この方法では画面全体が再び描画されます。Galaxy S6 GPU のピクセル フィルレートはかなり制限されているので、別の大きな透過エレメントが画面上にあるとフレームレートが落ちます。
Gear VR ヘッドモデル
"HeadModel" は、首から目のちょうど真ん中へのオフセットを表します。ゲームで使用する Camera アクタは、この垂直な「首」の位置に配置されます。レンダリングに使用するそれぞれの目の実際の位置は、以下のように変形して、「首」の最初の位置をトランスフォームして計算します。
- ヘッド トラッキング オフセットを追加する (Gear VR はなし)
- ヘッド トラッキングからの入力に基づいて回転する
- HeadModel オフセットを追加する
- Inter Pupillary Distance (IPD) で目を別々にする
Gear VR では、UE4 は HeadModel と IPD を修正して使用しています (GearVR.cpp の Fsettings コンストラクタを参照してください)。Rift の場合、この情報は User Preferences (ユーザー設定) から読み込まれます。
Gear VR のデフォルト値は、我々のセットアップには大きすぎました。ヘルメットの中で宇宙飛行士の頭を回転させると、片目がそれを通してクリップします。 また、非常に小さいキャラクターをシミュレーションしたい場合、同じ HeadModel と IPD がまだ残っているので、キャラクター アクタを単純にスケールするだけでは不十分で、普通の人が床に横たわっているような印象になってしまいます。
そこで、HeadModel 全体をスケールしてみます。以下のコンソール コマンドを実行して、HeadModel、IPD 、ヘッド トラッキング オフセットを 0.1 スケールします。
- STEREO CS=0.1
- STEREO PS=0.1
これらのコマンドにより、カメラと潜在的なトラッキング オフセットが 10 倍にスケールされて、ユーザーは自分がとても小さくなったように感じます。
操作可能な HMD ランタイム パラメータについては、この関数
Engine/Source/ThirdParty/Oculus/Common/HeadMountedDisplayCommon.cpp function FHeadMountedDisplay::Exec() を参照してみてください。
UE4 の調整で (Gear) VR 体験クオリティを高める
ある機能のステートが原因で開発中に困難はありましたが、無事乗り越えることができました。発生した問題を紹介します。
UMG および UI 全般
VR で UI エレメントを使う作業は、難しいタスクでした。特に以下が、問題を起こす要注意の項目でした。
DEPTH TESTING と RENDER TO TEXTURE
ヘルメットの眼鏡の上に表示される UI のようなエレメントを作成したかったのですが、眼鏡のそばにこの UMG 3D ウィジェットを配置すると、カメラに近づきすぎてしまいました。Gear VR では、ユーザーは UI のフォーカスを合わせるために、無理して目を交差させなければなりません。
その後で、UI エレメントを数メートル押し離して大きくします。ただし、これによりステーションのジオメトリにクリップされます。
これらのエレメントは絶対に描画しなければなりません。標準のオブジェクトであれば、マテリアル設定の Depth Testing を無効にすれば良いです。UMG 3D ウィジェットの場合は、使用可能なマテリアルの一覧を修正します。Depth Testing を無効にするためのオプションを使って 3D ウィジェットを拡張 しました。
UMG ウィジェットをテクスチャにレンダリングする機能があればいいのにと思いました。そうすれば、3D ウィジェットよりも自由度が格段に大きくなります。背景のオブジェクトに UI エレメントを自然にブレンドする必要のある VR 設定では特にそうです。この要望はエピック ゲームズに伝えました。
GAZE 入力
今のところ、Gaze 入力を UMG 3D ウィジェットに簡単にパスする方法はありません。3D ウィジェットを拡張してマウス入力を合成するか、UMG を効率良く完全に避けながら、シーンの別々のオブジェクトでトレースを確認するセットアップを工夫しなければなりません。
UV 空間からマウス イベントへのライン トレース経由で UMG to texture と Gaze 入力サポートを組み合わせることができたら、VR の場合とても便利です。この機能に対する要望もエピック ゲームズに伝えました。
マチネ操作によるプレイヤー アニメーション
マチネのスケルタル メッシュのアニメーションは ASkeletalMeshActor およびその派生クラス上でのみ実行できます。ツールを柔軟に使って、ゲームの最初と最後のシーケンスにマチネで宇宙飛行士をアニメートしたかったのです。 しかし、ACharacter から派生したアクタには、マチネから直接コントロールしたスケルタルメッシュ アニメーションを付けることができませんでした。
通常 FPS ゲームでシネマティクスを行う場合は、プレイヤー キャラクターが表示されないように特別に作成したシーンへフェードして、特別に作成したスケルタル メッシュ アクタをたくさんスポーンします。 VR ではフェードで没入感を損ないたくありません。マチネ シーケンスと制御対象のプレイヤーに同じキャラクター オブジェクトを再利用したかったのです。シーケンスの最後に、キャラクターをプレイヤー制御モードにシームレスに切り替えたいです。
EV では、マチネでアニメートしたダミーのスケルタルメッシュを使い、本当のキャラクター (非表示ですが) をこのメッシュにアタッチします。シーケンスの最後に、ダミーを非表示にして本当のキャラクターを表示します。両方のメッシュの位置をぴったりそろえることは不可能なので、切り替えをした時に若干ずれていることがわかると思います。
終わりに
VR 開発では (モバイルの場合は特に) デベロッパー、デザイナーはまったく新しい課題を突き付けられます。一般的に広く採用されているパターンとソリューションのはずなのに作業が止まり、それとは違う方法を考えなければならなくなります。未解決の課題はまだ山積み、特にユーザー インターフェース関連がです。
モバイル VR は、デバイスの制約が非常に厳しいので特に難しいです。一貫したフレームワークを維持しながら最高のビジュアルを作り出すには、パフォーマンスを調整して創造性を豊かにしなければなりません。
アンリアル エンジンは、我々のビジョンをソリッドな製品に形を変えてくれました。実現にはまだ難しい項目もありますが、VR (特にモバイルは) まだ初期段階であることを考えると納得できます。UE4 の VR とモバイル機能が最近開発されて、新たなプロジェクトでの作業が楽しみになりました。
Escape Velocity または UE4 の VR 全般に関してご質問があれば、Unreal Engine forums に PM を送ってください。