今回は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レンダリングのハード(モバイル機器、AndroidやiOS系)では描画しない 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-) |
うひ~、結構長かった。
読むのも大変でしょうけど、気になってる人は是非。
あと、これは公開しちゃダメ!って部分がありましたら連絡ください。
大丈夫だと思いますが…