DepthPrepass有効時のCoplanar PolygonによるGPU負荷増大 [UE][Rendering]

DepthPrepassレンダリングに関連して,
モデルやレベルの作りによってGPU負荷が増大してしまう特殊な状況について説明します.

問題

同一平面で重なり合うポリゴン(Coplanar Polygon)は, 重なりの数だけBasePass PixelShaderが実行される可能性があります.
これにより本来DepthPrepass環境で除去される不要なBasePass負荷が追加で発生します.

同一平面で重なり合うポリゴン を Coplanar Polygon と呼んでいます.
Lamina Faces や Z-Fighting状態のポリゴン というような表現もあると思います.
もっと良い呼び名があれば教えてください!


以下のサンプルシーンはOpaqueで適当ワールドノイズマテリアルのCubeをいくつか配置した状態です.
よくOverDraw負荷が問題となる半透明が無いシーンなので安心と思いきや, 表示モードを「シェーダ複雑度」へ切り替えてみると.

サンプルシーン

何故か高負荷を示す真っ白な部分があります.

RenderDocでキャプチャして 「Quad Over Draw (Pass)」でOverDrawを確認します.

RenderDoc Quad Over Draw (Pass)

RenderDoc上でも確かに右側の配置でBasePassのOverDrawが発生しているようです.

BasePassではDeferredの場合はGBuffer書き込み, Forwardであれば複雑なLighting計算が実行されるため,本来実行されないはずのOpaqueでのBasePass OverDrawはGPU負荷に大きな影響を与えます.

原因

この問題の原因は深度が完全に一致するポリゴンが複数重なっている点と, DepthPrepass有りBasePassの仕組みの関係によるものです.

まずシーンの配置ですが, 左側の配置と同じ3つのCubeをポリゴンが重なるように配置しています *1.

このような状況では, DepthPrepass有効時のBasePassは重なり合ったポリゴンそれぞれについて全て実行されてしまい, 高負荷なBasePassが何度も実行されることによりGPU負荷を増大させます.

BasePassが複数回実行される理由

本来のDepthPrepass手法は, DepthPreapssで先に生成したDepthBufferを頼りに, 各Meshの可視ピクセルのマテリアルBasePass PixelShaderだけを最小限実行することで高速化するためのものです.
例として背景, 円柱, 板で構成されたシーンのDepthPrepass有りBasePassの挙動を以下に示します.
右側図の緑色部分がDepthTestを通過してBasePassのPixelShaderが実行されたピクセルになります.

  1. DepthPrepassでDepthBufferが完成
  2. 円柱モデルBasePass描画
  3. 背景モデルBasePass描画
  4. 板モデルBasePass描画

各モデルのBasePassが, 最終的に画面に見えている部分でだけ働いているのがわかると思います.
このようにBasePassが無駄に実行されないようにして高速化するというのがDepthPrepassの目的となります.

これを実現するためにBasePassは

DepthWrite=OFF 且つ DepthTest=GreaterEqual

という設定をされます *2.

指摘がありましたので追記-> Maskedを含めたマテリアルをDepthPrePassを利用してEarlyZ有効で効率的に描画するために Equal なDepthTestで描画する場合があります. 本件のシーンではOpaqueを対象とし且つRenderDocキャプチャ等も確認したところGreaterEqualであったためこのように記述しています(UE5.3).

 

この設定によって, 各モデルのBasePass描画では

DepthPrepassで確定した深度値に対して
同じかそれより近い場合にのみ描画する

という挙動をすることになります.

この 同じかそれより近い という点と, 深度が完全に一致してしまう Coplanar Polygon の関係によって今回のような問題が起きています.

終わり

Opaqueであるにも関わらずOverDrawによってBasePass負荷を増加させるCoplanar Polygonと, 関連したDepthprepassの簡単な説明でした.
この問題はときに異常な高負荷を発生させ, 更に原因がわかりにくいという厄介さを持っています (UE5ではシェーダ複雑度で確認できますが).
またMaskedでも同様に問題が起きます.

モデル制作やレベル配置をする際には多少気をつけてもらえると最適化担当の人間に平穏がもたらされます.

この記事が2022最後の記事となります, 良いお年を.


おまけ


最後に問題のCoplanar Polygon状況でのRenderDocキャプチャを貼っておきます.
問題のない配置とCoplanar Polygon配置.
右図の緑がDepthTest通過ピクセル表示.
OverDrawが発生している重なり部分でどのDrawでもDepthTest通過してしまっているのがわかります.

参考文献

*1:1モデル内のポリゴン同士でも, レベルに配置した別モデルのポリゴン同士でも関係なくこの問題は発生します.

*2:GreaterEqualなのはReverseZ環境でのことで, StandardZの場合はLessEqualです.