UE4での描画パフォーマンス最適化について
最終更新日:2017年01月12日記事作成日:2016年06月14日
UE4でHTC Vive、Oculus Rift対応ソフトを開発する際にフレームレートを確保する方法についてまとめています。
更新履歴
(2017年1月12日)「VR向けのレンダリングオプション」を追加
(2016年8月28日)「レンダリング解像度を下げる」にAdaptive Viewport Scalingについて追記
(2016年8月23日)「レンダリング解像度を下げる」にr.ScreenPercentageを追加
(2016年6月17日)「Instanced Stereo Rendering」の項目を「Unreal Engine+Oculus Rift開発メモ」から移動
(2016年6月14日)「Unreal Engine+Oculus Rift開発メモ」からページ分離
はじめに
Unreal EngineでVRソフトを作る場合、そのままでは十分なフレームレートが出ないことが多いです。VRでは左右両画面を描画しなければならない上に、Unreal Engineは、遅延シェーディングや物理ベースレンダリング、各種ポストエフェクトなど、デフォルトでほぼ全部入りの非常に高品質な描画をするようになっているためです。
ですので、描画品質を下げて対策します。Unityがゼロから絵を出していくのに対して、Unreal Engineは上から落としていくようなものだと考えてください。
VR向けのレンダリングオプション
以下のオプションは描画全体に影響が出るため、プロジェクトの初期段階で使用するかどうかを決定しておいたほうがいいでしょう。
Instanced Stereo Rendering
各メッシュを左右両画面にまとめて描いてドローコールを半減させる最適化機能です。プロジェクト設定(Project Settings) > RenderingでVR > Instanced Stereoをオンにすると使用できます。設定を変えるとエディタの再起動を要求され、シェーダ全部の再コンパイルで非常に長い時間がかかるため、要注意です。
Forward Shading
プロジェクト設定(Project Settings) > Rendering > Forward Shadingをチェックするとフォワードレンダリングになります。一般にライトが少ない場合の負荷が低減するほか、アンチエイリアスにエッジが鮮明なMSAAが使用できるようになります。
レンダリング解像度を下げる
描画負荷を下げる最も手っ取り早い方法(あるいは最終手段)は、レンダリング解像度を下げることです。GPUの負荷は、概ね描画するピクセル数と、ピクセルあたりのシェーダの複雑さに比例するためです。
HTC Viveの場合
「r.ScreenPercentage {数値}」コンソールコマンドでピクセルの密度を変えられます。デフォルトは140です。下げるほど画面がぼけてしまいますが、描画が軽くなります。
HTC Viveでは下記のhmd pdコマンドは効かないので注意してください。
Oculus Riftの場合
「hmd pd {数値}」コンソールコマンドでピクセルの密度を下げられます。デフォルトは1.0です。hmd pd 0.8、0.9あたりは、視覚的にあまり違いが分からないわりには効果が大きいです。
「hmd pd」などの設定の変更は、Saved/Config/*/Engine.iniに保存されます。Engine.iniは以下のフォルダに配置されています。
- プロジェクトフォルダ
- Shippingビルドの場合:ユーザーディレクトリ/AppData/Local/{プロジェクト名}
- Developmentビルドの場合:.exeのフォルダの{プロジェクト名}
hmd pdコマンドの数値はPixelDensityという項目に格納されています。初期化するには項目を削除します。
レンダリング解像度は描画品質と負荷をリニアに変えられますので、ゲーム中の設定メニューで変更できるようにしておくと、いろんなスペックのPCに対応できて便利かもしれません。
また、GPU負荷が85%を超えると自動的にレンダリング解像度を下げてフレームレートを維持しようとするAdaptive Viewport Scalingという機能が用意されています(Oculus Riftのみ対応)。「hmd pdadaptive on」コンソールコマンドで有効にできます。「hmd pdmax {数値}」「hmd pdmin {数値}」で最大・最小のピクセル密度を指定できます。
GPUビジュアライザーを使う
最適化をするには、具体的に何にどれくらい描画負荷がかかっているのかを調べる必要があります。GPUビジュアライザーでフレームの描画にかかったGPUの処理時間をキャプチャーして詳しく解析できます。他にも処理時間を表示するstat系のコンソールコマンドがありますが、あまりあてにならないので、まずこちらで調べたほうがいいと思います。
GPUビジュアライザーは実行中またはエディタ画面でCtrl+Shift+,(カンマ)を押すと開きます。VRプレビューに呼び出した場合は、プレビューを終了しないとウィンドウが見えないかもしれません。また、エディタ上で起動するときはビューポートのRealtimeが有効になっている必要があります。
表示されたグラフで時間のかかっている項目を調べて、Project Settings > Renderingやシーンに配置されているPost Process Volume、コンソールコマンドでエフェクトを切ったり、品質を落として最適化します。まずフレームレートを出せるようになってから、見た目と相談して落としどころを探していくといいと思います。
とにかく処理をカットするという観点から主な項目を紹介します。
BasePass
ベースとなるポリゴンの描画です。ポリゴン数やアクタの数などを減らして負荷を削減します。
Lights
ライトおよびシャドウです。下の項目を参照してください。
ClearTranslucentVolumeLighting
Lit Translucencyの処理です。「r.TranslucentLightingVolume 0」でカットできます。
BokehDOFRecombine
Separate Translucencyの処理です。Project Settings > RenderingでSeparate Translucencyを無効にするとカットできます。Separate Translucencyについては以下が詳しいです。
RenderVelocities
Motion Blurを切って、アンチエイリアスをTemporalAA以外にするとカットできます。
LightCompositionTasks_PreLighting
スクリーンスペース・アンビエントオクルージョンの処理です。画面全体に遮蔽による陰をつけます。Project Settings > RenderingでAmbient Occlusionを切るか、Post Process VolumeのAmbient Occlusion > Intensityを0にすると全カットできます。
完全に切ってしまうのはちょっと、というときは、Post Process VolumeのAmbient Occlusion > Qualityで負荷を下げられます。デフォルトの50から0にすると負荷が数分の1になります(ただしディザノイズが発生します)。他のパラメータは(Intensityを0にする以外)負荷に影響しないようです。
SSRTemporalAA
Screen Space Reflectionsの処理です。Post Process VolumeでScreen Space Reflectionsをゼロにするとカットできます。
Atomosphere
大気フォグの処理です。レベル上のAtmospheric Fogを取り除くとカットできます。
PostProcessing > Downsample
Bloomを切るとカットできます。
PostProcessEyeAdaptation
自動露出の処理です。Showdownデモでは「r.EyeAdaptationQuality 0」で無効化しているようです。
ReflectionEnvironmentGather
リフレクションのキャプチャの処理です。レベル上のSphereReflectionCaptureおよびBoxReflectionCaptureを取り除くとカットできます。
DistanceFieldLighting
MovableなSky Lightのディスタンスフィールド・アンビエントオクルージョンの処理です。
BuildHZB
Hierarchical Z-Bufferの処理です。階層化したZバッファを作成して高速なオクルージョンカリングを行うそうですが、逆に遅くなる場合も多いようです。「r.HZBOcclusion 0」コマンドでカットできます。HZBについては下記ブログが詳しいです。
PostProcessSelectionOutlineBuffer, CompositeEditorPrimitives
エディタからGPUビジュアライザーを呼び出したときに発生します。エディタの表示関連ですので無視して構いません。
SlateUI
FPSなどが表示されていると負荷がかかるようです。
その他の最適化
負荷の軽いライトを使う/ライトマップを焼く
GPUビジュアライザーを見ると、Lightsの項目にかなり時間がかかっていることがあります。ライティングは重い処理です。動的なライトを減らしたり、シャドウの設定を追い込んで負荷を下げます。
特にライトをスタティックにしてライトマップを焼くと、負荷がごっそり削減されます。ライトマップを焼くのはかなり時間と労力がかかり、ノウハウも必要なのですが、習得してみる価値はあると思います(習得中……)。
Movableのライトでは、カスケードシャドウの数値の影響が大きいです(Cascaded Shadow MapsのNum Dynamic Shadow Cascade)。この回数ぶんシャドウマップへのメッシュの描画が発生し、それだけ負荷が増えます。
シェーダの複雑さを調べる
ビューポートの左上の ライティング(Lit) > Optimization Viewmodes > シェーダー複雑度(Shader Complexity) を選択すると、画面のピクセルごとのシェーダ負荷を視覚化できます。赤く表示されているところは複雑なシェーダが使用されていますので、該当するマテリアルを開いてインストラクション数を減らします。
表示を変更してみる/統計情報を見る
ビューポートの 表示(Show) から表示設定を変えたり、アウトライナ(Outliner) で表示・非表示を切り替えて負荷の変化を見てみるのも有効だと思います。なお、アウトライナは眼のアイコンをドラッグでなぞると一気に表示を切り替えられます。
また、同じくビューポート左上のプルダウンメニューの 統計データ(Stat) > Advanced から表示量などの統計情報を確認できますので、参考にするといいでしょう。
VRと相性の悪いエフェクトについて
立体視では不自然に見えてしまうエフェクトがあります。とりあえずレンズフレアは切ったほうがいいようです。Project Settings > RenderingでLens Flaresをオフにします。SSRも反射がおかしくなるのでPost Process Volumeなどで無効化して、Reflection Probeなどで代替します。
また、アンチエイリアスについて、デフォルトのTemporalAAは動きに弱いので、FXAAに変更したほうがいいかもしれません。または、Forward Shadingを有効にしてMSAAを使用します。
右画面のBloomの左端が欠ける問題があります 。「r.BloomQuality 2」などで軽減できるようです。
VRモードではディスタンスフィールド・アンビエントオクルージョンが無効化されます(「VRモードにするとなんだか画面が明るい」と、しばらく原因に気づかなかったことがありました)。
参考リンク
Epic Games Japanのシモダさんが詳細な最適化ガイドを執筆されています。
おかずさんがエフェクトをほぼゼロまで削る非常に実践的な解説を書かれています。