Custom Shading Model & Substrate自定义着色模型与 Substrate
Shading Model Architecture着色模型架构
Shading models in UE's deferred pipeline are identified by a 4-bit integer packed into GBufferA's alpha channel (SHADINGMODELID_*). The lighting pass reads this ID and dispatches to the appropriate BRDF evaluation. All existing shading models are defined in ShadingCommon.ush:
UE 延迟管线中的着色模型由打包到 GBufferA Alpha 通道的 4 位整数标识(SHADINGMODELID_*)。光照通道读取此 ID 并分发到相应的 BRDF 计算。所有现有着色模型定义在 ShadingCommon.ush 中:
// Engine/Shaders/Private/ShadingCommon.ush #define SHADINGMODELID_UNLIT 0 #define SHADINGMODELID_DEFAULT_LIT 1 #define SHADINGMODELID_SUBSURFACE 2 #define SHADINGMODELID_PREINTEGRATED_SKIN 3 #define SHADINGMODELID_CLEAR_COAT 4 #define SHADINGMODELID_SUBSURFACE_PROFILE 5 #define SHADINGMODELID_TWOSIDED_FOLIAGE 6 #define SHADINGMODELID_HAIR 7 #define SHADINGMODELID_CLOTH 8 #define SHADINGMODELID_EYE 9 #define SHADINGMODELID_SINGLELAYERWATER 10 #define SHADINGMODELID_THIN_TRANSLUCENT 11 #define SHADINGMODELID_SUBSTRATE 12 #define SHADINGMODELID_NUM 13 // ← max 15 due to 4-bit limit #define SHADINGMODELID_MASK 0xF
GBufferInfo.h and related shaders — a significant engine modification.
4 位硬限制:着色模型 ID 仅 4 位,所以 UE 最多支持 15 个着色模型。当前使用了 12 个(0–12),剩余 3 个槽。如果添加超过 3 个自定义着色模型,还需要扩展 GBufferInfo.h 和相关着色器中的 GBuffer 打包——这是重大的引擎修改。
Adding a Custom Shading Model — Overview添加自定义着色模型 — 概览
Adding a custom shading model requires modifying both C++ and HLSL in at least 6 files. This is a source-level engine modification — it cannot be done in a plugin without engine source access. The modification points are:
添加自定义着色模型需要修改至少 6 个文件中的 C++ 和 HLSL。这是源码级别的引擎修改——没有引擎源码访问权限无法在插件中完成。修改点包括:
Step-by-Step Engine Code Changes分步骤引擎代码修改
Step 1: Define the HLSL ID (ShadingCommon.ush)步骤 1:定义 HLSL ID(ShadingCommon.ush)
// Engine/Shaders/Private/ShadingCommon.ush // Add before SHADINGMODELID_NUM: #define SHADINGMODELID_CUSTOM_NPR 13 ← your new ID #define SHADINGMODELID_NUM 14 ← increment
Step 2: Register in C++ (EngineTypes.h)步骤 2:在 C++ 中注册(EngineTypes.h)
// Engine/Source/Runtime/Engine/Classes/Engine/EngineTypes.h UENUM(BlueprintType) enum EMaterialShadingModel { MSM_Unlit UMETA(DisplayName="Unlit"), MSM_DefaultLit UMETA(DisplayName="Default Lit"), // ... existing entries ... MSM_CustomNPR UMETA(DisplayName="Custom NPR"), ← add here MSM_MAX, }; // Also update GetShadingModelString() in EngineTypes.cpp or MaterialShaderType.cpp
Step 3: Implement the BRDF (ShadingModels.ush)步骤 3:实现 BRDF(ShadingModels.ush)
// Engine/Shaders/Private/ShadingModels.ush // Add a new case in GetShadingModelRequiresBackfaceLighting(), // and add your BRDF function: FDirectLighting CustomNPRShadingBxDF(FGBufferData GBuffer, half3 N, half3 V, half3 L, float Falloff, half NoL, FAreaLight AreaLight, FShadowTerms Shadow) { FDirectLighting Lighting; // Cel shading example: quantize NdotL into ramp steps half RampedNoL = floor(max(0, NoL) * 4.0h) / 4.0h; Lighting.Diffuse = GBuffer.DiffuseColor * RampedNoL * Falloff; Lighting.Specular = 0; // No specular for cel shading Lighting.Transmission = 0; return Lighting; } // In IntegrateBxDF() — the main dispatch function: case SHADINGMODELID_CUSTOM_NPR: return CustomNPRShadingBxDF(GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow);
Step 4: Enable in Material Editor (Material.cpp)步骤 4:在材质编辑器中启用(Material.cpp)
// Engine/Source/Runtime/Engine/Private/Materials/Material.cpp // Add your model to the allowed list for relevant material domains: static bool IsShadingModelAllowed(EMaterialShadingModel ShadingModel, EMaterialDomain Domain, ...) { // MSM_CustomNPR is allowed for Surface domain only if (ShadingModel == MSM_CustomNPR) return Domain == MD_Surface; }
Step 5: GBuffer custom data (GetPrecomputedShadowMasks, etc.)步骤 5:GBuffer 自定义数据
GBufferD (Custom Data) slots are available for storing per-material shading model data. For example, subsurface scattering uses it for the subsurface color. Your NPR model can use it for a ramp texture UVs, outline width, or other parameters.
GBufferD(自定义数据)槽可用于存储每材质着色模型数据。例如,次表面散射用它存储次表面颜色。您的 NPR 模型可以用它存储渐变纹理 UV、轮廓线宽度或其他参数。
GBuffer Packing for Custom Data自定义数据的 GBuffer 打包
// In ShadingModels.ush — SetGBufferForShadingModel() macro: case SHADINGMODELID_CUSTOM_NPR: // Pack custom data into GBufferD.x (available when CustomData input is used) GBuffer.CustomData.x = GetMaterialCustomData0(MaterialParameters); // e.g., ramp scale GBuffer.CustomData.y = GetMaterialCustomData1(MaterialParameters); // e.g., outline width GBuffer.ShadingModelID = SHADINGMODELID_CUSTOM_NPR; break;
NPR Example — Cel Shading with OutlineNPR 示例 — 带轮廓的卡通渲染
A complete NPR cel shading implementation typically combines three elements: a quantized diffuse ramp (implemented in the shading model BRDF above), a rim/fresnel term for stylized specularity, and a screen-space outline pass (typically a separate post-process pass that reads depth/normals to detect edges). The outline pass can be implemented as a custom post-process material or as a dedicated RDG pass injected via a ViewExtension.
完整的 NPR 卡通渲染实现通常结合三个元素:量化漫反射渐变(在上面的着色模型 BRDF 中实现)、用于程式化高光的边缘/菲涅尔项,以及屏幕空间轮廓线通道(通常是读取深度/法线来检测边缘的独立后处理通道)。轮廓线通道可以实现为自定义后处理材质,或通过 ViewExtension 注入的专用 RDG 通道。
Substrate — The Next-Generation Material SystemSubstrate — 下一代材质系统
Substrate (available in UE 5.4+, enabled via r.Substrate=1) replaces the fixed shading model enum with a layered BSDF composition system. Instead of selecting one shading model from a list, artists compose materials from multiple BSDF slabs, each with independent properties (roughness, metallic, subsurface, etc.), blended together with mixing operators.
Substrate(UE 5.4+ 可用,通过 r.Substrate=1 启用)用分层 BSDF 组合系统替代了固定的着色模型枚举。艺术家不再从列表中选择一种着色模型,而是将多个 BSDF 层组合成材质,每层具有独立属性(粗糙度、金属度、次表面等),通过混合运算符混合在一起。
| Legacy Shading Models旧版着色模型 | SubstrateSubstrate | |
|---|---|---|
| Model selection模型选择 | One model per material (dropdown)每材质一个模型(下拉框) | Compose N BSDF slabs with mixing nodes用混合节点组合 N 个 BSDF 层 |
| Car paint车漆 | Clear coat shading model清漆着色模型 | Base metallic slab + clearcoat dielectric slab基础金属层 + 清漆电介质层 |
| Skin皮肤 | Subsurface Profile model次表面轮廓模型 | SSS slab + specular slab + oily top layerSSS 层 + 高光层 + 油脂顶层 |
| GBufferGBuffer | Fixed 3–4 render targets固定 3–4 渲染目标 | Variable-size encoded in a compact Substrate buffer编码在紧凑 Substrate 缓冲区中的可变大小 |
Substrate BSDF Layer ArchitectureSubstrate BSDF 层架构
Substrate stores material data differently from the legacy GBuffer. Each pixel can store multiple BSDF layers in a compact encoded format. The FSubstrateSceneData struct tracks the per-frame Substrate state. The key change for lighting: the deferred lighting pass must now iterate over potentially multiple BSDF slabs per pixel and accumulate contributions from each, rather than dispatching to a single BRDF function.
Substrate 以不同于旧版 GBuffer 的方式存储材质数据。每个像素可以以紧凑编码格式存储多个 BSDF 层。FSubstrateSceneData 结构体跟踪每帧的 Substrate 状态。光照的关键变化:延迟光照通道现在必须遍历每像素的多个 BSDF 层并从每层累积贡献,而不是分发到单个 BRDF 函数。
// Substrate/Substrate.h:106 — per-frame Substrate state struct FSubstrateSceneData { FRDGTextureRef TopLayerTexture; // compact top-layer data (for reflections) FRDGTextureRef MaterialTextureArray; // full material data (multiple BSDFs per pixel) int32 PeelLayersAboveDepth; // for subsurface / translucency peeling uint32 LayerCount; // max active layers // ... }; // Enabling Substrate requires: // 1. r.Substrate=1 in project settings // 2. All materials must be re-saved as Substrate materials // 3. Custom shading models must also be ported to Substrate BSDF nodes
Source Navigation源码导航
- Shaders/Private/ShadingCommon.ush:20
SHADINGMODELID_*define list — add your ID hereSHADINGMODELID_*定义列表 — 在此添加你的 ID - Shaders/Private/ShadingModels.ushIntegrateBxDF() dispatch, all BRDF implementationsIntegrateBxDF() 分发,所有 BRDF 实现
- Shaders/Private/DeferredLightingCommon.ushDeferred lighting loop that calls IntegrateBxDF per pixel调用 IntegrateBxDF 的延迟光照循环
- Engine/Classes/Engine/EngineTypes.h
EMaterialShadingModelenum — add your C++ enum entryEMaterialShadingModel枚举 — 添加 C++ 枚举条目 - Engine/Private/Materials/Material.cppMaterial domain validation, shading model filtering材质域验证、着色模型过滤
- Renderer/Private/Substrate/Substrate.h:106FSubstrateSceneData — per-frame Substrate stateFSubstrateSceneData — 每帧 Substrate 状态
- Shaders/Private/Substrate/SubstrateEvaluation.ushSubstrate BSDF evaluation shadersSubstrate BSDF 评估着色器