Shader Architecture — Compilation, Permutations & Material TranslationShader 架构 — 编译、排列组合与材质翻译
Shader Class HierarchyShader 类层级
All shaders in UE inherit from FShader. The hierarchy reflects the shader's scope of use:
UE 中所有 Shader 均继承自 FShader。层级结构反映了 Shader 的使用范围:
| Type类型 | Instances per platform每平台实例数 | Use case使用场景 |
|---|---|---|
| FGlobalShader | 1 per permutation每排列 1 个 | Post-process, compute, screen-space effects后处理、计算、屏幕空间效果 |
| FMaterialShader | 1 per material × permutation每材质 × 排列 1 个 | Material-dependent passes (base pass, shadow depth)依赖材质的通道(Base Pass、阴影深度) |
| FMeshMaterialShader | 1 per (material × VF × permutation)每(材质 × VF × 排列)1 个 | Vertex shaders that need vertex factory data需要顶点工厂数据的顶点着色器 |
DECLARE / IMPLEMENT Macros — Registration SystemDECLARE / IMPLEMENT 宏 — 注册系统
The DECLARE_GLOBAL_SHADER + IMPLEMENT_GLOBAL_SHADER pair is the most common pattern. IMPLEMENT_GLOBAL_SHADER expands to IMPLEMENT_SHADER_TYPE which creates a static FShaderType object and registers it in UE's global shader type registry at static initialization time (before main()). This registry drives the shader compilation job system.
DECLARE_GLOBAL_SHADER + IMPLEMENT_GLOBAL_SHADER 对是最常见的模式。IMPLEMENT_GLOBAL_SHADER 展开为 IMPLEMENT_SHADER_TYPE,在静态初始化时(main() 之前)创建一个静态 FShaderType 对象并注册到 UE 的全局 Shader 类型注册表中。这个注册表驱动着 Shader 编译作业系统。
// === Pattern 1: Global Compute Shader === class FMyBlurCS : public FGlobalShader { DECLARE_GLOBAL_SHADER(FMyBlurCS); // Declares GetStaticType(), ShaderTypeRegistration SHADER_USE_PARAMETER_STRUCT(FMyBlurCS, FGlobalShader); // Use parameter struct system BEGIN_SHADER_PARAMETER_STRUCT(FParameters, ) SHADER_PARAMETER_RDG_TEXTURE(Texture2D, Input) SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, Output) SHADER_PARAMETER(FVector4f, BlurParams) END_SHADER_PARAMETER_STRUCT() // Static dispatch: can this permutation compile on this platform? static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& P) { return IsFeatureLevelSupported(P.Platform, ERHIFeatureLevel::SM5); } // Optional: inject defines into the compile environment static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& P, FShaderCompilerEnvironment& Env) { FGlobalShader::ModifyCompilationEnvironment(P, Env); Env.SetDefine(TEXT("KERNEL_RADIUS"), 5); } }; // Registers at static init: source file, entry point, shader frequency IMPLEMENT_GLOBAL_SHADER(FMyBlurCS, "/Engine/Private/MyBlur.usf", "MainCS", SF_Compute); // IMPLEMENT_GLOBAL_SHADER expands to IMPLEMENT_SHADER_TYPE which calls (Shader.h:1754): // new ShaderMetaType(StaticGetTypeLayout(), "FMyBlurCS", SourceFile, FunctionName, // Frequency, PermutationCount, ...);
Permutation Domain System — Compile-Time Shader Variants排列组合域系统 — 编译时 Shader 变体
Shader permutations let a single HLSL file compile into multiple variants, each with different #define values. The permutation domain is a C++ type that describes all dimensions. The total shader count = product of all dimension counts. UE compiles all permutations upfront and caches them in the DDC.
Shader 排列允许单个 HLSL 文件编译为多个变体,每个变体具有不同的 #define 值。排列组合域是描述所有维度的 C++ 类型。总 Shader 数 = 所有维度数量的乘积。UE 预先编译所有排列并在 DDC 中缓存它们。
// === Permutation Domain declaration === class FMyLightingCS : public FGlobalShader { DECLARE_GLOBAL_SHADER(FMyLightingCS); SHADER_USE_PARAMETER_STRUCT(FMyLightingCS, FGlobalShader); // Each dimension becomes a #define in the shader class FUseHairTransmittance : SHADER_PERMUTATION_BOOL("USE_HAIR_TRANSMITTANCE"); class FNumShadowCascades : SHADER_PERMUTATION_INT("NUM_SHADOW_CASCADES", 4); // values 0-3 class FShadingModelDim : SHADER_PERMUTATION_ENUM_CLASS("SHADING_MODEL", EMyModel); // Combine into a domain — total = 2 × 4 × EMyModel::MAX variants using FPermutationDomain = TShaderPermutationDomain<FUseHairTransmittance, FNumShadowCascades, FShadingModelDim>; // Prune unnecessary permutations (reduces compile count) static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& P) { FPermutationDomain Domain(P.PermutationId); // Skip hair transmittance on mobile (feature not supported) if (Domain.Get<FUseHairTransmittance>() && !IsFeatureLevelSupported(P.Platform, ERHIFeatureLevel::SM5)) return false; return true; } }; // At runtime: select the right permutation and retrieve the compiled shader FMyLightingCS::FPermutationDomain PermutationVector; PermutationVector.Set<FMyLightingCS::FUseHairTransmittance>(bHairEnabled); PermutationVector.Set<FMyLightingCS::FNumShadowCascades>(NumCascades); TShaderMapRef<FMyLightingCS> ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel), PermutationVector);
Shader Parameter Binding — The Two SystemsShader 参数绑定 — 两种系统
UE 5 has two parameter binding systems. The modern system uses SHADER_USE_PARAMETER_STRUCT which auto-binds all members from the BEGIN_SHADER_PARAMETER_STRUCT block. The legacy system uses explicit FShaderParameter / FShaderResourceParameter member variables that are manually bound in SetParameters().
UE 5 有两种参数绑定系统。现代系统使用 SHADER_USE_PARAMETER_STRUCT,自动绑定 BEGIN_SHADER_PARAMETER_STRUCT 块中的所有成员。旧版系统使用显式的 FShaderParameter / FShaderResourceParameter 成员变量,在 SetParameters() 中手动绑定。
// === Modern system (RDG-compatible, recommended) === class FModernShaderCS : public FGlobalShader { DECLARE_GLOBAL_SHADER(FModernShaderCS); SHADER_USE_PARAMETER_STRUCT(FModernShaderCS, FGlobalShader); // auto-binding BEGIN_SHADER_PARAMETER_STRUCT(FParameters, ) SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, SceneColor) SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<uint>, OutputBuffer) SHADER_PARAMETER_STRUCT_REF(FViewUniformShaderParameters, View) // UB reference SHADER_PARAMETER(float, Exposure) END_SHADER_PARAMETER_STRUCT() }; // === Legacy system (still used in many existing shaders) === class FLegacyShaderCS : public FGlobalShader { DECLARE_GLOBAL_SHADER(FLegacyShaderCS); class FMyParam : public FShaderParameter { ... } class FMyTexture : public FShaderResourceParameter { ... } void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, ...) { // Manually bind each parameter to its RHI slot SetShaderValue(BatchedParameters, FMyParam, SomeValue); SetTextureParameter(BatchedParameters, FMyTexture, SomeTexture); } };
Compilation Pipeline — From Source to Bytecode编译管线 — 从源码到字节码
Shader compilation is asynchronous and multi-threaded. The high-level flow:
Shader 编译是异步多线程的。高级流程:
Material → HLSL Translation (FHLSLMaterialTranslator)材质 → HLSL 翻译(FHLSLMaterialTranslator)
Material graphs in the editor are not shaders — they are node graphs stored as UMaterialExpression objects. The translation from graph → HLSL happens in FHLSLMaterialTranslator (HLSLMaterialTranslator.cpp, 17,000+ lines). This translator walks the expression graph, emitting HLSL code chunks for each node, and assembles them into the final shader template.
编辑器中的材质图不是着色器——它们是存储为 UMaterialExpression 对象的节点图。图 → HLSL 的翻译发生在 FHLSLMaterialTranslator(HLSLMaterialTranslator.cpp,17000+ 行)中。该翻译器遍历表达式图,为每个节点生成 HLSL 代码块,并将它们组装到最终的着色器模板中。
// Translation flow (simplified) // 1. For each material output (BaseColor, Roughness, Normal, etc.), // FHLSLMaterialTranslator recursively translates the connected expression tree: // UMaterialExpressionTextureSample::Compile() → "Texture2DSample(Tex0, Samp0, TexCoord)" // UMaterialExpressionMultiply::Compile() → "(A * B)" // UMaterialExpressionAdd::Compile() → "(A + B)" // // 2. GetMaterialShaderCode() (line 3316) assembles the final HLSL by injecting // generated code chunks into the template: /Engine/Private/MaterialTemplate.ush // This template provides the CalcMaterialParameters(), GetMaterialBaseColor(), etc. functions // // 3. The resulting HLSL is keyed by FMaterialShaderMapId (shader map id hash) // and sent to the shader compiler worker. // // Generated code example for "Multiply(TextureSample, Constant(0.5))": // half3 Local0 = Texture2DSample(Material_Texture2D_0, ..., Parameters.TexCoords[0].xy); // half3 Local1 = 0.5f; // half3 Local2 = (Local0 * Local1); ← output // Key function in FHLSLMaterialTranslator: FString GetMaterialShaderCode() // line 3316 — assembles everything into final HLSL FString GenerateFunctionCode(uint32 Index, ECompiledPartialDerivativeVariation) // per-output code
ShaderMap & CachingShaderMap 与缓存
A ShaderMap is a collection of compiled shader instances for a specific (material, platform, quality level) combination. FMaterialShaderMap and FGlobalShaderMap store shaders indexed by type and permutation. They are serialized to the DDC using a hash key (FMaterialShaderMapId) that captures all inputs that affect compilation — source code hash, platform, quality settings, static parameters.
ShaderMap 是特定(材质、平台、质量级别)组合的编译 Shader 实例集合。FMaterialShaderMap 和 FGlobalShaderMap 按类型和排列索引存储 Shader。它们使用捕获所有影响编译的输入的哈希键(FMaterialShaderMapId)序列化到 DDC——源代码哈希、平台、质量设置、静态参数。
TShaderMapRef — Runtime Shader LookupTShaderMapRef — 运行时 Shader 查找
// Look up a compiled global shader at runtime (render thread) TShaderMapRef<FMyBlurCS> Shader(GetGlobalShaderMap(GMaxRHIFeatureLevel)); // For a specific permutation: FMyLightingCS::FPermutationDomain PermutationVector; PermutationVector.Set<FMyLightingCS::FUseHairTransmittance>(true); TShaderMapRef<FMyLightingCS> LightingShader(GetGlobalShaderMap(GMaxRHIFeatureLevel), PermutationVector); // Dispatch via FComputeShaderUtils (helper wrapper around SetShaderParameters + Dispatch) FComputeShaderUtils::AddFullscreenPass(GraphBuilder, GetGlobalShaderMap(GMaxRHIFeatureLevel), RDG_EVENT_NAME("MyBlur"), Shader, PassParams, FIntVector(DispatchX, DispatchY, 1));
Source Navigation源码导航
- RenderCore/Public/Shader.h:845FShader base class — parameters, bindings, type systemFShader 基类 — 参数、绑定、类型系统
- RenderCore/Public/Shader.h:1754
IMPLEMENT_SHADER_TYPEmacro — static type registrationIMPLEMENT_SHADER_TYPE宏 — 静态类型注册 - RenderCore/Public/GlobalShader.h:274FGlobalShader +
DECLARE/IMPLEMENT_GLOBAL_SHADERFGlobalShader +DECLARE/IMPLEMENT_GLOBAL_SHADER - RenderCore/Public/ShaderPermutation.h:482
SHADER_PERMUTATION_BOOL/INT/ENUM_CLASSmacros排列组合宏定义 - RenderCore/Public/ShaderParameterMacros.hAll
SHADER_PARAMETER_*,BEGIN/END_SHADER_PARAMETER_STRUCTmacros所有参数宏定义 - Engine/Private/Materials/HLSLMaterialTranslator.cpp:3316GetMaterialShaderCode() — final HLSL assembly from expression graphGetMaterialShaderCode() — 从表达式图生成最终 HLSL
- Engine/Private/Materials/HLSLMaterialTranslator.cpp:1042CompileMaterialAttributesCustomOutputs() — per-output translation每输出翻译