UE5.8 Substrate 分层材质系统:把汽车油漆一层层拆开画

📑 目录

UE5.8 Substrate 分层材质系统:把汽车油漆一层层拆开画

引子:老皮卡上的三层烦恼

美术小周接到了一个活儿:给一辆 1980 年代的老皮卡做材质。车身主体是深蓝色金属漆,表面有一层清漆,门把手和轮眉处又要有锈迹渗透出来。听起来不复杂,用传统 PBR 材质做了三天,她却 increasingly 烦躁。

问题出在哪?她用 Base Color 画金属漆底色,Roughness 控制光滑度,然后在 Clear Coat 参数上叠了一层清漆。锈迹用一张 mask 在 Base Color 和 Roughness 之间做线性插值。远看还行,镜头拉近到车门边缘,清漆底下的锈迹和金属漆开始打架:边缘发黑、能量不守恒、金属感一会儿过强一会儿消失。她把 Clear Coat 强度从 0.3 调到 0.8,又调回去,画面始终不对。

TA 阿杰走过来,看了一眼材质节点图:「你这是把油漆、清漆、锈迹当成一个扁平的 PBR 参数集合在 lerp,当然会拧巴。它们本来应该是物理上分开的三层。」

他打开 Project Settings,把 Substrate 开关打开,重启编辑器。十分钟后,小周看到了一个完全不同的节点结构。每个层都有自己的 BSDF,层与层之间用垂直堆叠(Vertical Stacking)连接,光线先在清漆层反射一部分,穿透的部分再碰到金属漆,再往下才会看到锈迹。清漆、金属漆、锈迹各自的光泽度和颜色不再互相吞噬。

Substrate 就是干这个的。它不是给传统材质加了几个新参数,而是换了一种描述材质的方式。


一、传统 PBR 材质的问题在哪里

传统 PBR 工作流里,一个材质球由一组标量参数定义:Base Color、Metallic、Specular、Roughness、Normal、Clear Coat、Clear Coat Roughness 等等。这些参数描述的是「整个表面看起来像什么」,而不是「这个表面由哪些物理层组成」。

当美术想把几种材质混在一起时,通常的做法是用 mask 做参数插值。比如:

Colorfinal=MaskColorpaint+(1Mask)ColorrustColor_{final} = Mask \cdot Color_{paint} + (1 - Mask) \cdot Color_{rust}

这种做法有两个根本问题。

第一,能量不守恒。两个材质单独看都没问题,lerp 之后反射能量的总和可能超过入射光。金属漆的 F0F_0 本来已经很高,再和锈迹的高粗糙度区域一混,某些角度会出现不自然的过曝或发黑。

第二,层的物理顺序被丢掉了。清漆应该在金属漆外面,锈迹应该在金属漆破损处。用 mask lerp 参数时,清漆和锈迹被压在同一深度,结果清漆的光泽会覆盖到锈迹上,锈迹的粗糙又会污染清漆边缘。

Substrate 的解决思路很直接:材质由若干层 BSDF 垂直堆叠而成,每层有自己的厚度、吸收特性和散射行为,光线按真实顺序与每一层交互。

flowchart TD
    A[入射光线] --> B{传统 PBR}
    A --> C{Substrate}
    B --> D[单组参数]
    D --> E[Mask Lerp 混合]
    E --> F[能量不守恒 层序混乱]
    C --> G[BSDF 层 A]
    G --> H[BSDF 层 B]
    H --> I[BSDF 层 C]
    I --> J[按物理顺序计算光线路径]

二、Substrate 的核心:BSDF 层

在 Substrate 中,材质的最小单位不再是「参数集合」,而是 BSDF 层(BSDF Layer)。每个层描述光线如何与该层交互:一部分被反射,一部分被吸收,还有一部分可能透射到下一层。

一个 Substrate 材质的输出由根节点 SubstrateGraph 定义,下面挂着若干 BSDF 节点。每个 BSDF 节点本身可以带颜色、粗糙度、法线、厚度等输入。不同 BSDF 节点之间通过 Horizontal MixVertical Stack 连接。

architecture-beta
    group substrate[Substrate 材质评估]
    service root as SubstrateGraph in substrate
    service slab1 as Slab 金属漆 in substrate
    service coat as Slab 清漆 in substrate
    service fuzz as Fuzz 绒毛 in substrate
    service metal as Metal 金属 in substrate
    service mix as Vertical Stack in substrate
    service out as 像素输出
    
    root:B --> mix:T
    coat:B --> slab1:T
    slab1:B --> metal:T
    fuzz:R --> coat:L
    mix:B --> out:T

