vault backup: 2024-11-14 12:59:18

This commit is contained in:
2024-11-14 12:59:18 +08:00
parent 0e5712546f
commit 39c710b19c
4 changed files with 91 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
---
title: 未命名
date: 2022-09-04 19:50:57
excerpt:
tags:
rating: ⭐
---
可以使用DrawDynamicMeshPass()实现在插件中使用MeshDraw绘制Pass。

View File

@@ -0,0 +1,258 @@
---
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
# NaniteMeshDraw
`Engine\Source\Runtime\Renderer\Private\Nanite\`NaniteMaterials.h & NaniteMaterials.cpp
PS.使用的Shader必须是`FNaniteGlobalShader`的子类。
## 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);

View File

@@ -0,0 +1,91 @@
---
title: Untitled
date: 2024-11-14 12:19:36
excerpt:
tags:
rating: ⭐
---
# 前言
探索思路:
- [ ] SceneProxy收集机制的改变。
- [ ] GetDynamicMeshElements的调用方式。
- [ ] 在SendRenderDynamicData_Concurrent中添加模仿USkeletalMeshComponent::SendRenderDynamicData_Concurrent()与FDebugSkelMeshSceneProxy
# GetDynamicMeshElements
看得出主要在FDynamicMeshElementContext::GatherDynamicMeshElementsForPrimitive()中调用Primitive->Proxy->GetDynamicMeshElements()。
```c++
UE::Tasks::FTask FDynamicMeshElementContext::LaunchAsyncTask(FDynamicPrimitiveIndexQueue* PrimitiveIndexQueue, UE::Tasks::ETaskPriority TaskPriority)
{
return Pipe.Launch(UE_SOURCE_LOCATION, [this, PrimitiveIndexQueue]
{
FOptionalTaskTagScope Scope(ETaskTag::EParallelRenderingThread);
FDynamicPrimitiveIndex PrimitiveIndex;
while (PrimitiveIndexQueue->Pop(PrimitiveIndex))
{
GatherDynamicMeshElementsForPrimitive(Primitives[PrimitiveIndex.Index], PrimitiveIndex.ViewMask);
}
#if WITH_EDITOR
while (PrimitiveIndexQueue->PopEditor(PrimitiveIndex))
{
GatherDynamicMeshElementsForEditorPrimitive(Primitives[PrimitiveIndex.Index], PrimitiveIndex.ViewMask);
}
#endif
}, TaskPriority);
}
void FDynamicMeshElementContext::GatherDynamicMeshElementsForPrimitive(FPrimitiveSceneInfo* Primitive, uint8 ViewMask)
{
SCOPED_NAMED_EVENT(DynamicPrimitive, FColor::Magenta);
TArray<int32, TInlineAllocator<4>> MeshBatchCountBefore;
MeshBatchCountBefore.SetNumUninitialized(Views.Num());
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
MeshBatchCountBefore[ViewIndex] = MeshCollector.GetMeshBatchCount(ViewIndex);
}
MeshCollector.SetPrimitive(Primitive->Proxy, Primitive->DefaultDynamicHitProxyId);
// If Custom Render Passes aren't in use, there will be only one group, which is the common case.
if (ViewFamilyGroups.Num() == 1 || Primitive->Proxy->SinglePassGDME())
{
Primitive->Proxy->GetDynamicMeshElements(FirstViewFamily.AllViews, FirstViewFamily, ViewMask, MeshCollector);
}
else
{
for (FViewFamilyGroup& Group : ViewFamilyGroups)
{
if (uint8 MaskedViewMask = ViewMask & Group.ViewSubsetMask)
{
Primitive->Proxy->GetDynamicMeshElements(FirstViewFamily.AllViews, *Group.Family, MaskedViewMask, MeshCollector);
}
}
}
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
FViewInfo& View = *Views[ViewIndex];
if (ViewMask & (1 << ViewIndex))
{
FDynamicPrimitive& DynamicPrimitive = DynamicPrimitives.Emplace_GetRef();
DynamicPrimitive.PrimitiveIndex = Primitive->GetIndex();
DynamicPrimitive.ViewIndex = ViewIndex;
DynamicPrimitive.StartElementIndex = MeshBatchCountBefore[ViewIndex];
DynamicPrimitive.EndElementIndex = MeshCollector.GetMeshBatchCount(ViewIndex);
}
}
}
```
# SendRenderDynamicData_Concurrent
## FDebugSkelMeshSceneProxy::GetDynamicMeshElements
# 其他?
MeshBuilderSurface.GetMesh(GetLocalToWorld(), MatProxySurface, SDPG_Foreground, false, false, ViewIndex, Collector);

View File

@@ -0,0 +1,154 @@
---
title: Untitled
date: 2024-09-23 19:47:03
excerpt:
tags:
rating: ⭐
---
# ShadowPassSwitch
## Cpp
MaterialExpressionShadowReplace.h
MaterialExpressions.cpp
```c++
int32 UMaterialExpressionShadowReplace::Compile(class FMaterialCompiler* Compiler, int32 OutputIndex)
{
if (!Default.GetTracedInput().Expression)
{
return Compiler->Errorf(TEXT("Missing input Default"));
}
else if (!Shadow.GetTracedInput().Expression)
{
return Compiler->Errorf(TEXT("Missing input Shadow"));
}
else
{
const int32 Arg1 = Default.Compile(Compiler);
const int32 Arg2 = Shadow.Compile(Compiler);
return Compiler->ShadowReplace(Arg1, Arg2);
}
}
```
MaterialCompiler.h => **HLSLMaterialTranslator.cpp**
```c++
int32 FHLSLMaterialTranslator::ShadowReplace(int32 Default, int32 Shadow)
{
return GenericSwitch(TEXT("GetShadowReplaceState()"), Shadow, Default);
}
```
```c++
int32 FHLSLMaterialTranslator::GenericSwitch(const TCHAR* SwitchExpressionText, int32 IfTrue, int32 IfFalse)
{
if (IfTrue == INDEX_NONE || IfFalse == INDEX_NONE)
{
return INDEX_NONE;
}
// exactly the same inputs on both sides - no need to generate anything extra
if (IfTrue == IfFalse)
{
return IfTrue;
}
FMaterialUniformExpression* IfTrueExpression = GetParameterUniformExpression(IfTrue);
FMaterialUniformExpression* IfFalseExpression = GetParameterUniformExpression(IfFalse);
if (IfTrueExpression &&
IfFalseExpression &&
IfTrueExpression->IsConstant() &&
IfFalseExpression->IsConstant())
{
FMaterialRenderContext DummyContext(nullptr, *Material, nullptr);
FLinearColor IfTrueValue;
FLinearColor IfFalseValue;
IfTrueExpression->GetNumberValue(DummyContext, IfTrueValue);
IfFalseExpression->GetNumberValue(DummyContext, IfFalseValue);
if (IfTrueValue == IfFalseValue)
{
// If both inputs are wired to == constant values, avoid adding the runtime switch
// This will avoid breaking various offline checks for constant values
return IfTrue;
}
}
// Both branches of '?:' need to be the same type
const EMaterialValueType ResultType = GetArithmeticResultType(IfTrue, IfFalse);
const FString IfTrueCode = CoerceParameter(IfTrue, ResultType);
const FString IfFalseCode = CoerceParameter(IfFalse, ResultType);
if (IsLWCType(ResultType))
{
AddLWCFuncUsage(ELWCFunctionKind::Other);
return AddCodeChunk(ResultType, TEXT("LWCSelect(%s, %s, %s)"), SwitchExpressionText, *IfTrueCode, *IfFalseCode);
}
else
{
return AddCodeChunk(ResultType, TEXT("(%s ? (%s) : (%s))"), SwitchExpressionText, *IfTrueCode, *IfFalseCode);
}
}
```
>可以看得出最终会编译成(%s ? (%s) : (%s)),也就是 GetShadowReplaceState() ? True的Shader False时的Shader。
## Shader
### Common.ush
```c++
// NOTE: The raytraced implementation of the ShadowPassSwitch node is kept in RayTracingShaderUtils.ush as it needs to access per ray information.
#if RAYHITGROUPSHADER == 0
// Experimental way to allow adjusting the OpacityMask for shadow map rendering of masked materials.
// This is exposed via the ShadowPassSwitch material node. This can also be accessed with a Custom
// material node. If this turns out to be very useful we can expose as MaterialFunction
// and potentially expose other queries as well (e.g. SkeletalMesh, HitProxy, ).
// @return 0:no, 1:yes
bool GetShadowReplaceState()
{
#if SHADOW_DEPTH_SHADER
return true;
#else
return false;
#endif
}
float IsShadowDepthShader()
{
return GetShadowReplaceState() ? 1.0f : 0.0f;
}
#endif // RAYHITGROUPSHADER == 0
```
可以看得出主要通过**SHADOW_DEPTH_SHADER**宏进行判断而渲染阴影的Shader ShadowDepthVertexShader.usf&ShadowDepthPixelShader.usf都定义该宏为1。
### NaniteRasterizer.usf
```c++
// This must be defined before including Common.ush (see GetShadowReplaceState)
#define SHADOW_DEPTH_SHADER DEPTH_ONLY
```
在NaniteCullRaster.cpp中DEPTH_ONLY设置为1。
### RayTracingShaderUtils.ush
光追相关
```c++
#ifndef RAYHITGROUPSHADER
#error "This header should only be included in raytracing contexts"
#endif
#ifndef PATH_TRACING // Path Tracing has a similar implemental with a slightly different set of flags
#include "RayTracingCommon.ush"
static int CurrentPayloadInputFlags = 0;
bool GetShadowReplaceState()
{
return (CurrentPayloadInputFlags & RAY_TRACING_PAYLOAD_INPUT_FLAG_SHADOW_RAY) != 0;
}
float IsShadowDepthShader()
{
return GetShadowReplaceState() ? 1.0f : 0.0f;
}
#endif
```