UE4の描画パスについて Ver 4.6.1

今回はUE4の描画パスについて簡単に調べた結果をメモっておく感覚で書いていきます。

タイトルにバージョン番号が入っているのはバージョンによって変更される可能性が高いためです。

また、今回はソースコードを軽く読んでわかった範囲でしか書いていません。

間違いがありましたら突っ込んでいただけると大変ありがたいので、よろしくお願いします。

描画パスというのはいわゆる描画の順番です。

例えば、モデルが何も描画されていない、画面がクリアされているだけの状態ではポストプロセスを実行しても意味がありません。

半透明オブジェクトはその性質上、不透明オブジェクトの後に描かれなければなりません。

そのような順番を定義しているのが描画パスです。

UE4ではこの描画パスの定義は "Engine\Source\Runtime\Renderer\Private\DeferredShadingRenderer.cpp" の "FDeferredShadingSceneRenderer::Render()" メソッドが担っているようです。

以下はこのメソッドから呼ばれている関数群が何をやっているのかを順番に解説していったものです。

なお、ソースコードは掲載しませんが(規約に違反するし)、関数名と行番号は掲載しておきます。

自分でも調べてみたい方は参考にしてみてください。

では、続きからどうぞ。

Engine\Source\Runtime\Renderer\Private\DeferredShadingRenderer.cpp (660)

FDeferredShadingSceneRenderer::Render() による描画パス

グローバルなシステムテクスチャの初期化DeferredShadingRenderer.cpp (677)

GSystemTextures.InitializeTextures()

必要なレンダーターゲットを確保

必要となるターゲットの総量の内、確保可能な最大数を確保している?

DeferredShadingRenderer.cpp (680)

GSceneRenderTargets.Allocate()

各Viewportの初期化

Viewportで表示されるオブジェクトのセットアップ、動的シャドウを使う場合はそこに表示されるオブジェクトの選定、半透明オブジェクトのソートを行う

DeferredShadingRenderer.cpp (683)

InitViews()

FXSystemの描画前処理

GPUパーティクルのシミュレートを行っている

DeferredShadingRenderer.cpp (758)

FXSystem->PreRender()

Z Pre-Pass が有効な場合に行うEarly Z描画

Tileレンダリングのハード(モバイル機器、AndroidiOS系)では描画しない

PCやPS4の場合は深度バッファとHiZが生成されるので、後の描画が高速になる?

DeferredShadingRenderer.cpp (768)

RenderPrePass()

GBufferを確保DeferredShadingRenderer.cpp (774)

GSceneRenderTargets.AllocGBufferTargets()

Light Propergation VolumeのクリアDeferredShadingRenderer.cpp (779)

ClearLPVs()

DBufferを使用する場合のDeferred Decalの描画

DBufferとDeferred Decalについてはこちらを参照

DeferredShadingRenderer.cpp (796)

GCompositionLighting.ProcessBeforeBasePass()

必要ならGBufferのクリア

ワイヤーフレーム描画の場合はカラーバッファもクリア

ゲームリリース時にはGBufferや画面のクリアを行わないゲームが結構ある

DeferredShadingRenderer.cpp (805)

SetAndClearViewGBuffer()

DeferredShadingRenderer.cpp (816)

RHICmdList.Clear()

不透明オブジェクトの描画

MaskedかDefaultか、LightMapありかなしか、などで割と細かく分類されているものをそれぞれの分類順で描画

DeferredShadingRenderer.cpp (828)

RenderBasePass()

GBufferの描画されていない部分をクリア

GBufferのクリアを事前に行っているなら不要のはず

DeferredShadingRenderer.cpp (851)

ClearGBufferAtMaxZ()

カスタムデプスの描画

カスタムデプスについてはこちらを参照

DeferredShadingRenderer.cpp (860)

RenderCustomDepthPass()

ここで再びGPUパーティクルのシミュレート

ここでは深度バッファを利用した衝突判定を行うパーティクルの処理をしているっぽい

加えて、GPUパーティクルのソートも行う

DeferredShadingRenderer.cpp (865)

Scene->FXSystem->PostRenderOpaque()

SceneDepthTextureの半解像度(縦横それぞれ1/2の1/4解像度)バッファを作成DeferredShadingRenderer.cpp (875)

UpdateDownsampledDepthSurface()

Occlusionテストを行う

HZBの構築、Submitを行う

HZBについては@tempkinderさんのこちらの記事を参照

DeferredShadingRenderer.cpp (881)

BeginOcclusionTests()