上图中,SubstrateGraph 是入口。Vertical Stack 把清漆、金属漆、金属层按从上到下的顺序压成一摞。Fuzz 作为一个侧向贡献挂在清漆旁边,模拟表面的细小绒毛或灰尘。这种结构在传统材质里很难表达。


三、Substrate 支持的 BSDF 类型

UE5.8 的 Substrate 提供了几种常用 BSDF 节点,覆盖绝大多数游戏材质需求。

3.1 Slab

Slab 是最常用的 BSDF 类型,可以理解为「一块有厚度的介质薄片」。它描述的是非金属或弱金属的体积材质,支持漫反射、镜面反射、吸收和次表面散射。油漆、塑料、石头、木头、皮革都可以用它表达。

Slab 的关键参数包括:

  • Diffuse Albedo:漫反射颜色;
  • Specular:镜面反射强度,默认对应 F0;
  • Roughness:表面粗糙度;
  • Absorption:光线穿过 Slab 时被吸收的量;
  • Thickness:层的厚度,影响吸收和散射的累积效果。

当光线进入 Slab 时,一部分在表面反射,另一部分进入内部,经过吸收和散射后,从另一侧穿出。 absorption 越高、thickness 越大,透过去的颜色就越暗。

3.2 Metal

Metal BSDF 专门描述金属。金属没有漫反射,所有可见颜色来自镜面反射的 tinted 高光。传统 PBR 里用 Metallic 参数在金属和非金属之间切换,其实是对物理现实的一种妥协。Substrate 里的 Metal BSDF 直接建模金属的复折射率,颜色由 Edge Color 和 Base Color 共同决定。

金属的反射率可以用 Fresnel 公式近似:

R(θ)=R0+(1R0)(1cosθ)5R(\theta) = R_0 + (1 - R_0)(1 - \cos\theta)^5

其中 R0R_0 是垂直入射时的反射率,θ\theta 是入射角。金属的 R0R_0 通常远高于非金属,所以边缘会出现强烈的各向异性高光。

3.3 Clear Coat

Clear Coat 本质上也是一种 Slab,只是它的顶部表面更光滑,底部与下一层接触。清漆层会先把一部分光线反射出去,剩余光线进入下面的层。清漆的 Roughness 控制表面光泽度,Thickness 和 Absorption 控制清漆发黄或发蓝的程度。

汽车油漆的标志性效果就来自 Clear Coat 与金属漆层的配合。没有清漆,金属漆看起来会很平;没有金属漆,清漆下面没有内容可折射。

3.4 Fuzz

Fuzz 描述的是材质表面的细小纤维或绒毛,比如天鹅绒、地毯、桃子皮、苔藓。它不是在表面之上加一个简单贴图,而是模拟光线在纤维尖端散射的效果。Fuzz 通常作为侧向输入挂在一个 Slab 旁边,而不是垂直堆叠在表面之上。

Fuzz 的颜色、密度和方向都会影响最终外观。密度高时,表面看起来像天鹅绒;密度低时,只在轮廓边缘出现一圈柔和的光晕。

3.5 其他 BSDF

UE5.8 还继续扩展了 Substrate 的 BSDF 家族,包括:

  • Unlit:自发光或纯颜色层;
  • Hair:用于头发模型,支持多次散射;
  • Single Layer Water:简化版水面材质;
  • Atmosphere/Cloud:与体积云相关的特殊 BSDF。

对于绝大多数道具和角色材质,Slab + Metal + Clear Coat + Fuzz 已经够用了。


四、水平混合与垂直堆叠

Substrate 提供了两种把 BSDF 组合起来的方式:Horizontal Mix 和 Vertical Stack。理解它们的区别是做好分层材质的前提。

4.1 Horizontal Mix

Horizontal Mix 按 mask 把两个 BSDF 在水平方向混合。它适合表达「同一表面上有两种不同材质并排存在」,比如石头地面上局部有青苔,金属板上局部有锈迹。

Horizontal Mix 仍然使用 mask,但混合的是 BSDF 本身,而不是底层参数。这意味着每一层都保持自己的能量守恒特性。lerp 的结果不会像传统 PBR 那样出现反射能量异常。

4.2 Vertical Stack

Vertical Stack 是把两层 BSDF 在物理深度上摞起来。上层在表面,下层在底下。光线先与上层交互,没被反射和吸收的部分再进入下层。

