diff --git a/03-UnrealEngine/Rendering/RenderingPipeline/Materials/材质中PassSwitch节点实现方式.md b/03-UnrealEngine/Rendering/RenderingPipeline/Materials/材质中PassSwitch节点实现方式.md new file mode 100644 index 0000000..cd2edcd --- /dev/null +++ b/03-UnrealEngine/Rendering/RenderingPipeline/Materials/材质中PassSwitch节点实现方式.md @@ -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 +``` \ No newline at end of file