先总结下目前为止的流程:
void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList);
一,按需要重新分配渲染目标
1,void FSceneRenderTargets::AllocDummyGBufferTargets(FRHICommandList& RHICmdList)
1.1, template<typename InitializerType,typename RHIRefType,typename RHIParamRefType> static RHIParamRefType TStaticStateRHI<typename InitializerType,typename RHIRefType,typename RHIParamRefType>::GetRHI();
1.2,FGBufferResourceStruct::CreateUniformBuffer(GBufferResourceStruct, UniformBuffer_SingleFrame);
二,初始化视口(可以多个),包括确定可见性与设置阴影相关参数
1,bool FDeferredShadingSceneRenderer::InitViews(FRHICommandListImmediate& RHICmdList, struct FILCUpdatePrimTaskData& ILCTaskData, FGraphEventArray& SortEvents)
1.1,预设置可见性
void FSceneRenderer::PreVisibilityFrameSetup(FRHICommandListImmediate& RHICmdList)
1.1.1,根据当前画质设置,设置TemporalAA的采样方式,同时确定采样位置,
1.1.1.1, uint32 FSceneViewState::GetCurrentTemporalAASampleIndex() const
1.1.1.2,void FViewMatrices::HackAddTemporalAAProjectionJitter(const FVector2D& InTemporalAAProjectionJitter)
1.1.2,设置视口矩阵,包括视口投影矩阵和转换矩阵
void FViewMatrices::ApplyWorldOffset(const FVector& InOffset)
1.2,可见性计算
void FSceneRenderer::ComputeViewVisibility(FRHICommandListImmediate& RHICmdList)
1.2.1,初始化一系列用于可视化检测的缓冲区,(位数组,0和1代表是否可见)
1.2.2,用六棱锥进行筛选(a,b代表true或者false),不可见的对象的可视化检测缓冲区对应的比特位设置为0
template<bool UseCustomCulling, bool bAlsoUseSphereTest>
static int32 FrustumCull(const FScene* Scene, FViewInfo& View)
1.2.3,线框模式下,对直接剔除,剔除所有的非线框和过小的线框
1.2.4,在非线框模式下,对于处于视口范围内,但是被其他对象遮挡的对象进行一次剔除
static int32 OcclusionCull(FRHICommandListImmediate& RHICmdList, const FScene* Scene, FViewInfo& View)
1.2.5,根据所有的可见性位图,设置每个需要渲染的对象的可见性状况,即Hiddenflags
void FLODSceneTree::UpdateAndApplyVisibilityStates(FViewInfo& View)
1.2.6,给每个对象返回自己是否可见的机会
1.2.7,获取所有动态对象的渲染信息
void FSceneRenderer::GatherDynamicMeshElements(
TArray<FViewInfo>& InViews,
const FScene* InScene,
const FSceneViewFamily& InViewFamily,
const FPrimitiveViewMasks& HasDynamicMeshElementsMasks,
const FPrimitiveViewMasks& HasDynamicEditorMeshElementsMasks,
FMeshElementCollector& Collector)
1.3,完成可见性计算
void FSceneRenderer::PostVisibilityFrameSetup(FILCUpdatePrimTaskData& OutILCTaskData)
1.3.1,对半透明对象进行排序,半透明对象的渲染由于涉及到互相遮挡,则必须按照从后往前的顺序来渲染,才能保证渲染结果的正确性,因此,必须在此时完成排序
1.3.1.1,void FTranslucentPrimSet::SortPrimitives()
1.3.1.2,void FSceneViewState::TrimHistoryRenderTargets(const FScene* Scene)
1.3.2,对每个光照确定当前光照可见的对象列表,这里也是使用平截头体剔除,只需要测点光源和聚光灯,而平行光始 终可见
bool FConvexVolume::IntersectSphere(const FVector& Origin,const float& Radius) const
1.3.3,初始化雾与大气的常量值
void FSceneRenderer::InitFogConstants()
三、prepass预处理阶段
1,判断是否需要预处理
void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList)
2,预处理
2.1设置渲染状态
bool FDeferredShadingSceneRenderer::RenderPrePass(FRHICommandListImmediate& RHICmdList, TFunctionRef<void()> AfterTasksAreStarted)
2.1.1
bool FDeferredShadingSceneRenderer::RenderPrePassView(FRHICommandList& RHICmdList, const FViewInfo& View)
2.1.1.1
static void SetupPrePassView(FRHICommandList& RHICmdList, const FViewInfo& View, FDrawingPolicyRenderState& DrawRenderState, const bool bIsEditorPrimitivePass = false)
2.2,渲染三个绘制列表,这三个列表是由静态模型组成的,通过可见性位图控制是否可见。
bool FDeferredShadingSceneRenderer::RenderPrePassView(FRHICommandList& RHICmdList, const FViewInfo& View)
2.2.1,以StaticMesh为例绘制,
bool TStaticMeshDrawList<DrawingPolicyType>::DrawVisible(
FRHICommandList& RHICmdList,
const FViewInfo& View,
const typename DrawingPolicyType::ContextDataType PolicyContext,
const FDrawingPolicyRenderState& DrawRenderState,
const TBitArray<SceneRenderingBitArrayAllocator>& StaticMeshVisibilityMap,
const TArray<uint64,SceneRenderingAllocator>& BatchVisibilityArray
)
2.2.1.1载入公共着色器信息
template<typename DrawingPolicyType>
template<InstancedStereoPolicy InstancedStereo>
bool TStaticMeshDrawList<DrawingPolicyType>::DrawVisibleInner(
FRHICommandList& RHICmdList,
const FViewInfo& View,
const typename DrawingPolicyType::ContextDataType PolicyContext,
FDrawingPolicyRenderState& DrawRenderState,
const TBitArray<SceneRenderingBitArrayAllocator>* const StaticMeshVisibilityMap,
const TArray<uint64, SceneRenderingAllocator>* const BatchVisibilityArray,
const StereoPair* const StereoView,
int32 FirstPolicy, int32 LastPolicy,
bool bUpdateCounts
)
2.2.1.1.1
template<typename DrawingPolicyType>
template<InstancedStereoPolicy InstancedStereo>
int32 TStaticMeshDrawList<DrawingPolicyType>::DrawElement(
FRHICommandList& RHICmdList,
const FViewInfo& View,
const typename DrawingPolicyType::ContextDataType PolicyContext,
FDrawingPolicyRenderState& DrawRenderState,
const FElement& Element,
uint64 BatchElementMask,
FDrawingPolicyLink* DrawingPolicyLink,
bool& bDrawnShared
)
2.2.1.1.1.1,逐列表载入公共着色器信息
template<class DrawingPolicyType>
void CommitGraphicsPipelineState(FRHICommandList& RHICmdList, const DrawingPolicyType& DrawingPolicy, const FDrawingPolicyRenderState& DrawRenderState, const FBoundShaderStateInput& BoundShaderStateInput)
2.2.1.1.1.1.1
void SetGraphicsPipelineState(FRHICommandList& RHICmdList, const FGraphicsPipelineStateInitializer& Initializer, EApplyRendertargetOption ApplyFlags)
2.2.1.2.逐元素渲染(并非一对一的元素,而是经过组合的BatchElement)
2.2.1.2.1,设置渲染状态
void FMeshDrawingPolicy::SetMeshRenderState(
FRHICommandList& RHICmdList,
const FSceneView& View,
const FPrimitiveSceneProxy* PrimitiveSceneProxy,
const FMeshBatch& Mesh,
int32 BatchElementIndex,
const FDrawingPolicyRenderState& DrawRenderState,
const ElementDataType& ElementData,
const ContextDataType PolicyContext
) const
2.2.1.2.2,完成实际绘制
void FMeshDrawingPolicy::DrawMesh(FRHICommandList& RHICmdList, const FMeshBatch& Mesh, int32 BatchElementIndex, const bool bIsInstancedStereo = false) const;
2.3,绘制动态的预处理阶段对象
bool FDeferredShadingSceneRenderer::RenderPrePassViewDynamic(FRHICommandList& RHICmdList, const FViewInfo& View, const FDrawingPolicyRenderState& DrawRenderState)
2.3.1,询问RenderProxy是否被当作一个遮挡物体,决定是否需要在这个阶段绘制
FPrimitiveSceneProxy::ShouldUseAsOccluder()
2.3.2,具体绘制动态物体
bool FDepthDrawingPolicyFactory::DrawDynamicMesh(
FRHICommandList& RHICmdList,
const FViewInfo& View,
ContextType DrawingContext,
const FMeshBatch& Mesh,
bool bPreFog,
const FDrawingPolicyRenderState& DrawRenderState,
const FPrimitiveSceneProxy* PrimitiveSceneProxy,
FHitProxyId HitProxyId,
const bool bIsInstancedStereo,
const bool bIsInstancedStereoEmulated
)
四、现在进行一个极为重要的阶段,BasePass。
即,通过逐对象的绘制,将每个对象和光照相关的信息都写入到缓冲区中。
涉及到问题
(1)逐对象绘制后的结果如何写入到缓冲区中
(2)缓冲区中的内容如何管理
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_BasePass));
RenderBasePass(RHICmdList, BasePassDepthStencilAccess);
RHICmdList.SetCurrentStat(GET_STATID(STAT_CLM_AfterBasePass))
bool FDeferredShadingSceneRenderer::RenderBasePass()
1,设置渲染视口
4.1.1,bool FDeferredShadingSceneRenderer::RenderBasePassView()
4.1.1.1,void SetupBasePassView()
4.1.1.1.1,如果PrePass阶段已经写入深度,则深度写入关闭,直接使用已经写入的深度结果进行深度检测。
FDrawingPolicyRenderState::SetDepthStencilState();
4.1.1.1.2,打开前4个渲染目标的RGBA写入
class TStatucBkebdStateWriteMask;
4.1.1.1.3,设置区域大小,根据是否开启InstanceStereoPass而有所变化
4.1.1.1.3.1,
FRHICommandList::SetViewport()
4.1.1.1.3.2,
FRHICommandList::SetStereoViewport()
4.1.1.1.2,渲染静态数据。如果之前已经进行了深度渲染,那么首先渲染Masked蒙版对象,然后渲染普通的不透明对象。否则,就反过来,先渲染不透明对象,再渲染蒙版对象。
FDeferredShadingSceneRenderer::RenderBasePassStaticData()
4.1.1.1.2.1,FDeferredShadingSceneRenderer::RenderBasePassStaticDataType()
4.1.1.1.2.1.1,DrawVisible()
4.1.1.1.2.1.2,DrawVisibleInstancedStereo()
4.1.1.1.3,渲染动态数据。
FDeferredShadingSceneRenderer::RenderBasePassDynamicData()
4.1.1.1.3.1
FBasePassOpaqueDrawingPolicyFactory::DrawDynamicMesh()
总结下目前流程
先总结下目前为止的流程:
void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList);
一,按需要重新分配渲染目标
1,void FSceneRenderTargets::AllocDummyGBufferTargets()
1.1,static RHIParamRefType TStaticStateRHI<typename InitializerType,typename RHIRefType,typename RHIParamRefType>::GetRHI();
1.2,FGBufferResourceStruct::CreateUniformBuffer();
二,初始化视口(可以多个),包括确定可见性与设置阴影相关参数
1,bool FDeferredShadingSceneRenderer::InitViews()
1.1,预设置可见性
void FSceneRenderer::PreVisibilityFrameSetup()
1.1.1,根据当前画质设置,设置TemporalAA的采样方式,同时确定采样位置,
1.1.1.1, uint32 FSceneViewState::GetCurrentTemporalAASampleIndex() const
1.1.1.2,void FViewMatrices::HackAddTemporalAAProjectionJitter()
1.1.2,设置视口矩阵,包括视口投影矩阵和转换矩阵
void FViewMatrices::ApplyWorldOffset()
1.2,可见性计算
void FSceneRenderer::ComputeViewVisibility()
1.2.1,初始化一系列用于可视化检测的缓冲区,(位数组,0和1代表是否可见)
1.2.2,用六棱锥进行筛选(a,b代表true或者false),不可见的对象的可视化检测缓冲区对应的比特位设置为0
static int32 FrustumCull()
1.2.3,线框模式下,对直接剔除,剔除所有的非线框和过小的线框
1.2.4,在非线框模式下,对于处于视口范围内,但是被其他对象遮挡的对象进行一次剔除
static int32 OcclusionCull()
1.2.5,根据所有的可见性位图,设置每个需要渲染的对象的可见性状况,即Hiddenflags
void FLODSceneTree::UpdateAndApplyVisibilityStates()
1.2.6,给每个对象返回自己是否可见的机会
1.2.7,获取所有动态对象的渲染信息
void FSceneRenderer::GatherDynamicMeshElements()
1.3,完成可见性计算
void FSceneRenderer::PostVisibilityFrameSetup()
1.3.1,对半透明对象进行排序,半透明对象的渲染由于涉及到互相遮挡,则必须按照从后往前的顺序来渲染,才能保证渲染结果的正确性,因此,必须在此时完成排序
1.3.1.1,void FTranslucentPrimSet::SortPrimitives()
1.3.1.2,void FSceneViewState::TrimHistoryRenderTargets()
1.3.2,对每个光照确定当前光照可见的对象列表,这里也是使用平截头体剔除,只需要测点光源和聚光灯,而平行光始 终可见
bool FConvexVolume::IntersectSphere() const
1.3.3,初始化雾与大气的常量值
void FSceneRenderer::InitFogConstants()
三、prepass预处理阶段
3.1,判断是否需要预处理
void FDeferredShadingSceneRenderer::Render()
3.2,预处理
3.2.1设置渲染状态
bool FDeferredShadingSceneRenderer::RenderPrePass()
3.2.1.1
bool FDeferredShadingSceneRenderer::RenderPrePassView()
3.2.1.1.1
static void SetupPrePassView()
3.2.2,渲染三个绘制列表,这三个列表是由静态模型组成的,通过可见性位图控制是否可见。
bool FDeferredShadingSceneRenderer::RenderPrePassView()
3.2.2.1,以StaticMesh为例绘制,
bool TStaticMeshDrawList<DrawingPolicyType>::DrawVisible()
3.2.2.1.1载入公共着色器信息
bool TStaticMeshDrawList<DrawingPolicyType>::DrawVisibleInner()
3.2.2.1.1.1
int32 TStaticMeshDrawList<DrawingPolicyType>::DrawElement()
3.2.2.1.1.1.1,逐列表载入公共着色器信息
void CommitGraphicsPipelineState()
3.2.2.1.1.1.1.1
void SetGraphicsPipelineState()
3.2.2.1.2.逐元素渲染(并非一对一的元素,而是经过组合的BatchElement)
3.2.2.1.2.1,设置渲染状态
void FMeshDrawingPolicy::SetMeshRenderState();
3.2.2.1.2.2,完成实际绘制
void FMeshDrawingPolicy::DrawMesh() ;
3.2.3,绘制动态的预处理阶段对象
bool FDeferredShadingSceneRenderer::RenderPrePassViewDynamic()
3.2.3.1,询问RenderProxy是否被当作一个遮挡物体,决定是否需要在这个阶段绘制
FPrimitiveSceneProxy::ShouldUseAsOccluder()
3.2.3.2,具体绘制动态物体
bool FDepthDrawingPolicyFactory::DrawDynamicMesh( )
四、BasePass阶段:渲染不透明和MASK材质
通过逐对象的绘制,将每个对象和光照相关的信息都写入到缓冲区中。
bool FDeferredShadingSceneRenderer::RenderBasePass()
4.1,设置渲染视口
4.1.1,bool FDeferredShadingSceneRenderer::RenderBasePassView()
4.1.1.1,void SetupBasePassView()
4.1.1.1.1,如果PrePass阶段已经写入深度,则深度写入关闭,直接使用已经写入的深度结果进行深度检测。
FDrawingPolicyRenderState::SetDepthStencilState();
4.1.1.1.2,打开前4个渲染目标的RGBA写入
class TStatucBkebdStateWriteMask;
4.1.1.1.3,设置区域大小,根据是否开启InstanceStereoPass而有所变化
4.1.1.1.3.1,
FRHICommandList::SetViewport()
4.1.1.1.3.2,
FRHICommandList::SetStereoViewport()
4.2,渲染静态数据。如果之前已经进行了深度渲染,那么首先渲染Masked蒙版对象,然后渲染普通的不透明对象。否则,就反过来,先渲染不透明对象,再渲染蒙版对象。
FDeferredShadingSceneRenderer::RenderBasePassStaticData()
4.2.1,FDeferredShadingSceneRenderer::RenderBasePassStaticDataType()
4.2.1.1,DrawVisible()
4.2.1.2,DrawVisibleInstancedStereo()
4.3,渲染动态数据。
FDeferredShadingSceneRenderer::RenderBasePassDynamicData()
4.3.1
FBasePassOpaqueDrawingPolicyFactory::DrawDynamicMesh()