lumen在渲染的时候会走几个步骤:
第一是BeginUpdateLumenSceneTasks对场景的距离场体素重建
第二是UpdateLumenScene更新lumen的场景以及包括用nanite提出并且上传lumen的card
第三是RenderLumenSceneLighting获取lumen光照的直接光与间接光
第四是RenderLumenSceneVisualization可视化探针的获取与设置,体素步进与辐射度设置。
第五是RenderDiffuseIndirectAndAmbientOcclusion中对lumen的探针执行计算获取探针的光照来叠加。
通过Lumen::SetupViewUniformBufferParameters来设置uniform的数据。
数据拷贝到内存中
对lumen的card的渲染
对CardsToRender中的所有FCardRenderData对象都执行SubmitMeshDrawCommandsRange,提交到渲染指令中。这里的CardsToRender是经过BeginUpdateLumenSceneTasks过滤后的。其中的参数带有4张rt,包括lumen算出来的albedoatlas,normalatlas,emissiveatlas以及depthstencilatlas。
Nanite剔除
后面就用nanite来剔除,首先通过Nanite::InitRasterContext获取光栅化的上下文信息,以及通过Nanite::InitCullingContext获取剔除的上下文信息。
对视角或单视角剔除
然后根据是否是GLumenSceneNaniteMultiViewCapture来指定是多个view处理的还是单个view处理的。
然后组织成NaniteView来对所有CardsToRender进入Nanite::CullRasterize。如果是单view则对所有CardsToRender执行PackedView的Nanite::CullRasterize。
其中Nanite::CullRasterize中的NaniteInstanceDraws就是用nanite来渲染的对象。执行剔除。Nanite::CullRasterize,包括HZB,vsm剔除。
距离场剔除
紧接着会执行距离场的剔除,其中的参数Lumen::GetDistanceSceneNaniteLODScaleFactor()是2的
幂次。然后执行Nanite::CullRasterize对单独的PackedView做剔除。
CullRasterize相当的处理
这里的Nanite::CullRasterize需要的参数是场景,视野对象,剔除上下文,光栅化上下文,然后是光栅化状态(比如近裁剪面以及剔除方式是正面背面等)。
具体到CullRasterize中,如果视锥数量大于MAX_VIEWS_PER_CULL_RASTERIZE_PASS则要拆开另一个pass来剔除。
然后用FInitArgs_CS初始化cluster的剔除
用AddPass_InstanceHierarchyAndClusterCull来加入一个层级剔除和簇剔除。
Nanite关于lumen的渲染:
然后用Nanite::DrawLumenMeshCapturePass来渲染,执行到NaniteRender.cpp的DrawLumenMeshCapturePass。
首先设置参数FNaniteMarkStencilRectsParameters,然后执行到FPixelShaderUtils::AddRasterizeToRectsPass,在里面执行RHICmdList.DrawPrimitive,标记所有通过深度测试的像素的模板。
接着设置参数FNaniteEmitMaterialIdRectsParameters,然后执行FPixelShaderUtils::AddRasterizeToRectsPass,用RHICmdList.DrawPrimitive绘制信息,这里是用深度信息获取材质信息。
然后设置参数到FNaniteEmitGBufferParameters,包括簇信息,albedo,normal,emissive,并设置uniform数据到FNaniteUniformParameters,利用const_cast<FScene&>(Scene).UniformBuffers.NaniteUniformBuffer.UpdateUniformBufferImmediate,也就是nanite的uniform数据设置。
两种模式提交渲染
然后有两种模式,一个是有距离场的模式,一个是执行列表模式。
距离场模式:
有距离场的模式通过BuildNaniteMaterialPassCommands获取到NaniteMaterialPassCommands关于nanite的材质的pass。对每个pass进行提交SubmitNaniteMaterialPassCommand。这里的
这里的SubmitNaniteMaterialPassCommand是执行到NaniteRender的SubmitNaniteMaterialPassCommand,也是通过FMeshDrawCommand::SubmitDrawBegin和FMeshDrawCommand::SubmitDrawEnd去执行到具体平台的draw指令。
nanite执行列表模式
如果不是距离场的模式,则遍历CardRenderData.NaniteCommandInfos然后拿到里面的id,通过Scene.NaniteDrawCommands[ENaniteMeshPass::LumenCardCapture]获取到FMeshDrawCommand,然后用SubmitNaniteMaterialPassCommand来执行MeshDrawCommand的draw。
再次获取深度信息:
最后他还再执行一次深度值的获取,这里主要是如果有修改能第一时间写入。
上传lumen的buffer
然后用FLumenCardIdUpload上传lumen的card。这里是对几个IBuffer的上传,包括有CardsToRenderIndexBuffer,CardsToRenderHashMapBuffer,VisibleCardsIndexBuffer。
这里的上传的核心是地址拷贝,FPlatformMemory::Memcpy(DestCardIdPtr, CardIdPtr, CardIdBytes);这里的目标地址是是RHI的一个buffer。
过滤lumen的深度:
然后执行完上传后还会过滤一遍深度。PrefilterLumenSceneDepth。这里是执行到FDeferredShadingSceneRenderer::PrefilterLumenSceneDepth。
首先初始化CardScatterContext的变量。
然后执行FLumenCardScatterContext::CullCardsToShape,主要是执行FCullCardsToShapeCS这个computeshader,也就执行LumenSceneLighting.usf的CullCardsToShapeCS。主要过滤的方式是card是否可见,card是否受到灯光范围影响以及card是否在可视范围内。
然后就是BuildScatterIndirectArgs,也就是跟RenderLumenSceneLighting的BuildScatterIndirectArgs的间接光参数初始化一样。
然后FLumenCardCopyDepth执行lumencard的深度拷贝。主要是执行LumenSceneLighting.usf的LumenCardPrefilterLightingPS通过mrt执行三个颜色的赋值,OutLighting,OutColor1,OutColor2。分别是父级光照信息,直接辐照度颜色,间接辐照度颜色。