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
4-bit hard limit: The shading model ID is only 4 bits, so UE supports a maximum of 15 shading models. Currently 12 are used (0–12), leaving 3 slots. If you add more than 3 custom shading models, you must also expand the GBuffer packing in 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 层 + 高光层 + 油脂顶层
GBufferGBufferFixed 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
Substrate is the future of UE materials. Epic is actively migrating all built-in shading models to Substrate. For new projects starting on UE 5.4+, consider designing materials with Substrate from the start. The classic shading model approach still works but will eventually be deprecated. Substrate's main advantage for high-end work: physically correct multi-layer materials (e.g., multi-layer car paint, skin with oily sheen) that were impossible to create in the legacy system. Substrate 是 UE 材质的未来。Epic 正在积极将所有内置着色模型迁移到 Substrate。对于从 UE 5.4+ 开始的新项目,考虑从一开始就使用 Substrate 设计材质。经典着色模型方法仍然有效,但最终将被废弃。Substrate 对高端工作的主要优势:在旧系统中无法创建的物理正确的多层材质(例如,多层车漆、带油脂光泽的皮肤)。

Source Navigation源码导航

Unreal Engine 5.6 · Engine/Shaders/Private/ & Engine/Source/Runtime/Engine/
Source analysis · For learning purposes