ライティング開始

ちょっと複雑なので少し詳しく書いておく

DeferredShadingRenderer.cpp (890)
DBufferを用いないDeferred Decalの描画CompositionLighting.cpp (293)

AddDeferredDecalsBeforeLighting()

スクリーン空間のAmbient Occlusionの描画CompositionLighting.cpp (300)

AddPostProcessingAmbientOcclusion()

ポストプロセスのAmbient Cubemapの描画CompositionLighting.cpp (305)

AddPostProcessingAmbientCubemap()

ここまでが一連の処理DeferredShadingRenderer.cpp (904)

GCompositionLighting.ProcessAfterBasePass()

半透明用のVolumeライトバッファをクリアDeferredShadingRenderer.cpp (908)

ClearTranslucentVolumeLighting()

ここからメインのライティング

描画すべきライトを集めてソートする

シャドウを落とさない、ライトファンクションを利用していないものは(可能なら)Tile-Basedで描画

Tile-Basedが使用できないなら普通に描画

Tile-Based Deferred Renderingについては手前味噌ですがこちらを参照

LightRendering.cpp (312-348)

LightRendering.cpp (423)

RenderTiledDeferredLighting()

LightRendering.cpp (429)

RenderSimpleLightsStandardDeferred()

シャドウも落とさないしライトファンクションも利用していないが、TBDRで描画できなかったライトを描画

StandardDeferredライトと呼ばれているらしい

LightRendering.cpp (445)

RenderLight()

半透明用のVolumeライトが有効なら各ライトをVolumeライトにインジェクション

3Dテクスチャにライトの効果を描画していく作業

LightRendering.cpp (455)

InjectTranslucentVolumeLightingArray()

LightRendering.cpp (461)

InjectSimpleTranslucentVolumeLightingArray()

シャドウを落とす、ライトファンクションを用いるライトは各ライトごとに処理するLightRendering.cpp (468-552)
まずはシャドウを落とす場合にシャドウマップの描画

半透明のシャドウマップもここで描画する

半透明はたしかFourier Opacity Mapsだったと記憶している

LightRendering.cpp (495)

RenderTranslucentProjectedShadows()

LightRendering.cpp (497)

RenderProjectedShadows()

LPVを使う場合はReflective Shadow Mapsの描画LightRendering.cpp (508)

RenderReflectiveShadowMaps()

ライトファンクションの描画

Shadow Indicator(よくわからん)の描画

LightRendering.cpp (515)

RenderLightFunction()

LightRendering.cpp (522)

RenderPreviewShadowsIndicator()

Light Attenuation Bufferのリゾル

ライトの減衰情報を一旦別バッファに描画している?

LightRendering.cpp (534)

GSceneRenderTargets.FinishRenderingLightAttenuation()

半透明用のVolumeライトへのインジェクションLightRendering.cpp (541)

InjectTranslucentVolumeLighting()

ライト描画

シャドウを落とす、ライトファンクションを用いるライトの処理はここまで

LightRendering.cpp (550)

RenderLight()

各ライトのLPVに対するインジェクション

メインのライティング処理はここまで

LightRendering.cpp (561-593)

Lpv->InjectLightDirect()

Ambient Cubemapの半透明用VolumeライトへのインジェクションDeferredShadingRenderer.cpp (916)

InjectAmbientCubemapTranslucentVolumeLighting()

半透明用VolumeライトのフィルタリングDeferredShadingRenderer.cpp (919)

FilterTranslucentVolumeLighting()

LPVの伝達処理

なお、921行目のコメントはコピペミスで”LPVバッファをクリア”とか書かれてるw

DeferredShadingRenderer.cpp (924)

PropagateLPVs()

動的なSkyLightの描画DeferredShadingRenderer.cpp (928)

RenderDynamicSkyLighting()

Deferred Reflectionの描画

スクリーンスペースではなく、キャプチャしたReflectionの描画

DeferredShadingRenderer.cpp (931)

RenderDeferredReflections()

LPVによるGI描画CompositionLighting.cpp (344)

AddPostProcessingLpvIndirect()

スクリーン空間サブサーフェイススキャッタリング(SSSSS)のポストプロセス処理CompositionLighting.cpp (347-376)
ライトシャフトが有効ならライトシャフトのOcclusionを描画DeferredShadingRenderer.cpp (953)

RenderLightShaftOcclusion()

大気フォグの描画DeferredShadingRenderer.cpp (977)

RenderAtmosphere()

フォグの描画