sequenceDiagram
    participant L as 入射光线
    participant C as Clear Coat 层
    participant P as 金属漆 Slab
    participant R as 锈迹 Slab
    participant O as 最终出射光
    L->>C: 到达表面
    C-->>O: 部分直接反射(清漆高光)
    C->>P: 穿透部分进入金属漆
    P-->>O: 部分反射(金属漆颜色)
    P->>R: 继续穿透到达锈迹
    R-->>O: 反射或吸收
    O->>O: 各层贡献按物理顺序累加

汽车油漆就是典型的 Vertical Stack。清漆在最上面,金属漆在中间,底漆或金属基板在最下面。锈迹如果只在局部出现,可以用 Horizontal Mix 把「完好油漆栈」和「破损锈迹栈」混合起来。

4.3 能量守恒怎么处理

Substrate 在内部维护能量守恒。当两层垂直堆叠时,上层反射走一部分能量,透射给下层的能量会自动衰减。衰减量由 BSDF 的反射率、吸收率和厚度决定。

对于两层系统,最终出射光可以粗略写成:

Lout=Lreflectedtop+TtopLreflectedbottomL_{out} = L_{reflected}^{top} + T_{top} \cdot L_{reflected}^{bottom}

其中 LreflectedtopL_{reflected}^{top} 是上层的反射光,TtopT_{top} 是上层对下层光线的透射系数。Substrate 在运行时自动保证 R+T+A1R + T + A \leq 1,其中 AA 是吸收部分。


五、实战:做一辆老皮卡的多层车漆

回到小周的老皮卡。我们用 Substrate 重新搭建它的车身材质。

5.1 层结构设计

车身主体需要三层:

  1. 最外层是 Clear Coat,光滑、低粗糙度、略带厚度;
  2. 中间是 金属漆 Slab,深蓝色、金属颗粒感、中等粗糙度;
  3. 最底层是 金属基板 Metal,在油漆剥落处露出来。

锈迹只在门把手、轮眉、保险杠局部出现。我们用一张 Rust Mask 做 Horizontal Mix,一边是「清漆 + 金属漆 + 金属基板」的完整栈,另一边是「锈迹 Slab + 金属基板」的破损栈。

graph TD
    A[SubstrateGraph] --> B[Horizontal Mix]
    B -->|Mask 0| C[Vertical Stack]
    B -->|Mask 1| D[Vertical Stack]
    C --> C1[Clear Coat]
    C --> C2[金属漆 Slab]
    C --> C3[金属基板 Metal]
    D --> D1[锈迹 Slab]
    D --> D2[金属基板 Metal]

5.2 节点搭建步骤

第一步,创建 Material,把 Shading Model 从 Default Lit 改为 Substrate。

第二步,拖一个 Substrate Slab 节点作为金属漆。参数大致如下:

  • Diffuse Albedo:深蓝色,略带饱和度;
  • Specular:0.5 左右;
  • Roughness:0.25,用一张 microflake 噪波贴图扰动,模拟金属漆里的云母片;
  • Normal:细颗粒法线,模拟金属漆的橘皮效果。

第三步,拖一个 Substrate Slab 节点作为清漆。参数:

  • Diffuse Albedo:接近纯白;
  • Roughness:0.05 到 0.1;
  • Thickness:0.1 到 0.3 毫米;
  • Absorption:极少量黄色,模拟旧清漆轻微发黄。

第四步,拖一个 Substrate Metal 节点作为金属基板。颜色用冷灰色,Edge Color 稍微偏蓝。

第五步,用 Vertical Stack 节点把清漆、金属漆、金属基板按顺序连接起来。Vertical Stack 的上接口接上层,下接口接下层。

第六步,再建一组破损栈:一个 Substrate Slab 作为锈迹,颜色偏橙棕,Roughness 较高,Absorption 较强;下面同样接金属基板。

第七步,用 Horizontal Mix 节点把完整栈和破损栈按 Rust Mask 混合。Rust Mask 是一张手绘的黑白图,白色表示锈迹区域。

第八步,把 Horizontal Mix 的输出连到 SubstrateGraph 的 Substrate 引脚。

5.3 关键细节

金属漆里的 microflake 效果不要靠把 Roughness 拉到极低来实现。真正的金属漆在正面看比较光滑,侧面看会因为云母片而变粗糙。可以用 View AngleFresnel 节点对 Roughness 做角度修正:

Roughnesseff(θ)=Roughnessbase+k(1cosθ)Roughness_{eff}(\theta) = Roughness_{base} + k \cdot (1 - \cos\theta)

其中 kk 控制侧面粗糙度增加的幅度。这样正面看是清亮的,侧面看有柔和的金属闪烁。

