413 lines
17 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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<CW_RGB, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_Zero, BF_One>::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⊗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
```c++
TStaticDepthStencilState<
bEnableDepthWrite, // 是否启用深度写入
DepthTest, // 深度测试比较函数
bEnableFrontFaceStencil, // (正面)启用模板
FrontFaceStencilTest, // (正面)模板测试操作
FrontFaceStencilFailStencilOp, //(正面)模板测试失败时如何更新模板缓冲区
FrontFaceDepthFailStencilOp, //(正面)深度测试失败时如何更新模板缓冲区
FrontFacePassStencilOp, //(正面)通过模板测试时如何更新模板缓冲区
bEnableBackFaceStencil, // (背面)启用模板
BackFaceStencilTest, // (背面)模板失败操作
BackFaceStencilFailStencilOp, //(背面)模板测试失败时如何更新模板缓冲区
BackFaceDepthFailStencilOp, //(背面)深度测试失败时如何更新模板缓冲区
BackFacePassStencilOp, //(背面)通过模板测试时如何更新模板红冲去
StencilReadMask, // 模板读取Mask
StencilWriteMask // 模板写入Mask
>
```
```c++
//一般使用这个
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
深度测试比较函数。
```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<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::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<Nanite::FRasterResults>& NaniteRasterResults。
2. 调用Lambda RenderNaniteBasePass()本质上是调用Nanite::DrawBasePass()进行渲染。