--- 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 ```