Oculus向けのコンテンツをUE4で制作するために、セットアップがまだな方はこちらの「Unreal Engine 4 (UE4) でOculusを使うための手順」を参考にセットアップと動作確認をお願いします。
また、UE4のドキュメントサイトにも「Oculus Rift クイックスタート」というページもありますのでざっと目を通しておいてください。
ということで、UE4コンテンツをOculus上で動作確認はできる状態になっているものとしてここからのお話は進めさせていただきます。
#Oculus上で75fps出すためのノウハウ
いきなりでなんなんですが、Oculus Rift DK2では75fps動作させることが推奨されています。これって結構ハードルが高くて所謂コンソール界隈だとアクションゲーム(特に格闘ゲーム等)には60fps動作が求められているんですけど、その他は結構30fpsで動いていたりするものも多かったりします。
で、Oculusの場合は左右の眼用に2画面描画しなければならず、両方別々にレンダリングすると単純計算でフレームレートは半分になってしまいます。なので30fps動作しているようなものは15fpsにまで落ちてしまう可能性があります。
しかもOculusさん、次のバージョンでは解像度が上がる(描画するピクセル数が増えるのでGPUネックのコンテンツはフレームレートがさらに落ちる可能性がある)うえにフレームレートまで上げる事を想定していると・・・あははは、全然ムリじゃん。
ムリじゃない!不可能を可能にする!とか、無いものを創りだす!というのがクリエイターの醍醐味。ですよね?
実際にUE4のOculus動作で75fps化に関してはおかずさん(@pafuhana1213)の「UE4+OculusRift DK2で75fps安定させるまでにしたこと」に詳しい情報があります。
###1. まずはボトルネックを調査するための下準備
UE4で様々な調査をする際に便利なのが「コンソールコマンド」というものなんですが、コンソールコマンド入力用のキーがUSキーボード仕様になってしまっているので、日本語キーボードでも入力しやすいキーに変更しておきます。
インストールフォルダ\バージョン\Engine\Config\BaseInput.ini(Windowsの標準的な状態だと、C:\Program Files\Unreal Engine\4.5\Engine\Config\BaseInput.iniになっていると思います)を開いて、「+ConsoleKeys=Tilde」という行を探してその下に「+ConsoleKeys=F12」という行を追加して「F12」キーでもコンソールコマンドが打てるようにしましょう。(他のキーを設定しても大丈夫です)
もしくは「編集」メニューの「プロジェクト設定」から、「エンジン」-「入力」の「Console Keys」でプロジェクト毎に設定することも可能です。
(ちなみにコンソールコマンド自体を追加する事もできますが、historiaさんの解説記事がわかりやすいです)
###2. ボトルネックの調査
ゲームをプレイしてコンソールコマンド「stat unit」や「stat unitgraph」を入力することでFrame(1フレームの実行時間)/Game(ゲームスレッドの実行時間)/Draw(描画スレッドの実行時間)/GPU(GPUの実行時間)をミリ秒単位で表示する事ができますが、Game/Draw/GPUは平行して動作しているので、Frameはその中で一番大きな数字に連動します。(ちなみに60fpsの場合は16.6msに、75fpsの場合は13.3msに収まっている必要があります)
実行してみるとわかるんですが、Game/Draw/GPUの中で一番重いのはGPUになっているのではないかと思います。
あと、実はstat機能はエディタの画面でもビュー左上の「▼」ボタンから「リアルタイム」と「統計情報を表示」にチェックを入れて「統計データ」から「Engine」の「UnitGraph」等にチェックを入れる事でリアルタイムに確認可能です。レベル制作時等はこちらが便利かもしれません。
あと「Advanced」内の「SceneRendering」や「InitViews」はDraw Call数を見れたりや、カリングが効いた結果のプリミティブ数等も確認できて便利です。
###3. GPU内のボトルネックの調査と軽減
「ProfileGPU」というコンソールコマンドもしくはShift+Ctrl+,(カンマ)キーのコンビネーションでGPUのプロファイルができます。
上部にグラフが出て、下部に各項目毎の処理時間が表示されますが、上部のグラフで大きな領域を占めているのが「HZB」「Lights」「PostProcessing」あたりになっているんじゃないかと。
####3.1 HZB
HZBって耳慣れないけど何?ってなる人が多いと思いますが「Hierarchical Z-Buffer」という階層的なZバッファを使って遮蔽のテストとカリングをするための機構になります。で、この構築が意外と重く・・・かなり描画の重いオブジェクトが壁等で遮蔽されていてカリングされることでHZBがパフォーマンス向上に寄与している。とかでない場合はOFFにしちゃって良いかと思います。
Oculus ConnectでのNickのプレゼンテーションでShowdownデモの最適化でHZBはOFFにしたと説明していましたが「r.HZBOcclusion 0」とコンソールコマンドを打つ事でOFFにできます。「r.HZBOcclusion 1」とパフォーマンスを比べてみて、パフォーマンスの良い方法選択が良いかと思います。
iniファイルで初期設定が可能ですが詳しくは後半に載せてあります。
また、カリングの補助機能に関しては静的なスタティックメッシュに限定すると、シーンの歩き得る範囲を「Precomputed Visibility Volume」で囲ってから、「Settings」の「ワールド設定」から「Precomputed Visibility」の「Precompute Visibility」にチェックを入れることで「Visibility Cell Size」で区切った領域ごとの可視オブジェクトのリストを事前作成して、リストを元に描画するという機能がありますので、これで結構代替できると思います。
###3.2.1 Lights
次にLightsですが、動的なシャドウは描画のバッファを切り替えたり描画されたシーンのサンプリングを行ったりとかなり重い処理になります。
まずは、なるべく動的なシャドウイング・ライティングを減らすためにシーン上のライトの設定を見直します。エディタ右上(デフォルト位置)の「シーンアウトライナ」のテキスト入力欄にLightと打つとシーン上のライトがリストアップされますので、クリックするとアウトライナ下の「詳細」タブにライトの詳細プロパティが表示されます。ここで重要なのが「可動性」の「スタティック」「ステーショナリ」「ムーバブル」で、機能としては以下のようになっています。
- スタティック:静的なスタティックメッシュやジオメトリにはライト・シャドウを事前計算で焼付けるので、一番軽い。
- ステーショナリ:(ディスタンスフィールド)シャドウマップを事前計算で作成しておいて利用するので、動的にシャドウマップを計算するよりも軽い。ライトの明滅は可能だが、移動できない。
- ムーバブル:動的にシャドウマップを生成するので動的に動かしたりすることも可能だが、一番重い。
なので、パフォーマンス的には、全てスタティックで焼き付けてしまうのが理想です。
詳しくはライトの可動性に関するドキュメントページを参照ください。
https://docs.unrealengine.com/latest/JPN/Engine/Rendering/LightingAndShadows/LightMobility/index.html
また、ライトの可動性のパフォーマンス検証に関してはalweiさん(@aizen76)のUE4 ライトの可動性とパフォーマンスについてにて詳しく検証されています。
とはいえ・・・動的なライトを使いたい場合もあると思います。そこで検討していただきたいのがそのライトはシャドウを落とす必要があるのかどうか?という点です。例えば、太陽光の下でライターの火を点けました。手や顔の周りは少し明るくなって欲しいとは思いますが、シャドウは必要ないかもしれないですよね。そういう場合は「Cast Shadows」のチェックを外してシャドウの描画を抑制するとパフォーマンスが向上します。
###3.2.2 動的オブジェクトへのシャドウ
基本的に動的オブジェクトへのシャドウはオブジェクト毎にシャドウバッファを生成してシャドウが描画されます。バッファの切り替えやシーンのサンプリングを伴う重いものなので、この数はパフォーマンスへの影響がとても大きいです。「show shadowfrustums」というコンソールコマンドで、各動的オブジェクトへのシャドウバッファ生成に適用されている錐体が全て表示され、影響を与えているライト毎に錐体の色は違うものになっています。(ビュー上の「表示」「詳細設定」の「Shadow Frustums」にチェックを入れても確認できます)
で、パフォーマンス向上のためにはこの数を減らす事がカギになります。まず上記のライターの火のようなシャドウの必要のないものにまでシャドウが生成されていないか?ライトの影響範囲(シャドウの描画される範囲)は適切か?適切でないならライトの影響範囲(Radius)を小さくする、シャドウが必要ないならCast Shadowsのチェックを外す。
さらに「show shadowfrustums」の結果を見ていくと、同じような場所にシャドウの錐体が重なっている場所はないでしょうか?
キャラクターにアタッチして持たせているアイテムや帽子、一箇所にかたまっている複数の揺れる草アクターや何かは、シャドウをまとめてパフォーマンスを向上させる事ができます。
その方法ですが、まずはアクタを親子付けするために、シーンアウトライナ上で、子供にしたいアクタをドラッグして親にドロップします。親子付けができたら、親の「詳細」プロパティの「Lighting」項目中の「Light Attachments as Group」にチェックを入れます。これでシャドウバッファが親に統合され、パフォーマンスを向上させることができます。
###3.3 PostProcessing
最後に残る処理はポストプロセスになるかと思いますが、あまり有用でないものはパフォーマンス向上のために品質を下げたりOFFにしちゃいましょう。詳しくは後半のNickの設定をご参照ください。
###4. 描画解像度(r.ScreenPercentage / hmd sp)の調整
ここまでイロイロと書いてきましたが、以下のNickのプレゼンでも触れられてる「hmd sp 数字」で描画解像度を調整できます。この数字を100にすると、ターゲット解像度と同じ解像度で描画されるのですが、デフォルトでは130くらいになっています。なので、これを100にするだけでもかなりGPUの描画にかかる時間を減らす事ができますし、どうしてもフレームレートを出したいので解像度が落ちても良いということであれば80とか50とかにしてしまうのもひとつの手です。
#Oculus ConnectでのNick Whiting & Nick Donaldsonのプレゼンでの情報
9月にOculus社が開催したOculus ConnectというイベントでEpic本社のNick WhitingとNick Donaldsonが「Showdown」というデモの制作ノウハウのプレゼンテーションと来場者の方々に実際にShowdownデモを体験していただく機会があったのですが、そのプレゼンテーションから有用な情報もざっとシェアさせていただきます。
NVIDIAさんのイベントでCar Flipという名前で紹介されていたShowdownデモ
https://www.youtube.com/watch?v=1dVAYmbIdfU
Oculus ConnectでのNickのプレゼンテーション
https://www.youtube.com/watch?v=0oM6Xe7fT-8
ビデオは長いので・・・UE4のUnrealEngine.comサイト内の「Resources」ページに「Lessons from Integrating the Oculus Rift into UE4」という名前でスライドもありますので、時間がないけど詳しく知りたいという皆さんはスライドの方を見てみてください。
ざっと紹介すると
- レンズの歪みを補正するために、ポスト処理でディストーションかけているけど、歪ませる前の画像は実際のデバイスの解像度より少し高めに描画してから歪めるのが描画品質的にお勧めで、Epic内では130%から140%大きめの解像度で描画して使っている。その制御用のパラメータが「r.ScreenPercentage」でOculus動作時は「hmd sp 100」等を指定することで解像度を落とす事ができる。(パフォーマンスを稼ぐ事ができる)
- センサーから読んだ情報を画面に反映させるまで描画のバッファリング等がありレイテンシが酷いので、バッファリングを行わない等いろいろやったけど、Rutime 0.4.xのDirect Modeでかなり改善されるよ。
- それでもなおセンサー情報から映像までのレイテンシを減らす方法としてタイムワープが実装されているよ。描画されたピクセルと深度をさらに最新のセンサ情報に応じて移動(HMDの回転)させるんだけど、75fpsや90fps動作時の回転角が小さいと良い感じに適用できてる。
- でもこれらを有効利用するためには高いフレームレートを安定して保つ必要があって、高フレームレート動作のためにはトレードオフも必要になる。
- 動的ライトを極力抑えてライトマップだけにする、動的オブジェクトには間接光のキャッシュを適用、シャドウもシャドウバッファを使うのではなく丸影等フェイク表現も。
- それでもまだ最適化が必要だね。
- 「stat SceneRendering」してみたら、ドローコールが多かったね。「show Staticmeshes」してみたら、8ms以上使っている事がわかった。
- その他にも「stat Particles」したり「show Particles」や「show PostProcessing」「show Translucency」「show SkeletalMeshes」等してみると、簡単にそれぞれどのくらいの処理がかかっていたのか確認できる。
- CPUプロファイリングツールでRenderスレッドやGameスレッドのプロファイルも有用。
- GPUのプロファイリングも重要だね。HZBオクルージョンがいきなり重かったよ・・・。
スライド末のボーナスページに載っている.iniの描画設定はこちら
r.SeparateTranslucency=0
r.HZBOcclusion=0
r.FinishCurrentFrame=1
r.MotionBlurQuality=0
r.PostProcessAAQuality=3
r.BloomQuality=1
r.EyeAdaptationQuality=0
r.AmbientOcclusionLevels=0
r.SSR.Quality=1
r.DepthOfFieldQuality=0
r.SceneColorFormat=2
r.SSSSS=0
r.TranslucencyVolumeBlur=0
r.TranslucencyLightingVolumeDim=4
r.MaxAnisotropy=8
r.LensFlareQuality=0
r.SceneColorFringeQuality=0
r.FastBlurThreshold=0
showflag.decals=0
r.SSR.MaxRoughness=0.1
r.compileshadersfordevelopment=0
r.rhicmdbypass=0
r.TiledReflectionEnvironmentMinimumCount=10
#Oculus体験を向上させるためのノウハウ(酔いの低減、実験の為のビジュアライズ)
VRの普及のためにはVRの良い体験が重要です。中でも特に酔いがない快適な体験はとても重要です。
詳しくは10/25に開催されたOcufes開発者会で発表させていただきましたので、そちらを参照いただければと思います。
UE4のVehicleGameをDK2 75fps対応したが酔う!とのことなのでその軽減にチャレンジ@OcuFes開発者会
ざっくり説明すると、UE4のVehicleGameというラリーゲームのサンプルをOculus対応に改造したものを9月のCEDECの来場者の皆さんに体験していただいたものの、酔うという意見を多数いただいたので、その酔いの低減にチャレンジしてみたという内容です。
もともと、コースの起伏も激しくかなり揺れる車体なので、普通にやれば酔って当然のものなのですが、UE4の様々な機能を駆使して検証と改良を行いました。
その検証に使った車の挙動のブループリントコードを共有させていただきます。
UE4の4.5以上のVehicleGameサンプルに適用してください。
###設定方法
- VH_Buggy_DriversEye.uassetをVehicleGameフォルダ下のContent/Vehicles/VH_Buggy/Blueprint フォルダにコピーしてください。(例. C:\Users\YourUserName\Documents\Unreal Projects\VehicleGame\Content\Vehicles\VH_Buggy\Blueprint)
- エディタの「Settings」アイコンをクリックして「World Settings」を選択してください。
- Default Pawn ClassにVH_Buggy_DriversEyeを設定していください。
- ファイルメニューから「名前を付けて保存...」から新たなレベル名で保存してください。
- エディタの「プレイ」アイコンでプレイできます。
(Oculusを接続してスタンドアローンゲームでプレイしてAlt+EnterでOculusでもプレイ可能です)
###操作説明
- Vキー(もしくはゲームパッドXボタン)で、カメラの軌跡等ビジュアライズ
- Rキー(もしくはゲームパッドYボタン)で、ポジショントラッキングのリセットとカメラの切り替え
- もともとのサンプルのサードパーソン視点
- ドライバー位置近辺の車体にカメラをがっちり固定したような視点(とても酔いやすい、CEDEC2014公開版)
- ドライバーの頭にカメラを括りつけたような視点(ステディカメラ風の挙動、人間の眼の位置の動きに近づいてはいるはず(首や体をダンパーとして頭の重さで慣性移動)で注視点のブレを軽減できたが、それでも酔う)
- カメラのロールとピッチの回転は止め、水平位置は固定して、水平移動方向のみ回転(酔いにくい)
- 「Pause/Break」キーでポーズして「F8」キーでエディタ操作に戻ってビジュアライズされた軌跡を確認できます。
###遊んでみよう!
実はUE4はネットワーク対応機能も既に入っていて、もちろんこのVehicleGameも通信対戦で遊べます。PCとOculusを2セット用意して対戦してみよう!(Oculusは必ずしも2セットである必要はありません)
サーバ側:インストールフォルダ\UE4Editor.exe "ドキュメントフォルダ\Unreal Projects\VehicleGame\VehicleGame.uproject" DesertRallyRace?listen –game
クライアント側:インストールフォルダ\UE4Editor.exe "ドキュメントフォルダ\Unreal Projects\VehicleGame\VehicleGame.uproject" サーバIP –game
(ちなみに、サーバIPアドレスを127.0.0.1にすると同一PC上で動作させることも可能です)
※プロジェクト設定中のProject IDが同じでないと通信対戦に失敗するので注意。(Project IDが異なると、別プロジェクトのコンテンツと認識され対戦接続できないようになっています)
#UE4でOculus体験をもっと楽しむ
##LeapMotion
ちょうど本日、UE4のAdventカレンダーにToorsooさんがUE4でLeapMotionを使うためのUE4 Leapmotionでもっと遊んでみたという記事をポストされていまして、とても参考になりました。超オススメです!
##BlueprintのOculus用ノードを使ってさらに機能向上
UE4ドキュメントサイトに「Oculus Rift ベスト プラクティス」というページや、UE4 wikiサイト wiki.UnrealEngine.com 上に有志によるUE4からOculusを使うための様々な情報がありますが、ブループリントでも制御できるようになっていますので、いろいろ機能を追加してみてください。
例えば、「Reset Orientation and Position」というブループリントノードで体験者のポジションや向きをリセットする事が可能です。体験者の交代時にRキーが押されたらポジションをリセットする、等の設定はとても有用です。
web上でも様々な情報が見つけられると思いますが、michemmcさんのフォーラム投稿記事「VR Game Template」等もとても参考になります。
#みんなでOculusコンテンツの開発を楽しみましょう!
長文にお付き合い頂きましてありがとうございました!みんなでOculusコンテンツの開発楽しみましょう!
明日(12/5)はひでっくすさん(@hidex97)の「VRは筋肉!Oculus体験会向けモバイルデスクトップPCを作ってみた」の予定となります。
あれっ?予定・・・?既にあ・・・る?