韓国がモバイルゲーム開発においてのUE4採用の最前線になっているためか、Unreal Summitはモバイル向けの話題が多めです。その中から今回はEpic Games KoreaのDmitriy Dyominさんによる、ソフトウェアオクルージョンカリングのセッションを読んでみました。モバイル版のオクルージョンカリングはPC版とは異なる手法で実装されており、このテーマ1つでなかなかの分量です。題名にモバイルとありますが、PC版の実装にも触れています。
残念ながら動画の音質が非常に悪く字幕も生成されていないので、以下のスライドをおすすめします。
https://replay.unrealsummit.co.kr/data2018/usm2018_44.pdf
要約
- モバイル版のためにSoftware occlusion culling実装(今回の主題)
- PC版やコンソール版ではHardware occlusion queries、HiZ occlusionというGPUを活用した手法を使う
- モバイル版(OpenGL ES)でもHiZ occlusionを実装したが採用せず、エンジンにも組み込まなかった
- iOSではSoftware occlusion cullingはうまくいかず、Hardware occlusion queriesを使うことに
- UE4.20からモバイルでSoftware occlusion cullingとHardware occlusion queriesが使えるように
要求仕様
- PCやコンソールとのクロスプラットフォーム対戦可能
- モバイルのスペックが足りないからと言って視距離を制限するなどゲームプレイ上不利になる事はできない
- terrain以外は破壊可能なので、precomputed visibilityはつかえない
Hardware occlusion queries
- OpenGL ES3以降
- bounding boxを頂点シェーダのみ、ピクセルシェーダ抜きで描画してクエリ
- PCやコンソールではdepth pre-passの後にクエリを投げ、1フレーム待機で結果を得られる
- モバイルではdepth pre-passがない、最低2フレームかかるがFortniteでは3フレーム待つ
- 平均50%くらいドローコールを削れる
- UE4.20で、r.AllowOcclusionQueries=1 がモバイルでサポート
Hardware occlusion queriesの問題点
- 結果を得るまで3フレームの遅延
- クエリ1回当たり追加でドローコール1回。FORTNITEは150ドローコール増加。
- Adrenoは512クエリの制限
Software occlusion cullingを実装してみる
- メインメモリにデプスバッファを作る
- SIMDで頂点変換
- CPUでラスタライズ、クリッピング、カリング
- 重い! ~1100 オブジェクト、~60万ポリゴン
Software occlusion cullingの高速化
- 良いoccluderをアセット単位でアーティストが手動で選別(悪いoccluderとされたらバッファに描画しない)
- 描画に使うLODもアーティストが指定
- 良いoccluderもそのフレームでoccluderとして使う価値があるかはヒューリスティックに判断(カメラから近い程良い)
- 1フレームあたり200個ぐらいまでが適切
Occludeeの最適化
- 二次元Bounding Boxでまず判定
- 三次元Bounding Boxを三角形に分解してデプステスト
デプスバッファの最適化
- デプスはいらない、1ピクセル1ビットで十分、以下occlusion bufferと呼ぶ
- occluderとoccludeeの三角形を全てデプスでソートして手前から処理
- occluderは三頂点の最も奥のZを採用
- occludeeは三頂点の最も手前のZを採用
occlusion bufferのレイアウト
- 384x256ピクセル
- 6x4の 'bin'という単位に分ける。binは64x64ピクセル
- bin1つは uint64 Bin[64]
- 描画とテストはビット演算
- binごとに別スレッドで処理させることもできる
結果
- 一万個の三角形を 5-8msで処理(Galaxy S8)
- 30-50%のオブジェクトをカリング
- 1フレームのレイテンシ
Software occlusion cullingについて
- UE4.20で、r.Mobile.AllowSoftwareOcclusion=1 で使える
- iOSでは採用せず。オープンワールドではうまく機能しなかったため、3フレームのレイテンシを我慢してHardware occlusion cullingを採用
インテルのソフトウェアオクルージョンの紹介
HiZ occlusion - PC版の実装
- デプスバッファのMip Chainを作る
- 複数のOccludeeのBBoxをテクスチャに書き込んでピクセルシェーダから参照
- Render Targetの1ピクセルは1Occludeeに対応していて、隠蔽されたかどうかが書き込まれる
- 次のフレームで結果を利用
- occludeeが増えてもコストはほぼ変わらないメリット
HiZ occlusion - OpenGL ESの実装
- PC版の実装のようにRender TargetをCPUから参照しようとするとすごく待たされた
- ピクセルシェーダの代わりに頂点シェーダ+Transform Feedbackで処理した
- 3フレームレイテンシで結果を取れた
- Occlusion queryのほうが結果が良かった
- 不採用、エンジンにも反映せず
モバイルGPUのオクルージョンクエリは待たされる等の制限があるとのことで、代わりにCPUでラスタライザを実装、更にそれを実用レベルにしてしまうのは驚きでした。
Galaxy S8基準でソフトウェアカリングに5~8msかかるとはいえ、バックグラウンドスレッドで動くのでゲームスレッドやレンダリングスレッドの仕事を増やしているわけではないと想像します。
余談ですが、Samsungは仕向地などによって同じブランドでもSoCが違うことがあります。Galaxy S8の場合、日本やアメリカはSnapdragonですが、韓国ではExynos+Maliの構成です。Snapdragonのほうがゲーム向けで、Exynosは相対的にグラフィック性能が落ちる代わりにCPU性能は高いです。スライド上のGalaxy S8は韓国モデルと思われますが、もしかするとゲームでCPUが遊びがちなExynos向けの実装を試みた結果だったかもしれません。