照样,先回顾下目前流程
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()
五,RenderOccusion阶段
其实就是遮挡查询,比如说,在视锥体内,山后面的石头看不见了,也要剔除。在屏幕坐标系上,也就是处于屏幕内,但是被遮挡。这里主要用了类似屏幕上打马赛克的方式,根据级别不同,打不同分辨率的马赛克。这样就遮住不同的东西了。