--- title: Untitled date: 2024-09-25 14:59:32 excerpt: tags: rating: ⭐ --- # 前言 可以使用DrawDynamicMeshPass(),实现在插件中使用MeshDraw绘制Pass。 参考文章: - ***UE5,为HairStrands添加自定义深度与模板***:https://zhuanlan.zhihu.com/p/689578355 # MeshDraw 推荐学习: - CustomDepth - RenderBasePassInternal() - RenderAnisotropyPass() Shader推荐: - DepthOnlyVertexShader.usf - DepthOnlyPixelShader.usf ## BasePass ### DrawBasePass() 该函数在FDeferredShadingSceneRenderer::RenderBasePassInternal()中调用。 DrawNaniteMaterialPass() => SubmitNaniteIndirectMaterial() ## PSO - RDG 04 Graphics Pipeline State Initializer https://zhuanlan.zhihu.com/p/582020846 - FGraphicsPipelineStateInitializer - FRHIDepthStencilState* DepthStencilState - FRHIBlendState* BlendState - FRHIRasterizerState* RasterizerState - EPrimitiveType PrimitiveType - FBoundShaderStateInput BoundShaderState.VertexDeclarationRHI - FBoundShaderStateInput BoundShaderState.VertexShaderRHI - FBoundShaderStateInput BoundShaderState.PixelShaderRHI - …… // 应用 SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit,0); ## FMeshPassProcessorRenderState - FMeshPassProcessorRenderState - FRHIBlendState* BlendState - FRHIDepthStencilState* DepthStencilState - FExclusiveDepthStencil::Type DepthStencilAccess - FRHIUniformBuffer* ViewUniformBuffer - FRHIUniformBuffer* InstancedViewUniformBuffer - FRHIUniformBuffer* PassUniformBuffer - FRHIUniformBuffer* NaniteUniformBuffer - uint32 StencilRef = 0; ### FRHIBlendState 使用***FBlendStateInitializerRHI()*** 进行初始化。 它定义了8个渲染对象,一般我们只用第一组,它的七个参数分别是: - Color - Color Write Mask - Color Blend 混合类型 - Color Src 混合因子 - Color Dest 混合因子 - Alpha - Alpha Blend 混合类型 - Alpha Src 混合因子 - Alpha Dest 混合因子 ```c++ FRHIBlendState* CopyBlendState = TStaticBlendState::GetRHI(); ``` 颜色写入蒙版: ```c++ enum EColorWriteMask { CW_RED = 0x01, CW_GREEN = 0x02, CW_BLUE = 0x04, CW_ALPHA = 0x08, CW_NONE = 0, CW_RGB = CW_RED | CW_GREEN | CW_BLUE, CW_RGBA = CW_RED | CW_GREEN | CW_BLUE | CW_ALPHA, CW_RG = CW_RED | CW_GREEN, CW_BA = CW_BLUE | CW_ALPHA, EColorWriteMask_NumBits = 4, }; ``` #### 混合运算 混合运算符对于颜色混合方程和Alpha混合方程效果是一样的,这里就只用颜色混合方程来做讲解。 | BlendOperation | 颜色混合方程 | | -------------------- | ---------------------------------------------------------------------------------- | | BO_Add | $$C=C_{src} \otimes F_{src} + C_{dst} \otimes F_{dst}Csrc​⊗Fsrc​+Cdst​⊗Fdst$$​ | | BO_Subtract | $$C = C_{src} \otimes F_{src} - C_{dst} \otimes F_{dst}C=Csrc​⊗Fsrc​−Cdst​⊗Fdst$$​ | | BO_ReverseSubtract | $$C = C_{dst} \otimes F_{dst} - C_{src} \otimes F_{src}C=Cdst​⊗Fdst​−Csrc​⊗Fsrc$$​ | | BO_Min | $$C = Min(C_{src} , C_{dst} )C=Min(Csrc​,Cdst​)$$ | | BO_Max | $$C = Max(C_{src} , C_{dst} )C=Max(Csrc​,Cdst​)$$ | | BO_Min和BO_Max忽略了混合因子 | | #### 混合因子 | BlendFactor | 颜色混合因子 | Alpha混合因子 | | ----------------------------- | ---------------------------------------------------------------- | ------------------------ | | BF_Zero | $$F = (0,0,0)F=(0,0,0)$$ | $$F=0F=0$$ | | BF_One | $$F=(1,1,1)F=(1,1,1)$$ | $$F=1F=1$$ | | BF_SourceColor | $$F=(r_{src},g_{src},b_{src})F=(rsrc​,gsrc​,bsrc​)$$ | – | | BF_InverseSourceColor | $$F=(1-r_{src},1-g_{src},1-b_{src})F=(1−rsrc​,1−gsrc​,1−bsrc​)$$ | – | | BF_SourceAlpha | $$F=(a_{src},a_{src},a_{src})F=(asrc​,asrc​,asrc​)$$ | $$F=a_{src}F=asrc$$​ | | BF_InverseSourceAlpha | $$F=(1-a_{src},1-a_{src},1-a_{src})F=(1−asrc​,1−asrc​,1−asrc​)$$ | $$F=1-a_{src}F=1−asrc$$​ | | BF_DestAlpha | $$F=(a_{dst},a_{dst},a_{dst})F=(adst​,adst​,adst​)$$ | $$F=a_{dst}F=adst$$​ | | BF_InverseDestAlpha | $$F=(1-a_{dst},1-a_{dst},1-a_{dst})F=(1−adst​,1−adst​,1−adst​)$$ | $$F=1-a_{dst}F=1−adst$$​ | | BF_DestColor | $$F=(r_{dst},g_{dst},b_{dst})F=(rdst​,gdst​,bdst​)$$ | – | | BF_InverseDestColor | $$F=(1-r_{dst},1-g_{dst},1-b_{dst})F=(1−rdst​,1−gdst​,1−bdst​)$$ | – | | BF_ConstantBlendFactor | F=(r,g,b)F=(r,g,b) | F=aF=a | | BF_InverseConstantBlendFactor | F=(1-r,1-g,1-b)F=(1−r,1−g,1−b) | F=1-aF=1−a | | BF_Source1Color | 未知 | 未知 | | BF_InverseSource1Color | 未知 | 未知 | | BF_Source1Alpha | 未知 | 未知 | | BF_InverseSource1Alpha | 未知 | 未知 | 最后四个选项没有在DirectX中找到对应的选项,没有继续探究,前面的应该足够一般使用了。 ### FRHIDepthStencilState ```c++ TStaticDepthStencilState< bEnableDepthWrite, // 是否启用深度写入 DepthTest, // 深度测试比较函数 bEnableFrontFaceStencil, // (正面)启用模板 FrontFaceStencilTest, // (正面)模板测试操作 FrontFaceStencilFailStencilOp, //(正面)模板测试失败时如何更新模板缓冲区 FrontFaceDepthFailStencilOp, //(正面)深度测试失败时如何更新模板缓冲区 FrontFacePassStencilOp, //(正面)通过模板测试时如何更新模板缓冲区 bEnableBackFaceStencil, // (背面)启用模板 BackFaceStencilTest, // (背面)模板失败操作 BackFaceStencilFailStencilOp, //(背面)模板测试失败时如何更新模板缓冲区 BackFaceDepthFailStencilOp, //(背面)深度测试失败时如何更新模板缓冲区 BackFacePassStencilOp, //(背面)通过模板测试时如何更新模板红冲去 StencilReadMask, // 模板读取Mask StencilWriteMask // 模板写入Mask > ``` ```c++ //一般使用这个 TStaticDepthStencilState::GetRHI(); //CustomStencil中使用的 TStaticDepthStencilState::GetRHI() ``` #### DepthTest 深度测试比较函数。 ```c++ enum ECompareFunction { CF_Less, CF_LessEqual, CF_Greater, CF_GreaterEqual, CF_Equal, CF_NotEqual, CF_Never, // 总是返回false CF_Always, // 总是返回true ECompareFunction_Num, ECompareFunction_NumBits = 3, // Utility enumerations CF_DepthNearOrEqual = (((int32)ERHIZBuffer::IsInverted != 0) ? CF_GreaterEqual : CF_LessEqual), CF_DepthNear = (((int32)ERHIZBuffer::IsInverted != 0) ? CF_Greater : CF_Less), CF_DepthFartherOrEqual = (((int32)ERHIZBuffer::IsInverted != 0) ? CF_LessEqual : CF_GreaterEqual), CF_DepthFarther = (((int32)ERHIZBuffer::IsInverted != 0) ? CF_Less : CF_Greater), }; ``` ```c++ enum EStencilOp { SO_Keep, SO_Zero, SO_Replace, SO_SaturatedIncrement, SO_SaturatedDecrement, SO_Invert, SO_Increment, SO_Decrement, EStencilOp_Num, EStencilOp_NumBits = 3, }; ``` ### CustomStencil #### InitCustomDepthStencilContext() 根据当前平台是否支持使用ComputeShader直接输出结果(bComputeExport)、以及是否写入Stencil缓存,以此来创建不同的资源。最终输出FCustomDepthContext。 ```c++ struct FCustomDepthContext { FRDGTextureRef InputDepth = nullptr; FRDGTextureSRVRef InputStencilSRV = nullptr; FRDGTextureRef DepthTarget = nullptr; FRDGTextureRef StencilTarget = nullptr; bool bComputeExport = true; }; ``` #### EmitCustomDepthStencilTargets() 根据bComputeExport,分别使用RDG的ComputeShader与PixelShader输出DepthStencil。 - CS使用FComputeShaderUtils::AddPass() - PS使用NaniteExportGBuffer.usf的**EmitCustomDepthStencilPS()**,FPixelShaderUtils::AddFullscreenPass() 以**FEmitCustomDepthStencilPS**(NaniteExportGBuffer.usf)为例,额外输入的Nanite相关变量: - FSceneUniformParameters Scene - StructuredBuffer`<`FPackedView`>` InViews - ByteAddressBuffer VisibleClustersSWHW? - FIntVector4, PageConstants - Texture2D`<`UlongType`>`, VisBuffer64 - ByteAddressBuffer MaterialSlotTable #### FinalizeCustomDepthStencil() 替换输出的Depth&Stencil。 # FViewInfo FViewInfo& ViewInfo - WriteView.bSceneHasSkyMaterial |= bSceneHasSkyMaterial; - WriteView.bHasSingleLayerWaterMaterial |= bHasSingleLayerWaterMaterial; - WriteView.bHasCustomDepthPrimitives |= bHasCustomDepthPrimitives; - WriteView.bHasDistortionPrimitives |= bHasDistortionPrimitives; - WriteView.bUsesCustomDepth |= bUsesCustomDepth; - WriteView.bUsesCustomStencil |= bUsesCustomStencil; - FRelevancePacket::Finalize() 相关性: - 相关性定义 - FStaticMeshBatchRelevance - FMaterialRelevance - View相关计算 - FViewInfo::Init() - FRelevancePacket - FRelevancePacket::Finalize() # 相关宏定义 - SCOPE_CYCLE_COUNTER(STAT_BasePassDrawTime);: - DECLARE_CYCLE_STAT_EXTERN(TEXT("Base pass drawing"),STAT_BasePassDrawTime,STATGROUP_SceneRendering, RENDERCORE_API); - DEFINE_STAT(STAT_BasePassDrawTime); - DEFINE_GPU_STAT(NaniteBasePass); - DECLARE_GPU_STAT_NAMED_EXTERN(NaniteBasePass, TEXT("Nanite BasePass")); - GET_STATID(STAT_CLP_BasePass) - FRDGParallelCommandListSet ParallelCommandListSet(InPass, RHICmdList, GET_STATID(STAT_CLP_BasePass), View, FParallelCommandListBindings(PassParameters)); - DECLARE_CYCLE_STAT(TEXT("BasePass"), STAT_CLP_BasePass, STATGROUP_ParallelCommandListMarkers); # NaniteMeshDraw `Engine\Source\Runtime\Renderer\Private\Nanite\`NaniteMaterials.h & NaniteMaterials.cpp PS.使用的Shader必须是`FNaniteGlobalShader`的子类。 以下是Nanite物体的CustomDepth绘制过程: ```c++ bool FSceneRenderer::RenderCustomDepthPass( FRDGBuilder& GraphBuilder, FCustomDepthTextures& CustomDepthTextures, const FSceneTextureShaderParameters& SceneTextures, TConstArrayView PrimaryNaniteRasterResults, TConstArrayView PrimaryNaniteViews) { if (!CustomDepthTextures.IsValid()) { return false; } // Determine if any of the views have custom depth and if any of them have Nanite that is rendering custom depth // 构建NaniteDrawLists,用于后面的绘制 bool bAnyCustomDepth = false; TArray NaniteDrawLists; NaniteDrawLists.AddDefaulted(Views.Num()); uint32 TotalNaniteInstances = 0; for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex) { FViewInfo& View = Views[ViewIndex]; if (View.ShouldRenderView() && View.bHasCustomDepthPrimitives) { if (PrimaryNaniteRasterResults.IsValidIndex(ViewIndex)) { const FNaniteVisibilityResults& VisibilityResults = PrimaryNaniteRasterResults[ViewIndex].VisibilityResults; // Get the Nanite instance draw list for this view. (NOTE: Always use view index 0 for now because we're not doing // multi-view yet). NaniteDrawLists[ViewIndex] = BuildNaniteCustomDepthDrawList(View, 0u, VisibilityResults); TotalNaniteInstances += NaniteDrawLists[ViewIndex].Num(); } bAnyCustomDepth = true; } } SET_DWORD_STAT(STAT_NaniteCustomDepthInstances, TotalNaniteInstances); .. if (TotalNaniteInstances > 0) { RDG_EVENT_SCOPE(GraphBuilder, "Nanite CustomDepth"); const FIntPoint RasterTextureSize = CustomDepthTextures.Depth->Desc.Extent; FIntRect RasterTextureRect(0, 0, RasterTextureSize.X, RasterTextureSize.Y); if (Views.Num() == 1) { const FViewInfo& View = Views[0]; if (View.ViewRect.Min.X == 0 && View.ViewRect.Min.Y == 0) { RasterTextureRect = View.ViewRect; } } const bool bWriteCustomStencil = IsCustomDepthPassWritingStencil(); Nanite::FSharedContext SharedContext{}; SharedContext.FeatureLevel = Scene->GetFeatureLevel(); SharedContext.ShaderMap = GetGlobalShaderMap(SharedContext.FeatureLevel); SharedContext.Pipeline = Nanite::EPipeline::Primary; // TODO: If !bWriteCustomStencil, we could copy off the depth and rasterize depth-only (probable optimization) //初始化Nanite::FRasterContext RasterContext。 Nanite::FRasterContext RasterContext = Nanite::InitRasterContext( GraphBuilder, SharedContext, ViewFamily, RasterTextureSize, RasterTextureRect, false, // bVisualize Nanite::EOutputBufferMode::VisBuffer, true, // bClearTarget nullptr, // RectMinMaxBufferSRV 0, // NumRects nullptr, // ExternalDepthBuffer true // bCustomPass ); //用于构建FCustomDepthContext结构体,创建对应的贴图资源。主要包含了InputDepth、InputStencilSRV、DepthTarget、StencilTarget以及bComputeExport(是否使用ComputeShader输出)。 Nanite::FCustomDepthContext CustomDepthContext = Nanite::InitCustomDepthStencilContext( GraphBuilder, CustomDepthTextures, bWriteCustomStencil); Nanite::FConfiguration CullingConfig = { 0 };//Nanite剔除设置,用的较多的是bUpdateStreaming、bPrimaryContext、bTwoPassOcclusion,设置为true。 CullingConfig.bUpdateStreaming = true; for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex) { RDG_EVENT_SCOPE_CONDITIONAL(GraphBuilder, Views.Num() > 1, "View%d", ViewIndex); FViewInfo& View = Views[ViewIndex]; if (!View.ShouldRenderView() || NaniteDrawLists[ViewIndex].Num() == 0) { continue; } //创建Nanite渲染器 auto NaniteRenderer = Nanite::IRenderer::Create( GraphBuilder, *Scene, View, GetSceneUniforms(), SharedContext, RasterContext, CullingConfig, View.ViewRect, /* PrevHZB = */ nullptr ); NaniteRenderer->DrawGeometry( Scene->NaniteRasterPipelines[ENaniteMeshPass::BasePass], PrimaryNaniteRasterResults[ViewIndex].VisibilityResults, *Nanite::FPackedViewArray::Create(GraphBuilder, PrimaryNaniteViews[ViewIndex]), NaniteDrawLists[ViewIndex] ); Nanite::FRasterResults RasterResults; NaniteRenderer->ExtractResults( RasterResults ); // Emit depth Nanite::EmitCustomDepthStencilTargets( GraphBuilder, *Scene, View, RasterResults.PageConstants, RasterResults.VisibleClustersSWHW, RasterResults.ViewsBuffer, RasterContext.VisBuffer64, CustomDepthContext ); } Nanite::FinalizeCustomDepthStencil(GraphBuilder, CustomDepthContext, CustomDepthTextures); } ... } ``` - Nanite::InitRasterContext():初始化Nanite::FRasterContext RasterContext。 - Nanite::InitCustomDepthStencilContext():位于NaniteMaterials.cpp,用于构建FCustomDepthContext结构体,创建对应的贴图资源。主要包含了InputDepth、InputStencilSRV、DepthTarget、StencilTarget以及bComputeExport(是否使用ComputeShader输出)。 - auto NaniteRenderer = Nanite::IRenderer::Create():创建Nanite渲染器 - NaniteRenderer->DrawGeometry():Nanite物体绘制 - NaniteRenderer->ExtractResults( RasterResults ):提取渲染结果。 - ***Nanite::EmitCustomDepthStencilTargets()***:使用提取到的Nanite::FRasterResults RasterResults,输出CustomDepth。结果存储在 FCustomDepthContext& CustomDepthContext中。 - FDepthExportCS / FEmitCustomDepthStencilPS - Nanite::FinalizeCustomDepthStencil():将CustomDepthContext中的结果输出到CustomDepthTextures上。 ## BasePass Nanite 1. Render()中向RenderBasePass()传入const TArrayView& NaniteRasterResults。 2. 调用Lambda RenderNaniteBasePass(),本质上是调用Nanite::DrawBasePass()进行渲染。