こっちはハイトフォグかな?

DeferredShadingRenderer.cpp (986)

RenderFog()

半透明オブジェクトの描画

Separate Translucencyのものもここで描画する

DeferredShadingRenderer.cpp (1000)

RenderTranslucency()

屈折によるDistortionの処理DeferredShadingRenderer.cpp (1008)

RenderDistortion()

ライトシャフトによるブルームの処理DeferredShadingRenderer.cpp (1013)

RenderLightShaftBloom()

Distance Field AOの処理

現状では複数Viewportに対応してないっぽい

スプリットスクリーンのゲームでは使用できない?

DeferredShadingRenderer.cpp (1019)

RenderDistanceFieldAOSurfaceCache()

メッシュのDistance FieldのVisualize

処理結果を見るだけかな?

DeferredShadingRenderer.cpp (1024)

RenderMeshDistanceFieldVisualization()

速度ブラーのため、移動オブジェクトの速度を描画DeferredShadingRenderer.cpp (1034)

RenderVelocities()

ここから最後のポストプロセス

これまた複雑かつ長い

DeferredShadingRenderer.cpp (1047)

GPostProcessing.Process()

BeforeTranslucency設定のポストプロセスマテリアルを描画PostProcessing.cpp (878)

AddPostProcessMaterial()

Depth of Fieldの処理

ガウスブラーによるDOFの処理の後、ボケ処理(指定した絞り形状のテクスチャを利用した描画)を行っている

Separate Translucentバッファはこの段階でマージされてるっぽい

PostProcessing.cpp (888)

AddPostProcessDepthOfFieldGaussian()

PostProcessing.cpp (898)

AddPostProcessDepthOfFieldBokeh()

PostProcessing.cpp (905)

FRCPassPostProcessBokehDOFRecombine

(ボケが有効でない場合はこちら)

BeforeTonemapping設定のポストプロセスマテリアルを描画PostProcessing.cpp (913)

AddPostProcessMaterial()

TemporalAAを使用する場合はここで描画

FXAAの場合は後に行う

PostProcessing.cpp (921)

AddTemporalAA()

PostProcessing.cpp (928)

AddTemporalAA()

(速度バッファを使用しない場合はこちら)

モーションブラーの処理

セットアップ、解像度のダウンサンプリング、ガウスブラー、モーションブラー描画、コンバインの処理が行われる

PostProcessing.cpp (932-994)

FRCPassPostProcessMotionBlurSetup

FRCPassPostProcessDownsample

RenderGaussianBlur()

FRCPassPostProcessMotionBlur

FRCPassPostProcessMotionBlurRecombine

SceneColorのダウンサンプリングPostProcessing.cpp (1000)

FRCPassPostProcessDownsample

ヒストグラムの描画PostProcessing.cpp (1006-1040)

FRCPassPostProcessHistogram

FRCPassPostProcessHistogramReduce

Eye Adaptationの描画

ヒストグラムはここで必要になる

PostProcessing.cpp (1046)

AddPostProcessEyeAdaptation()

ブルーム描画PostProcessing.cpp (1057)

AddBloom()

PostProcessing.cpp (1060-1148)

(モバイルの場合はこちら)

トーンマッピング

ReplacingTonemapper設定のポストプロセスマテリアルを1つだけ描画するが、

そのマテリアルが存在しなければデフォルトのトーンマッピングが行われる

PostProcessing.cpp (1155)

AddSinglePostProcessMaterial()

PostProcessing.cpp (1171)

AddTonemapper()

(デフォルトのトーンマッピング)

FXAAが有効ならここで処理PostProcessing.cpp (1177)

AddPostProcessAA()

いくつかのエディタ用の描画(選択したアウトラインとか)が行われる

その後、AfterTonemapping設定のポストプロセスマテリアルを描画

PostProcessing.cpp (1244)

AddPostProcessMaterial()

サブサーフェイスとGBufferのVisualize

デバッグ用かな

PostProcessing.cpp (1246-1254)
HMD用のポストプロセス

OculusとかMorpheusとか

PostProcessing.cpp (1256-1277)

FRCPassPostProcessHMD

FRCPassPostProcessMorpheus

あとはデバッグ系と高解像度スクリーンショットの機能など

その後は後処理して終了!

おつかれさまでした!

PostProcessing.cpp (1279-)

うひ~、結構長かった。

読むのも大変でしょうけど、気になってる人は是非。

あと、これは公開しちゃダメ!って部分がありましたら連絡ください。

大丈夫だと思いますが…