清漆的 Thickness 不是越大越好。太厚会让颜色发闷,像一层塑料壳。老皮卡的清漆经过多年风化,厚度应该偏低,Absorption 略带黄色,边缘会有细微剥落。

锈迹和清漆的交界处不要做得太硬。Rust Mask 应该用高斯模糊或手绘笔刷过渡,让锈迹看起来是从清漆裂缝里渗出来的,而不是贴上去的一块贴纸。

5.4 调试时常看的参数

[/Script/Engine.RendererSettings]
r.Substrate=1
r.Substrate.Debug=1
r.Substrate.MaterialGraph=1
r.Substrate.Visualization=1
  • r.Substrate.Debug:打开 Substrate 调试视图,看每层 BSDF 的能量贡献;
  • r.Substrate.Visualization:切换不同可视化模式,检查层堆叠是否正确;
  • r.Substrate.MaterialGraph:在材质编辑器里显示更多 Substrate 专用节点。

小周用 r.Substrate.Debug 一看,发现清漆层的反射能量在某些角度被金属漆层重复计算了。她把清漆的 Specular 从 0.6 降到 0.45,金属漆的 Roughness 从 0.2 提到 0.28,画面立刻自然了很多。


六、性能与平台考虑

Substrate 带来更真实的分层效果,但也不是免费午餐。理解它的开销结构,才能在项目里正确取舍。

6.1 着色复杂度

传统材质只有一个 BSDF 计算路径。Substrate 材质如果有三层 Vertical Stack,像素着色器需要依次评估每层 BSDF,并把结果按能量守恒合并。层数越多,ALU 开销越大。

粗略估算,一个有 NN 层 BSDF 的 Substrate 材质的像素着色成本大约是:

CpixelNCBSDF+CstackC_{pixel} \approx N \cdot C_{BSDF} + C_{stack}

其中 CBSDFC_{BSDF} 是单层的 BSDF 评估成本,CstackC_{stack} 是层合并的固定开销。如果每层还带了独立的法线贴图和粗糙度贴图,采样成本也会线性增长。

6.2 内存占用

Substrate 材质需要存储每层的参数和中间结果。在 G-Buffer 中,Substrate 占用的通道比传统 PBR 更多。具体数量取决于当前启用的 Substrate 功能和平台,但通常会比 Default Lit 多 1-2 个 render target。

在内存紧张的平台上,比如 Switch 2 或低端移动设备,要控制 Substrate 材质的使用范围。 hero assets 和重要角色可以用,远景道具和小物件尽量用传统材质。

6.3 平台支持

Substrate 在 UE5.8 中默认在所有支持 SM5 和 SM6 的平台上可用。PlayStation 5 和 Xbox Series X|S 上运行良好。PC 上需要 DX12 或 Vulkan。

移动平台要谨慎。高端移动芯片可以跑 Substrate,但性能和发热会明显上升。项目需要在 Scalability 配置中为不同平台设置开关。

[/Script/Engine.RendererSettings]
r.Substrate.Mobile=0
r.Substrate.Quality=2
  • r.Substrate.Mobile:在移动平台是否启用 Substrate;
  • r.Substrate.Quality:Substrate 质量级别,0 是最低,3 是最高。

6.4 一个性能测试案例

阿杰在 RTX 3070 上测试了老皮卡材质。车身用了三层 Substrate 加上 Fuzz 模拟顶棚织物,地面和远景道具保持 Default Lit。结果:

  • Base Pass 中 Substrate 材质占比 12%;
  • 单个 Substrate 材质的像素着色成本约为传统材质的 2.3 倍;
  • 如果把全车都换成 Substrate,帧率从 62 掉到 48;
  • 只在车身、轮毂、挡风玻璃三个关键部位用 Substrate,帧率稳定在 58。

这个对比说明:Substrate 应该用在玩家会近距离观察、光照交互复杂的表面,而不是 blanket 覆盖。


七、UE5.8 中 Substrate 的新改进

Substrate 在 UE5.0 就已经作为实验功能出现,到 UE5.8 已经成熟到可以在生产环境大规模使用。5.8 版本的改进主要集中在稳定性、性能和工具链三个方面。

7.1 编辑器集成更完整

5.8 的材质编辑器对 Substrate 节点做了重新整理。节点颜色、分类和预览方式都比早期版本更直观。新建 Material 时可以直接选择 Substrate Shading Model,不再需要手动改 ini。

材质预览窗口增加了 Substrate 专用的可视化层。美术可以直接看到每一层 BSDF 对最终颜色的贡献,调试分层效果时不再需要打开复杂的调试命令。

