[前回の整理] FrowardRenderer におけるDrawVisible系メソッド
DrawVisible系のメソッドは、結局のところ、TStaticMeshDrawList::DrawElement()を呼び出す。
template<typename DrawingPolicyType> void TStaticMeshDrawList<DrawingPolicyType>::DrawElement( const FViewInfo& View, const FElement& Element, uint64 BatchElementMask, FDrawingPolicyLink* DrawingPolicyLink, bool& bDrawnShared )
FrowardRendererのBasePassで使用するDrawingPolicyTypeは、FMeshDrawingPolicyが基底の、TBasePassForForwardShadingDrawingPolicy<T>のテンプレート特殊化クラス。
template<typename LightMapPolicyType> class TBasePassForForwardShadingDrawingPolicy : public FMeshDrawingPolicy
FrowardRendererで使用されているLightMapPolicyTypeは以下の通り。
FNoLightMapPolicy TLightMapPolicy<LQ_LIGHTMAP> TDistanceFieldShadowsAndLightMapPolicy<LQ_LIGHTMAP> FSimpleDirectionalLightAndSHIndirectPolicy
TStaticMeshDrawList::DrawElement()の大まかな流れ
引数のbDrawnSharedは、直前のDrawElement呼び出しで使用されたDrawPolicyLinkが同じものであるかどうかが代入される。
falseの場合は
DrawingPolicyLink->DrawingPolicy.DrawShared()
を呼び出す。
引数のBatchElementMaskに応じて次のメソッドを、必要な回数呼び出す。
DrawingPolicyLink->DrawingPolicy.SetMeshRenderState() DrawingPolicyLink->DrawingPolicy.DrawMesh()
上記の通り、DrawElement()の実行部分は、DrawingPoilicyに実装されている。
DrawShared()が、端的に言えば、シェーダー/マテリアル切り替え単位の設定部分。
SetMeshRenderState()が、DrawCallごとに設定が必要なUniform/Texture/Stateの設定部分。
DrawMesh()がDrawCallの呼び出し部分となる。
FMeshDrawingPolicyについて
TBasePassForForwardShadingDrawingPolicyの基底クラスである、FMeshDrawingPolicyを見るとDrawCall呼び出しの大まかな流れが分かる。
DrawElement()に関連する下記の3つのメソッドについて見てみる
- DrawShared()
- FMeshDrawingPolicyのメンバーで保持しているVertexFactoryの
VertexFactory->Set()
を呼び出し、頂点配列をBindしている。 - SetMeshRenderState()
- 引数で指定されたMeshに設定されているフラグと、FMeshDrawingPolicyに設定されているフラグをチェックして、FillMode,CullModeの指定を行っている。
- DrawMesh()
- 引数で受け取った、Mesh,BatchElementIndexより、DrawCallを呼び出す頂点範囲とIndexBufferを示すFMeshBatchElementを取得し、これに基き、実際のDrawCallを呼び出す。
FMeshDrawingPolicyでは、シェーダーの設定は行われておらず、頂点配列のBindとFillMode,CullModeの指定とDrawCallの呼び出しが行われている。
また、同一DrawingPolicy内では、頂点配列は共有されており、これを複数のDrawCallで共有できる仕組みを有していることが分かる。
TBasePassForForwardShadingDrawingPolicyについて
次に、FMeshDrawingPolicyの派生クラスである、TBasePassForForwardShadingDrawingPolicy<LightMapPolicyType>について見てみる。
- コンストラクタ
- コンストラクタでは、VertexShaderとPixelShader(後述)を取得している。これらは、LightMapPolicyTypeと、RenderTargetのフォーマットで決まる。
- DrawShared()
- 下記メソッドの呼び出し
RHISetBoundShaerState()
VertexShader->SetParameters()
PixelShader->SetParameters()
LightMapPolicy.Set() - SetMeshRenderState()
- 下記メソッドの呼び出し
LightMapPolicy.SetMesh()
VertexShader->SetMesh()
PixelShader->SetMesh()
FMeshDrawingPolicy::SetMeshRenderState() - DrawMesh()
- FMeshDrawingPolicyと同じ
RHISetBoundShaerState()は、IA/VS/PSのBindを行っており、FMeshDrawingPolicyと比較すると、シェーダー関連の設定と、LightMapPolicyによる設定が追加されているのが分かる。
FNoLightMapPolicyについて
ForwardShadingで使用されているLightMapPolicyTypeの中で、一番単純な、FNoLightMapPolicyの、DrawCallに関連するメソッドを見てみる。
- Set()
- 引数で受け取った、FVertexFactory型の、VertexFactory->Set()を呼び出し、VertexFactoryが保持している頂点配列を、Bindしている。
引数で渡されるVertexFactoryは、TBasePassForForwardShadingDrawingPolicy<T>のメンバーのVertexFactoryなので、遡れば、DrawingPolicyLink->DrawingPolicyのVertexFactoryということになる。つまり同一DrwaingPolicyLink内で頂点配列は共有される。 - SetMesh()
- 何もしない。
VertexShaderとPixelShaderについて
TBasePassForForwardShadingDrawingPolicy<LightMapPolicyType>内で宣言されている、VertexShaderとPixelShaderは以下の通り。
TBasePassForForwardShadingVSBaseType<LightMapPolicyType>* VertexShader; TBasePassForForwardShadingPSBaseType<LightMapPolicyType>* PixelShader;
どちらもFMeshMaterialShaderを基底にしている。
template<typename LightMapPolicyType> class TBasePassForForwardShadingVSBaseType : public FMeshMaterialShader, public LightMapPolicyType::VertexParametersType template<typename LightMapPolicyType> class TBasePassForForwardShadingPSBaseType : public FMeshMaterialShader, public LightMapPolicyType::PixelParametersType
VertexShader, PixelShaderの各インスタンスは、DrawingPolicyのコンストラクト時に、ポインタが取得される。どちらもShaderの実体を保持するが、設定するUniformやTextureの実体は保持しない。
DrwaElement()に関連する以下のメソッドを見てみる。
- VertexShader->SetParameters()
- 以下のメソッドを呼び出す
HeightFogParameters.Set(GetVertexShader(), &View);
FMeshMaterialShader::SetParameters(GetVertexShader(),MaterialRenderProxy,InMaterialResource,View,TextureMode); - PixelShader->SetParameters()
- 以下のメソッドを呼び出す
FMeshMaterialShader::SetParameters(GetPixelShader(),MaterialRenderProxy,MaterialResource,*View,TextureMode);
このルーチンはVertexShaderで使われたものと同様。 - VertexShader->SetMesh()
- 以下のメソッドを呼び出す
FMeshMaterialShader::SetMesh(GetVertexShader(),VertexFactory,View,Proxy,BatchElement); - PixelShader->SetMesh()
- ReflectionCubeMapのBind(必要に応じて)
以下のメソッドを呼び出す
FMeshMaterialShader::SetMesh(GetPixelShader(),VertexFactory,View,Proxy,BatchElement);
上記のことから、TBasePassForForwardShadingDrawingPolicy内で宣言されている、VertexShaderとPixelShaderクラスは、
FMeshMaterialShaderに対して、HeightFog用のパラメータ設定と、ReflectionCubeMapのBindを追加したものと考えられる。
FMeshMaterialShaderについて
シェーダーのパラメータ設定はおおよそ、この基底クラスに集約されている。DrawElement呼び出しからは、以下のメソッドが呼び出される。
FMeshMaterialShader::SetParameters(GetVertexShader(),MaterialRenderProxy,InMaterialResource,View,TextureMode);
FMaterialShader::SetParameters()を呼び出すだけ。FMaterialShader::SetParameters()では、
引数Viewが保持するUniformBufferのBind (View関連パラメータのUniform)
引数MaterialRenderPorxyが保持してるUniformBufferのBind (Material関連パラーメータのUniform)
引数MaterialRenderPorxyがFGuidを保持してるUniformBufferのBind (ParameterCollection(Sceneが実体保持)のUniform)
引数MaterialRenderPorxyが保持してる2DTextureのBind
引数MaterialRenderPorxyが保持してるCubeTextureのBind
以下は条件によって必要に応じて各種設定される
DeferredShading用のTextureの設定(PixelShader向け)
引数Viewが保持するAtomosphere pass用のUniformパラメータの設定
PostProcessパラメータの設定
EyeAdaptation用のTextureの設定
PerlinNoiseGradiantテクスチャの設定
PerlinNoise3Dテクスチャの設定
これ等のリソースの設定位置(BindSlot)は基本的に、FMaterialShaderが保持している。
対して、設定されるリソースの実体は、引数のView/MaterialRenderProxy、もしくはGlobal変数から取得される。
FMeshMaterialShader::SetMesh(GetPixelShader(),VertexFactory,View,Proxy,BatchElement);
引数VertexFactoryに関連するUniform/Textureの設定。
引数BatchElementに格納されているUniformの設定(内容は変換マトリクスなど)
引数Proxy,Viewに格納されているUniformの設定(内容はLODのFading用)
引数VertexFactoryは頂点配列に相当するデータなので、これに対応するUniformやTextureが設定される。
具体的には、SpeedTree/Particle/GPUSkinning/VectorFieldVisualizationなど、UE4のMaterialで保持しないシェーダーリソース情報の設定がここで行われる。
大まかな流れ
だいたいこんな感じだと思われる。