16 KiB
Raw Blame History

title, date, excerpt, tags, rating
title date excerpt tags rating
Untitled 2024-09-25 14:59:32

前言

可以使用DrawDynamicMeshPass()实现在插件中使用MeshDraw绘制Pass。

参考文章:

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 混合因子
FRHIBlendState* CopyBlendState = TStaticBlendState<CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One>::GetRHI();

颜色写入蒙版:

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⊗FsrcCdst⊗Fdst$$
BO_ReverseSubtract $$C = C_{dst} \otimes F_{dst} - C_{src} \otimes F_{src}C=Cdst⊗FdstCsrc⊗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=(1rsrc,1gsrc,1bsrc)
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=(1asrc,1asrc,1asrc) $$F=1-a_{src}F=1asrc$$
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=(1adst,1adst,1adst) $$F=1-a_{dst}F=1adst$$
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=(1rdst,1gdst,1bdst)
BF_ConstantBlendFactor F=(r,g,b)F=(r,g,b) F=aF=a
BF_InverseConstantBlendFactor F=(1-r,1-g,1-b)F=(1r,1g,1b) F=1-aF=1a
BF_Source1Color 未知 未知
BF_InverseSource1Color 未知 未知
BF_Source1Alpha 未知 未知
BF_InverseSource1Alpha 未知 未知

最后四个选项没有在DirectX中找到对应的选项没有继续探究前面的应该足够一般使用了。

FRHIDepthStencilState

TStaticDepthStencilState<
		bEnableDepthWrite,          // 是否启用深度写入
		DepthTest,                  // 深度测试比较函数
		bEnableFrontFaceStencil,    // (正面)启用模板
		FrontFaceStencilTest,       // (正面)模板测试操作
		FrontFaceStencilFailStencilOp, //(正面)模板测试失败时如何更新模板缓冲区
		FrontFaceDepthFailStencilOp,  //(正面)深度测试失败时如何更新模板缓冲区
		FrontFacePassStencilOp,     //(正面)通过模板测试时如何更新模板缓冲区
		bEnableBackFaceStencil,     // (背面)启用模板
		BackFaceStencilTest,        // (背面)模板失败操作
		BackFaceStencilFailStencilOp, //(背面)模板测试失败时如何更新模板缓冲区
		BackFaceDepthFailStencilOp, //(背面)深度测试失败时如何更新模板缓冲区
		BackFacePassStencilOp,      //(背面)通过模板测试时如何更新模板红冲去
		StencilReadMask,            // 模板读取Mask
		StencilWriteMask            // 模板写入Mask
		>
//一般使用这个
TStaticDepthStencilState<true, CF_DepthNearOrEqual>::GetRHI();
//CustomStencil中使用的
TStaticDepthStencilState<true, CF_DepthNearOrEqual, true, CF_Always, SO_Keep, SO_Keep, SO_Replace, false, CF_Always, SO_Keep, SO_Keep, SO_Keep, 255, 255>::GetRHI()

DepthTest

深度测试比较函数。

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),
};
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。

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绘制过程

bool FSceneRenderer::RenderCustomDepthPass(
	FRDGBuilder& GraphBuilder,
	FCustomDepthTextures& CustomDepthTextures,
	const FSceneTextureShaderParameters& SceneTextures,
	TConstArrayView<Nanite::FRasterResults> PrimaryNaniteRasterResults,
	TConstArrayView<Nanite::FPackedView> 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<FNaniteCustomDepthDrawList, SceneRenderingAllocator> 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::InitRasterContext(
			GraphBuilder,
			SharedContext,
			ViewFamily,
			RasterTextureSize,
			RasterTextureRect,
			false, // bVisualize
			Nanite::EOutputBufferMode::VisBuffer,
			true, // bClearTarget
			nullptr, // RectMinMaxBufferSRV
			0, // NumRects
			nullptr, // ExternalDepthBuffer
			true // bCustomPass
		);

		Nanite::FCustomDepthContext CustomDepthContext = Nanite::InitCustomDepthStencilContext(
			GraphBuilder,
			CustomDepthTextures,
			bWriteCustomStencil);

		Nanite::FConfiguration CullingConfig = { 0 };
		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;
			}

			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::FSharedContext存储FGlobalShaderMap、ERHIFeatureLevel、EPipeline的结构体。

  • Nanite::InitRasterContext()
  • Nanite::InitCustomDepthStencilContext()

NaniteRenderer

  1. auto NaniteRenderer = Nanite::IRenderer::Create()
  2. NaniteRenderer->DrawGeometry
  3. NaniteRenderer->ExtractResults( RasterResults );
  4. Nanite::EmitCustomDepthStencilTargets()

Nanite::FinalizeCustomDepthStencil()