メモ: UE4のRenderingの呼ばれ方

ただの私的メモ。

だが、UE4のエンジン側の描画周りのソース見始める人の取っ掛かりとして役に立つかもしれないので。
UE4のRendering(not Shader or UserInterface)に関するざっくりとした流れ。
たぶんVisualStudioでソース追っかけながら見ないと何書いてるかさっぱりだと。

MainからRenderへのコマンド発行

Main側からのRenderingコマンドの発行は、かなりざっくりとした感じで、以下のような流れ。
BeginRenderingViewFamily()内で、Globalのフレームカウンタがインクリメントされる。
加えて、FSceneRendererのインスタンスが毎フレーム作られ、RenderCommandに引き渡される。

UE4_render_main_overview

FSceneRendererについて

Main側で、FSceneRenderer::CreateSceneRendererを呼び出し、RenderThread側で使用するSceneRendererのインスタンスを毎フレーム作る。Renderingが終われば、SceneRendererはRenderThread側で破棄される。
FSceneRendererの初期化には、FSceneViewFamily,FHitProxyConsumerを渡す。
FSceneViewFamilyは、FSceneRendererのメンバーにコピーする。FSceneViewFamilyからSceneのPointerを取得する。
FSceneViewFamilyメンバーのViews(FSceneView型)をViews(FViewInfo型)に変換し格納する。
FViewInfoはFSceneViewを継承している。FViewInfoはSceneRendererが使うView依存のレンダリング情報を格納するためのものと思われる。
FHitProxyConsumerはよく分からん。

RenderViewFamily_RenderThread()について

 
RenderCommandを通じて、RenderThread側にこのルーチンの実行を依頼する。したがって、このルーチンの実行は、RenderThreadで行われる。
Main側で生成され、引数で受け取ったSceneRendererに基きRenderingを実行する関数。

実質的なレンダリングは2択で、
SceneRenderer->RenderHitProxies();
もしくは
SceneRenderer->Render();
のどちらかを行う。通常のRenderingはRender()になる。

Editor上では、FDeferredShadingSceneRenderer::Render()が呼ばれる。
UE4には、FSceneRendererを継承した、
FForwardShadingSceneRenderer

FDeferredShadingSceneRenderer
が実装されている。通常Editor上では、DeferredRendererが使われる。

引数に
-featureleveles2
をつけると、Rendering時に生成されるFSceneRendererをForwardShadingSceneRendererに切り替えることが出来る。しかし、正しいと思える動作が確認できなかった。(ver4.1)

FForwardShadingSceneRenderer::Render()について

現状Editor上での使用は難しいFForwardShadingSceneRendererだが、その仕組みの単純さから、取っ掛かりに向いていると思われる。
結局Renderingの本体はFForwardShadingSceneRenderer::RenderForwardShadingBasePass()にある。
RenderTargetの設定とClearをした後に、各ViewにおいてStaticDrawListとDynamicPrimitiveの描画を繰り返す。ちなみにViewはいわゆるViewportに相当し、ViewFamilyは(最終結果の)RenderTargetに相当すると思われる。
FForwardShadingSceneRendererでは、
StaticMesh(Default)->DynamicMesh->StaticMesh(Masked)
の順番で描画される模様。

StaticMeshのDraw

StaticMeshのDrawListは、DrawingPolicyに応じて下記4種類に分かれており、加えてDynamicPrimitiveの前後で描画するために、計8種のDrawListがある
LowQualityLightMap
DistantFieldShadowMapLightMap
DirectionalLightAndSHIndirect
NoLightMap
FowardRenderingの場合は、実質LightMapPolicyによってこれ等が分かれている。

DrawingPolicyは、シェーダーの大分類に相当するものと思われる。おそらく、各DrawingPolicy内で、共有するTextureやUniformがあるものと思われる。DrawingPolicy内でのShader切り替えの際は、これら共有するリソースやステートは、既に設定されている前提の下、最小限のステート変更でShaderを切り替えるものと思われる。

FScene::GetForwardShadingBasePassDrawListというMethodで、LightMapPolicyTypeに応じてFSceneに格納されているDrawListのメンバーを取得する仕組みがある。
DrawListには、TStaticMeshDrawList<DrawingPolicyType>::AddMesh()を通じてMeshが登録される。Meshの描画時に必要になるDrawingPolicyの実体はAddMeshを通じて受け取る。
DrawingPolicyのインスタンスには、いわゆるMaterial関連のパラメータが格納され、同一のMaterialを用いたMeshはDrawingPolicyLinkによってリンクされてDrawListに格納される。

描画は、TStaticMeshDrawList<DrawingPolicyType>::DrawVisible系の呼び出しより、DrawingPolicyLinkごとにDrawElementが呼び出される。
DrawingPolicyLink->DrawingPolicy.DrawSharedがDrawingPolicyLinkごとに一度呼び出され、
各Elementの、BatchElementMaskごとに、
DrawingPolicyLink->DrawingPolicy.SetMeshRenderState
DrawingPolicyLink->DrawingPolicy.DrawMesh
が呼び出される。
BatchElementMaskはElement.Mesh->Elementが複数存在する場合のVisiblity制御。
DrawingPolicyLink内の描画では、おそらく同一のShaderが使用され、最低限のTexture/Uniformのみが切り替わるものと思われる。


続きはあるかわからん。