上个月帮朋友迁移一个演示工程,引擎从老版本一路升到带Substrate的版本。打开插件后,我第一件事就是想把那套用了很久的传统金属材质换到新材质流程里。结果材质编辑器打开的一瞬间,我猜谁都一样:原来那一排BaseColor、Metallic、Specular、Roughness滑条全没了,取而代之的是一棵参数树,以及一堆看起来更底层的参数名。
我盯着DiffuseAlbedo和F0看了半天,心想“这俩以前不是藏在Metallic后面吗”。后来把Metalness-To-DiffuseAlbedo-F0这个节点用顺手了,才意识到这次迁移不是简单换个节点,而是整个材质参数体系在换骨架。这篇文章就把这个节点彻底讲透。适合正在做Substrate迁移的技术美术、材质美术,以及想弄明白旧PBR和新PBR参数映射关系的图形程序员。
1. 第一次启用Substrate时:材质编辑器里消失的Metalness滑条
1.1 打开老材质后的第一轮混乱
用传统材质模型写了三五年材质的TA,第一次打开Substrate的材质编辑器,大概率会愣一下。原来的Shading Model下拉菜单、Metallic滑条、Specular滑条、Roughness滑条,真的一个都不在了。取而代之的是一大块新的节点类型,比如Substrate Material、Substrate Mixed Material、Substrate Layered Material。你在旧材质里建的节点最终输出是Material Attributes;到了Substrate,最终输出变成了一棵树,树根是一个Slab节点的参数列表,里面直接写着DiffuseAlbedo、F0、Roughness这些名字。
我一开始以为只是改版后把参数收纳进了一个结构体,于是熟门熟路地把老的BaseColor贴图往树里的DiffuseAlbedo一拖,再把旧的Metallic贴图到处找地方塞。结果发现在这个新体系里根本没有名为Metallic的输入位。你按TAB搜索也搜不到金属度这个关键词,能搜到的只有一堆“Metalness To xxx”之类的转换工具节点。换句话说,不只是参数位置变了,而是底层材质模型默认不再使用金属度作为核心输入了。
那一瞬间我是慌的。因为工程里的资产几百个,不可能指望美术团队把每张贴图重画一遍。这也是Substrate必须提供各种转换节点的原因,而所有这些转换节点的起点,就是名字又长又绕的Metalness-To-DiffuseAlbedo-F0。
1.2 一个名字很长的过渡节点,为什么值得单独讲
这个节点的名字已经把它做的事写完了:把传统PBR材质里的Metalness,转换成Substrate需要的DiffuseAlbedo和F0。不同引擎版本的节点命名可能有一点点差别,比如显示成Metalness To DiffuseAlbedo F0,或者Metalness-To-DiffuseAlbedo-F0,但功能基本一致。
为什么值得单独拿出来讲一整篇?因为所有从旧材质迁移到Substrate的资产,几乎都要经过它。它看起来像是一个傻瓜式转换器,接上贴图就能出结果,但我在实际项目里见过太多次错误用法:有人把输出F0当成旧的高光强度再乘一次系数,有人把Metalness贴图留在sRGB空间导致过渡区域脏成一片,还有人完全没搞懂DiffuseAlbedo到底该接到哪个Slab端口。这些错误如果不懂节点内部的参数语义,光靠眼睛看渲染结果是很难定位的。
所以这篇文章的核心不是教你“把A接到B”,而是把节点输入输出背后的物理含义和数学关系彻底拆开,这样你才能判断自己的接线是不是真的正确。
2. 传统PBR为什么需要Metalness:BaseColor一通道承担两种物理身份
2.1 非金属和金属在物理上本来就是两个独立的东西
要理解为什么Substrate要把Metalness消解掉,首先要回到物理层面。非金属,也就是电介质,比如木头、塑料、皮肤、混凝土,它们的光学行为是光进入表面后发生折射、散射,部分光再从表面逸出,表现为漫反射颜色。它们表面的菲涅尔反射率F0非常低,通常在0.02到0.08之间,而且是近似无色的灰,最多带一点点色相偏移。
金属则完全不同。金属是导体,表层自由电子会立即吸收入射光并重新辐射出去,所以金属几乎没有体漫反射,它的反射色直接就是材料本身的“颜色”。铜是暖橙色的高反射,金是黄绿色调的高反射,铝接近中性白高反射。金属的F0可以高得多,常在0.5到1.0之间,而且F0本身就是RGB彩色。
这里可以用一个简单公式理解F0的来源。对于垂直入射的光,F0大体可以由折射率n推算出来:
F0 = ((n - 1) / (n + 1))^2几种常见材料的F0:水大约是0.02,玻璃大约0.04,树脂塑料大约0.04到0.05,钻石因为折射率高,能到0.17以上。这就是为什么传统PBR里非金属的高光永远不应该是纯白或者纯黑,而是一个非常暗的灰。物理世界已经把范围框死了。
金属的漫反射反照率在理论上接近零,因为光根本没有机会进入金属内部发生体散射。这也是为什么金属材质的Albedo贴图画成深色是合理的,但如果你把一个金属物件的高光反射色画进BaseColor里的“漫反射”部分,那就彻底混乱了。
2.2 Metalness把两类参数缝进一条通道,也留了一个隐患
传统PBR为了解决成本问题,发明了Metalness这个标量。它本质上是一个分类开关,0代表非金属,1代表金属,中间值在物理上并不真实存在。美术拿一张BaseColor贴图,同时承担两个身份:当Metalness为0时,BaseColor是漫反射颜色;当Metalness为1时,BaseColor是F0反射颜色。
于是就有了经典近似映射:
diffuseAlbedo = BaseColor * (1 - Metalness) F0 = lerp(f0NonMetal, BaseColor, Metalness)其中f0NonMetal来自旧的Specular参数,默认0.5。而引擎光照模型内部再做一次混合,把漫反射结果和镜面反射结果按Metalness权重混合起来。这个设计在资源上是省了一件大事:一张BaseColor贴图同时记录非金属的固有色和金属的反射色,不需要为金属区域单独画一张F0贴图,也不需要为金属材质单独准备一套漫反射贴图。
但隐患也随之而来。美术在画贴图时必须心知肚明,这个笔刷画出来的深色锈迹,在金属区域会被当作反射色,在非金属区域会被当作体色;同一个数值在不同材质语义下结果天差地别。尤其是很多游戏项目喜欢用“金属、非金属混合在一张贴图”的办法做旧化,比如金属表面有漆面剥落、有灰尘、有锈迹,这时候BaseColor里的某块颜色到底是漫反射还是F0,就成了一笔糊涂账。传统工作流里这个账靠美术的经验在记,到了Substrate,你就需要一个显式工具把这笔账重新拆开。
3. 参数重构后的Substrate为什么容不下Metalness:桥接节点的设计动机
3.1 Slab体系里的DiffuseAlbedo和F0是独立参数
Substrate和传统材质节点最大的差别,不是换了个皮肤,而是把材质从“一个输入面板+一个固定Shading Model”变成了“用Slab节点组合出来的材质树”。
简单理解,Slab可以看作一个材质参数块。一个常规的Substrate材质至少有一个BSDF Slab,BSDF Slab里直接提供DiffuseAlbedo、F0、Roughness等输入。如果你要做多层混合材质,就再叠一个Mixed或Layered Slab,不同层各自有自己的BSDF参数。编辑器里呈现的就是一棵参数树,树的每根分支都对应一个物理属性块。
在这个体系里没有Metallic滑条的位置。因为Metalness的本质不是一个物理属性,而是“把漫反射参数和镜面反射参数二选一”的包装器。Substrate选择了更底层、更接近物理的语言,它直接问你两个问题:漫反射颜色是多少?垂直反射率F0是多少?所以老资产进入到新体系,必须有一个翻译过程,把二选一的包装打开,把其中一部分信息放到DiffuseAlbedo,另一部分放到F0。
Metalness-To-DiffuseAlbedo-F0节点就是这个翻译器。
3.2 分离之后,多层混合的收益才真正体现
为什么这个转换值得做,而不是继续保留金属度?我在实际做多层材质测试时感受很深。
传统材质做多层混合,最常见的结果是两层都要输出一张“BaseColor+Metalness”的组合,在混合节点里再按遮罩插值。这里有一个隐藏问题:金属度是标量插值,但BaseColor的语义在两层里可能完全不同。上层是掉漆的铁板,下层是红锈,两层各自有Metalness,插值过程中红锈区的反射特性和铁板的反射特性会交叉污染。你很难在着色器层面精确控制“这一层混入多少Marble、那一层保留多少Metalness”。
Substrate把每层的DiffuseAlbedo和F0拆开之后,层与层之间可以做到更干净的物理叠加。每个BSDF Slab自己就是一个完整的反射模型,层之间的混合是BSDF层的混合,不是参数表中四个滑条的混合。这个优势的前提,是老材质的参数先被正确地拆解到DiffuseAlbedo和F0里。如果拆错了,层叠后会出现更诡异的结果。
所以说,Metalness-To-DiffuseAlbedo-F0不只是为了迁移兼容而存在的补丁节点,它是整个Substrate材质树里物理正确性的第一道入口。
4. 输入输出与内部映射:一份可以手推的公式
4.1 输入端与输出端的语义区别
这个节点通常有三个输入端、两个输出端:
| 端口 | 来源 | 语义 | 注意点 |
|---|---|---|---|
| BaseColor | 旧BaseColor贴图 | 同时包含旧漫反射色和旧金属反射色 | 贴图存储空间是sRGB,进入材质网络后按线性计算 |
| Metalness | 旧Metallic贴图 | 材质区域分类:非金属=0,金属=1 | 必须是线性数据,纹理属性里关掉sRGB |
| Specular | 旧Specular参数,常为0.5 | 非金属区域的F0微调 | 不是高光强度,是反射率微调 |
| DiffuseAlbedo输出 | 去往Substrate Slab | 漫反射反照率 | 非金属区域有效,金属区域接近0 |
| F0输出 | 去往Substrate Slab | 垂直入射菲涅尔反射率 | 旧金属色从这里回到光照系统 |
特别注意一点:Roughness不经过这个节点。老材质里的Roughness贴图仍然直接连到Substrate Slab的Roughness端口,不要等这个节点帮你传。转换节点只处理BaseColor和Metalness之间的参数重分配。
4.2 节点的核心映射公式
根据经典PBR近似,节点内部做的核心映射可以写成这样:
diffuseAlbedo = BaseColor * (1 - Metalness) F0 = lerp(f0NonMetal, BaseColor, Metalness)其中f0NonMetal是旧Specular映射过来的非金属反射率。在传统UE材质里,默认Specular=0.5,对应的非金属F0大约落在0.04到0.08这个区间。0.04对应折射率1.5左右的典型玻璃/树脂,0.08则更接近很多引擎默认采用的美术化反射基准。具体映射系数在Substrate各版本之间可能略有差异,因为有的版本还做了能量补偿或色彩空间修正,但大方向就是这个。
这个公式解释了不少问题。当Metalness为0,整个BaseColor原封不动进入DiffuseAlbedo,F0是一个接近灰0.04的小值,这就是一块标准非金属。当Metalness为1,DiffuseAlbedo被乘成0,BaseColor整体进入F0,这就是一块纯金属。中间值则是不伦不类的“半金属”,物理上不存在,传统工作流里也不应该出现。
旧式Specular滑条的作用也在公式里体现了。它不是直接调高光亮度,而是调非金属区域的F0基准值。Specular越高,非金属的高光反射率越高。到了Substrate体系,这个值最终映射成F0输出,不要再额外乘0.04或者加0.08,否则反射亮度会错得离谱。
4.3 三组手算样例:从0到1暴力验证
我们设BaseColor为红色常量(0.8, 0.1, 0.1),Specular保持默认0.5,Metalness分别取0、0.6、1。手工算一下输出:
| Metalness值 | DiffuseAlbedo输出 | F0输出 | 实际含义 |
|---|---|---|---|
| 0 | (0.8, 0.1, 0.1) | 灰色小值,大约0.04左右 | 红色塑料/油漆表面 |
| 0.6 | (0.32, 0.04, 0.04) | 从灰0.04向红(0.8,0.1,0.1)插值60% | 半金属过渡,通常应避免 |
| 1 | (0, 0, 0) | (0.8, 0.1, 0.1) | 红色金属,例如红铜 |
这个表建议你保存下来,后面做材质调试时可以直接对照。我自己调试时经常用纯色常量而不是真实贴图,就是为了快速验证节点逻辑是否按预期工作。如果渲染出来的金属区域高光颜色不是BaseColor的值,反而整体发灰,大概率是F0链路被改过。
在真实项目里,我几乎不会主动使用0.6这种金属度中间值。旧材质如果有这种中间值,一般都应该检查是不是贴图没画干净,而不是指望Substrate帮你“修正”成一个真实材质。
5. 老材质迁移接线顺序,以及三个让我返工的接线坑
5.1 标准接线顺序:从贴图到Substrate Slab
如果你只是想把一个老材质快速迁到Substrate,可以按这个顺序操作:
- 启用Substrate插件,重启编辑器。
- 新建一个Substrate Material节点,双击进入内部结构,找到Substrate Slab参数块。
- 把旧材质里的BaseColor纹理接到转换节点的BaseColor输入,Metallic纹理接到Metalness输入,Specular常数或贴图接到Specular输入。
- 把转换节点的DiffuseAlbedo输出和F0输出,分别接到Substrate Slab对应的DiffuseAlbedo和F0端口。
- 旧Roughness贴图直接接到Slab的Roughness端口。
- 编译保存,先不急着调参数,跑一帧看整体亮度趋势。
大致框图不需要复杂化,本质上就是把旧材质面板上的三个参数搬运到转换节点三个输入端,再把两个输出接到新Slab对应的两个端口。不同引擎版本里Slab端口的名字可能有细微差别,比如有的版本叫Base Color,有的版本叫Diffuse Albedo,但物理语义一致,以你当前编辑器显示的引脚为准。
5.2 坑一:F0输出被当成旧高光强度二次缩放
这个坑我至少见三个人踩过。一些美术在传统材质里习惯了“Specular滑条控制高光强度”这种潜意识,看到F0输出就以为是高光强度,顺手把它接到新材质的高光参数,或者乘了一个0.04再进Slab,结果金属材质的高光弱到几乎看不见。
F0不是高光强度,它是垂直入射时的菲涅尔反射率,是PBR模型的直接输入。金属区域的F0就是金属的反射颜色,比如红铜的F0接近它本身的暖红色。如果你在节点后端乘0.04,等于把红铜的反射率压到了玻璃级别,金属感直接消失。正确做法是转换节点输出什么,就把什么原样送到Slab,中间不要再乘任何权重。
如果你想把F0接到材质树上某个自定义复数颜色端口,也请先确认那个端口的语义是线性反射率,而不是“亮度增益”。
5.3 坑二:Metalness贴图被留在sRGB空间
有个项目迁移后,金属边缘总出现一条又脏又亮的过渡带,怎么调高光参数都没用。我排查到贴图才发现,项目的Metalness贴图在纹理导入设置里勾着sRGB,也就是说它被当成了颜色贴图,进到节点前先被转到了线性空间,数值曲线被拉变形。
金属度贴图在传统工作流里必须按线性数据处理。如果它被视作sRGB,原本0和1之间的阶跃边缘就会带上中间渐晕,转换节点拿到一个错误的0.5,最终生成一个不存在的半金属区域。检查方法是直接看纹理导入面板,确认颜色空间那一栏是“线性数据,不勾选sRGB”。
还有一个小验证办法:把Metallic贴图临时替换成一个纯常量0或1,如果过渡脏边消失,说明问题就是贴图空间设置,而不是光照模型本身。
5.4 坑三:多层材质时所有层都接到了同一个Slab上
再上升到复合材质时,问题会更隐蔽。Substrate做多层混合时,不是把所有贴图接到同一个材质结果节点,而是使用Mixed或Layered材质,每层有自己的Slab实例。有些人在转换时图省事,把顶层和底层的贴图全部连到同一个Slab上,再靠遮罩混合,结果层与层之间没有任何遮挡裁剪,透光、混色、高光叠影全来了。
正确做法是每种语义的层单独走一遍转换节点,各自的DiffuseAlbedo和F0送进对应Slab。比如做掉漆金属板,底层是铁锈层,顶层是金属漆层,两层要各自构建两个BSDF实例,层间混合交给Substrate的层叠机制,而不是把所有参数揉进一个BSDF。这样F0才能正确参与层间插值,而不是被错误的线性混合冲掉。
6. 用极端颜色验证转换结果:边界检查与反向换算
6.1 纯色极限测试:金属与非金属必须界限分明
迁移完一批材质,不能只看场景截图就下结论。我的建议是做一个专门的纯色测试材质,用常量代替贴图,把BaseColor固定成明显红色,Metalness分别改成0和1,编译后渲染到测试小球上。观察两个关键点:非金属球的高光应该非常暗且近似无色;金属球的高光/反射应该呈现明显红色,而且漫反射几乎消失。
如果你觉得暗部差异看不清,可以把F0或者DiffuseAlbedo临时接到Emmisive输出口,再乘一个50到100的系数,用自发光放大暗部差异。这样你就能直观看到0.04这样的灰值和金属色的区别,不用靠猜。
我经常看到有人在这步发现节点反转的严重问题:非金属变成了强高光的亮片,金属反而变成哑光红塑料。出现这种结果,先检查输入贴图颜色空间,再检查F0链路是否被二次修改,最后检查BaseColor贴图是不是被美术画成了平面光照效果而非线性颜色。
6.2 反向换算与批量迁移时的高效验证
Substrate体系里还存在着与这个转换节点方向相反的工具,作用是把DiffuseAlbedo和F0合并回Metalness,用于在传统和Substrate之间往返转换。我建议你至少手动验证一次“正向转换再反向转换”的误差范围,确认你用的引擎版本在这个链路上没有引入奇怪的偏移。
做法很简单:用转换节点把老材质转成Substrate参数,再用反向节点把DiffuseAlbedo和F0并回BaseColor和Metalness,对比最初值。如果数值误差在可忽略范围内,说明迁移链路是健康的。如果黑点或高光区域误差明显,多半是贴图色彩空间或者Specular映射系数与版本默认值不符,需要单独处理。
批量迁移时,不需要每个材质都做细致的视觉对比。抽三层级做往返验证,外加所有资产做纯色极限测试就足够了。真正费时间的地方是那些“金属与非金属混杂在BaseColor里”的旧资产,它们转换后很可能出现中间金属度,需要美术按区域重新归类贴图,而不是靠节点救回来。
我自己真正吃透这个节点后,最大的变化不是学会了某个操作,而是重新理解了传统PBR工作流的取舍。Metalness是美术便利和资产成本妥协出来的产物,而Substrate想走的是物理参数独立的路子。转换节点就是这个过渡期的翻译官,它把旧账拆开重记,虽然第一眼看过去有点吓人,但用顺了你就会发现,参数语义清楚了,很多以前说不清的高光问题都不用再猜。
如果你也在做迁移,我建议把本文这个映射公式贴到项目Wiki里,并且固定好Metalness贴图的线性空间规范。别只靠节点名字去猜协议,不然迟早会在某个多层材质上翻车。