7.2 性能优化

5.8 对 Substrate 的像素着色器做了进一步压缩。对于常见的 Slab + Clear Coat + Metal 三层组合,编译后的指令数比 5.7 减少了约 15%。在主机平台上,这个优化能直接换算成帧时间。

同时,Substrate 的 G-Buffer 布局在 5.8 中更紧凑。某些质量级别下占用的 render target 通道数减少,缓解了 VRAM 压力。

7.3 与 Lumen、Nanite 的协同

Substrate 和 Lumen 的配合在 5.8 中更稳定。Lumen 的 Surface Cache 能正确捕获 Substrate 材质的能量分布,间接光在多层材质上的表现更准确。

Nanite 与 Substrate 也没有冲突。Substrate 材质可以应用在高面数的 Nanite 网格上,只要注意材质复杂度不要随着面数一起失控。

7.4 新的 BSDF 和混合模式

5.8 继续扩展 BSDF 库。一些在 5.7 中还是实验性的 BSDF,比如改进后的 Hair 和 Single Layer Water,在 5.8 中转为正式可用。Vertical Stack 的性能和正确性也有提升,多层堆叠时更少出现边缘 artifact。

7.5 迁移工具

把传统 PBR 材质迁移到 Substrate 时,5.8 提供了更好的辅助工具。编辑器可以把一个 Default Lit 材质自动转换为等价的 Substrate 材质节点。转换结果不一定完美,但能省去大量手工重建节点的时间。

阿杰测试了一下迁移工具:一个简单的金属材质转换后基本可用,但带 Clear Coat 的材质需要手动调整清漆层的 Thickness 和 Absorption。自动转换只能做 70% 的工作,剩下 30% 还需要美术介入。


八、常见问题与排坑

8.1 层数太多导致编译失败

Substrate 对层数没有硬性上限,但材质编译器会对过复杂的材质报错。如果你收到「Material too complex for current platform」的提示,先减少 BSDF 层数,或者把不重要的层合并到贴图里。

8.2 黑色边缘或 halo

黑色边缘通常出现在 Horizontal Mix 的 mask 边界。原因是 mask 没有经过 anti-aliased 处理,或者两层 BSDF 的 Roughness 差异太大。把 mask 用稍微模糊的版本,或者在 mask 边缘做 slight 羽化,可以缓解。

8.3 清漆看起来不像清漆

清漆不亮的常见原因有三个:Roughness 太高、Thickness 太大、Specular 太低。汽车清漆的 Roughness 通常在 0.03 到 0.1 之间。Thickness 用 0.05 到 0.2 毫米即可,太大反而像琥珀。

8.4 性能 profiler 看哪里

stat GPU 查看 Base Pass 开销。Substrate 材质的额外成本主要集中在 Base Pass。如果 Base Pass 占整帧比例过高,优先减少 Substrate 材质的屏幕覆盖面积,而不是先降分辨率。


九、写在最后

小周的老皮卡最后通过了美术总监的评审。镜头贴着车门滑过去,清漆层在太阳下闪着细碎的眩光,金属漆的深蓝色在阴影里沉着,轮眉的锈迹从清漆裂缝里渗出来,边缘没有发黑,也没有发亮。她说不清哪里变了,但整个车看起来像是可以摸得到温度的金属。

Substrate 给美术带来的是一层新的自由度。传统 PBR 的参数是在一个平面上调色,Substrate 则允许你在深度方向上一层层搭建。这种自由对车、漆、布、皮这类多层材质尤其重要。

但它不是必须开的开关。远处的小石子、低面道具、移动平台上大量重复物体,用传统材质仍然更划算。把 Substrate 当成一种精确工具,只在需要物理层叠的地方使用,它才能真正提升画面质量。

阿杰给小周定了一条内部规范:「车身、武器、主要角色、近景道具可以上 Substrate;远景、小杂物、地形第一层用 Default Lit。开了之后必须用 stat GPU 验证,别凭感觉。」

对团队来说,Substrate 最大的价值不是让画面更炫,而是让美术和 TA 不必再在参数 lerp 的泥潭里反复挣扎。油漆就是油漆,清漆就是清漆,锈迹就是锈迹,各层各算各的。光线照上去,该反射的反射,该穿透的穿透,该吸收的吸收。这种物理上的清爽,最终会变成视觉上的真实。

小周现在再做老皮卡,会先画三层结构图,而不是先调 Base Color。阿杰觉得,这比任何参数都重要。


参考与延伸阅读