做飞船维修场景的时候,我头一回真正觉得PBR这个技术不是用来“炫”的,而是救命的。以前用老式Blinn-Phong,调一个拉丝金属得把高光范围、高光强度、环境色三组参数来回拧半天,换盏灯颜色就又不对了。换了PBR标准着色器之后,材质表现一下子稳了——金属就是金属,塑料就是塑料,在灯光下面怎么转都基本符合直觉。这个章节我想完整拆一遍PBR与标准着色器的实战逻辑,从物理原理讲到飞船维修场景里的贴图配置、材质参数、灯光布置,再到我真正踩过的坑。这篇内容给美术、TA、还有那些想看懂引擎渲染基础的程序员看都很合适,读完你至少能独立把一个工业场景从零摆到能出图。
我去年接了一个太空题材的项目,里面有不少飞船维修、舱体外壳喷涂、损伤补丁这类场景,美术组前前后后折腾了一个多月PBR材质,积累的问题和方案特别典型。这一篇我按“设计思路 → 原理 → 实操 → 排查”四个部分展开,尽量把每个决定背后的原因讲清楚,而不是只丢你一张参数表。
1. 整体设计与思路拆解:飞船维修场景为什么必须走PBR
1.1 场景需求与PBR核心思路的契合点
飞船维修场景跟普通的室内场景最大的区别在于材质种类极其繁杂。你看一个船体停靠塔,随便扫一眼就能看到:
- 已经磨损但依然光滑的船体外壳(高金属度、中等光滑度)
- 刚换上去的崭新钛合金补丁(高金属度、低粗糙度、反光尖锐)
- 氧化的管线接口(中金属度、高粗糙度、带颜色偏移)
- 碳纤维或复合材料舱盖(低金属度、粗糙度差异大)
- 大量塑料、橡胶密封条、玻璃观察窗、屏幕表面
这种场景如果还用传统方式调材质,光是区分“同样的金属外壳,旧的、新的、生锈的、被擦亮的”就能逼疯人。PBR的好处是把材质参数收敛到了一个更小的、物理上可解释的范围内:金属度、粗糙度、反照率。你不需要再去理解“高光的幂次应该给多少才像铁”,你只需要把粗糙度调到0.3左右,金属度拉到1,反射率给一个灰白色,铁的质感自然就出来了。
所以我给项目定下的第一步设计原则是:统一使用标准着色器(Standard Shader)+ PBR贴图工作流,全场景禁止手工高光参数。材质表现差异全靠贴图去区分,而不是靠几十个思路不一致的材质球去凑。
1.2 为什么选择标准着色器而不是更复杂的次表面或自定义光照模型
有人可能会问,既然做太空题材、飞船维修,要不要直接上HDRP或者自己写一个复杂的着色器?我的回答是:看阶段和需求。
我们这个项目的目标平台不止高端PC,还要兼容中低端配置,维护展厅和模拟训练场景的实时渲染。用标准着色器最大的优势是跨管线兼容性强,着色器变体管理简单,性能消耗可控。标准着色器在Unity里是一个基于物理的微表面模型实现,虽然相比HDRP里的Lit Shader,缺少了曲率、厚度、细节贴图混合等高级特性,但它胜在稳定和通用。做飞船维修场景,90%的材质需求是金属、非金属、自发光、法线细节这几类,标准着色器完全覆盖。
对比过几个方案之后,我最关注的是两点:
- 材质参数的直觉程度。美术能快速上手,减少反复试错。
- TSR(着色器变体)体积。标准着色器通过关键字控制特性,比如法线贴图、细节贴图、自发光、高度图,按需开关后变体数量可控。
至于“策略路由”这类网络词,这里不展开,简单强调一个思路:在进行渲染功能选型时,要像一个路由器一样为不同类型的渲染需求做策略分流,而不是所有表面都走同一条最高规格的渲染路径。这也是我们后来在场景里划分“高精度近景材质”和“远景简化材质”的理论基础。
1.3 项目工作流设计:从贴图资产到引擎表现的动线
我们最终确定的工作流是:
- 在DCC软件里(Blender或Substance Painter)制作PBR贴图,输出反照率、金属度、粗糙度、法线;部分资产额外输出AO和高度图,用于标准着色器自带的Secondary Maps细节效果。
- Unity里基于材质名称分组,比如
Hull_Panel_Original、Hull_Panel_PatchNew、Pipe_Corrosion、Rivet_BareMetal,全部映射到标准着色器。 - 光照环境先搭好基础方向光和天光,放三到四个反射探针覆盖主场景区域。
- 用Lightmap和实时灯光混合,把飞行甲板和维修机库的明暗关系锁定。
- 最后统一用Post Processing做调色。
这套流程里最核心的决策是把“材质表现”尽可能推向贴图阶段。标准着色器本身参数很少,如果把细节全堆在引擎里调,一半的功夫都会浪费在数字之间来回试探。PBR贴图进了引擎之后基本所见即所得,这才是我们选它的根本原因。
2. PBR与标准着色器的核心细节解析
2.1 用“能量守恒”和“微表面”理解PBR
新手刚接触PBR时容易懵,一堆公式和名词,但其实核心就两个物理概念:能量守恒和微表面反射。
能量守恒的意思很直白:一束光打到物体表面,一部分被反射,一部分被折射吸收,加起来不会超过入射光的能量。所以材质越亮,它的漫反射就越弱;金属不会出现“又像镜子又有强烈底色反光”的怪状态。老式Blinn-Phong模型的最大问题就在这里,反射和漫反射经常互不商量,调出一个“塑料金属”毫无物理依据。
微表面理论说的是,任何材质在微观层面都不是绝对光滑的,而是由无数朝向各异的小平面组成。每个小平面都在做镜面反射,但朝向不一致导致反射光被散开。我们把“多少比例的小平面朝向接近法线方向”转成一个0到1的值,这就是粗糙度(或光滑度)。粗糙度低意味着微表面朝向一致,高光尖锐,像抛光金属;粗糙度高意味着微表面杂乱,高光扩散,像哑光漆。
这套物理模型在标准着色器里的体现就是几个简单参数:
- Metallic(金属度):0到1,决定反射颜色是来自反照率贴图还是来自环境反射。
- Smoothness(光滑度):0到1,等价于1减粗糙度,控制高光的扩散程度。
- Albedo(反照率):基础颜色,非金属部分是漫反射颜色,金属部分则基本决定反射率。
理解了能量守恒之后,你就明白为什么做金属材质的时候,反照率颜色要偏深。铁的反照率RGB大约在0.5左右,因为它在反射的同时也在吸收一定光。如果填了纯白金属,看起来反而会像铝或者银色油漆,不像结构钢。
2.2 标准着色器的参数面板逐项拆解
我用Unity标准着色器的默认参数表来说,因为这些参数在大多数基于物理渲染的引擎里都能找到对应项:
| 参数 | 作用 | 飞船维修场景里的常见取值 | 关键注意点 |
|---|---|---|---|
| Albedo | 基础颜色/反照率 | 船体外壳 #7A7E84,新补丁 #ACB0B4 | 不是给金属乱贴颜色,它是底层反射率 |
| Metallic | 金属度 | 外壳0.9,补丁1.0,橡胶0.0 | 金属度不是“光泽度”,非金属别乱给 |
| Smoothness | 光滑度 | 外壳0.35,补丁0.7,玻璃0.95 | 数值越高反光越聚拢 |
| Normal Map | 法线贴图 | 铆钉、焊道、刻痕、板件接缝 | 尽量不影响Albedo明暗 |
| Height Map | 高度图 | 用于细节贴图的凸凹感 | 需要配合Secondary Maps使用 |
| Emission | 自发光 | 指示灯、仪表盘、焊接光弧 | 不写自发光的话,灯丝也只是一片灰 |
| Secondary Maps | 第二套细节贴图 | 大面积旧化细节混合 | 性能有开销,远景建议关闭 |
在标准着色器里,Smoothness、Metallic都有两个通道来源:一张是主贴图自带通道,另一张来自高光贴图(Specular)。我们统一使用Metallic工作流,也就是把金属度写进金属贴图的R通道,粗糙度写进G通道,环境光遮蔽写进B通道。这能最大化贴图利用率,也方便Substance Painter直接导出。
2.3 反照率、金属度、粗糙度、AO的分工不能混
这个分线必须理清楚:同一张贴图里不同通道装的是完全不同的信息。
例如我做一个生锈的管道材质:
- 反照率贴图里,铁锈区域偏橘褐色,裸露铁皮区域偏灰白,但要控制饱和度不能太高,否则在灯光下会发光感。
- 金属度贴图里,铁皮区域是接近1的白色,铁锈区域是接近0的黑色,因为铁锈是非金属化合物。
- 粗糙度贴图里,铁锈区域比较粗糙给0.6以上,铁皮被磨出来的部分给0.2左右。
- AO贴图里,管件相接处、缝隙、凹坑深处给暗色。
如果反过来把铁锈区域金属度给高,它在灯光下就会出现金属反射,颜色会跟着环境走,看起来像镀了一层锈色金属膜,最后出来的效果就非常不真实。这种细节差异在飞船维修场景里特别致命,因为玩家会近距离查看这些管道,材质一旦露馅,整个场景的专业感就没了。
这里补一个我实测下来很重要的点:法线贴图不要和反照率/粗糙度贴图混用思路。法线贴图给的是方向信息,它会让光照计算产生高低起伏的错觉。但法线上绝不会包含“这里偏红”“这里有污渍”的信息。如果把污渍画进法线贴图,灯光固定时看起来像表面变形,灯光一动就穿帮。
2.4 光照环境对PBR材质表现的决定性影响
PBR材质本身只是半成品,光照环境才是把物理模型发挥出来的另一半。标准着色器的反射依赖环境反射源,如果场景里只有一束直射光没有Reflection Probe,金属会变成黑乎乎的一团,因为它几乎没有漫反射,全靠反射环境光贡献可见度。
飞船维修场景有大量镜面金属表面,对反射探针的布置要求很高。我的做法是:
- 机库中央放一个覆盖全场景的反射探针,用来捕捉整体环境底色。
- 在每个维修区域附近放一到两个小范围探针,用来捕捉实时灯光和道具产生的反射。
- 重要展示物体(比如正在维修的推进器喷口)用反射探针加上Cubemap小覆盖范围,保证近距离细节。
反射探针的更新频率也要控制。实时更新的探针每帧渲染一次Cubemap,非常吃GPU。维修场景里其实大多数反射物体是静止的,我直接把探针设为“只在场景变化时更新”,配合Runtime Reflection Probes的优化设置,能在不大幅损失画质的前提下把反射探针的DrawCall降下来。
3. 飞船维修场景的实操过程与核心实现
3.1 参考资产与素材准备:先定材质清单
动手做材质之前,我会先列一份“材质清单”,把一个维修机库拆成几个大区域,然后再细分物体类型。这份清单既是贴图制作的任务表,也是后续调材质的参照基准。
在飞船维修场景中,我分成了四类:
- 船体外壳:需要大面积的金属板,金属度高,光滑度中等;表面有轻微划痕、磨损、退色。
- 维修设备:包括机械臂、液压组件、螺丝、夹具。金属和非金属混搭,需要做高精度法线细节。
- 管线与接口:大量金属管道、橡胶软管、防静电涂层,粗糙度差异大。
- 修补与损坏区域:焊接痕迹、烧蚀面、裸露的断口、临时补丁,这些地方通常要加Emission做电弧或发热,视觉权重高。
每类物体我都在Substance Painter里用同一条烘焙模板处理,保证UV和法线方向一致,关键是把表皮法线和结构法线分开:结构法线给面片转折,表皮法线画细节划痕。这样贴图进Unity之后不会出现大面积的软阴影错位。
3.2 材质球配置实例:慢慢拧参数不如先分层
我在Unity里面对一堆数值时,基本不孤零零地调参数,而是先把物体分成“金属大类”和“非金属大类”,再分别处理:
金属大类(如船体外壳补丁):
- Albedo:给一个偏深的冷灰色
RGB(141, 148, 155),这是不锈钢和钛合金混合的常见底色。 - Metallic:拉到0.95以上,让反射颜色完全由环境决定。
- Smoothness:从0.3起步,磨砂感明显,但要保留轻微的高光反射。
- Normal Map:叠加铆钉和打磨线。
- 在细节区域用Secondary Maps加一层“大面积划痕”的混合,让近看不会太平。
非金属大类(如橡胶密封条):
- Albedo:深黑色偏一点暖色
RGB(13, 14, 15)。 - Metallic:0。
- Smoothness:0.2左右。
- Normal Map:轻微的凹凸纹理,不用太强,否则会像一块橡皮泥。
这里我最想强调的一个习惯是:先给一个最接近的预设值,整体看一遍,再逐个微调,不要在某个参数上死磕。PBR材质的反馈是整体性的,你盯着Smoothness半天,不如站起来看一眼整个场景在灯光下的和谐度。
3.3 灯光布置与反射探针协同:把金属“点亮”
灯光布置在维修场景里有很强的功能暗示:接近任务的区域亮,背景维修区暗,紧急指示灯保留区域性的颜色倾向。实际操作时我把灯光分了三层:
- 主光:模拟顶部机库日光灯带,平行方向光为主,强度不高,偏冷白
#E6EAEF。 - 辅光:模拟周围仪表和指示灯的泛光,暖色偏黄,强度很低,只提供阴影里的补光。
- 效果光:焊接处、发动器检查口、破损线束这些位置放点光源,用高亮和橙色Emission做视觉引导。
关键技巧在于,许多金属物体已经是由反射探针提供大部分视觉信息,所以不要把方向光的强度调得太过,否则反射高光很容易爆掉。我的方法是方向光强度设成1左右,反射探针强度设成0.6到0.8之间,场景整体看起来更自然。
反射探针里还要注意**“探针里有没有把自发光物体烘焙进去”**的问题。原本我在机库墙上放了几块发红光的电热板,结果发现金属机翼经过时反射出好几条亮红的条状光带,看着很科幻,但用在“维修”这种写实场景里反而显得刻意。后来我把部分仪表板的自发光强度调低,或者标记成不影响反射探针的物体,金属表面的反射才干净下来。
3.4 特殊物体的材质处理:焊接点、烧蚀面与玻璃
飞船维修场景里最吸引眼球的是焊接点和烧蚀区域。焊接点我一般用两层材质思路:外部金属高反射,内部熔融核心用Emission做一个从橘黄到暗红的渐变贴图,同时把Emission强度控制到能照亮周围一小块但不刺眼的程度。烧蚀面则要降低金属度,让它看起来像氧化之后变得有点像陶瓷,反射率降低,粗糙度升高,这样和旁边干净金属形成强烈对比。
玻璃材质在标准着色器里通常用一个接近透明的Emission(或者Transparent型Cutout变体)来做。但要注意:标准着色器处理玻璃折射效果有限,如果你需要真正的折射,还是得通道到HDRP或使用额外脚本。不过维修场景里的大部分玻璃窗都是仪表盖板和观察窗,反射比折射重要,所以直接用标准着色器的Metallic=0、Smoothness=0.95就能达到可接受的质感。
4. 常见问题与排查技巧实录
4.1 金属材质泛黑或完全变黑
这个太常见了,十个做PBR的新手九个遇到。我先说原因:金属材质几乎不产生漫反射,表现全靠环境反射。如果你只点亮了一个方向光但场景里没有反射探针,金属表面就没有图像可反射,自然就黑了。
排查路径:
- 先确认场景里有没有反射探针。
- 然后把金属材质临时换成非金属,看物体是不是立刻亮了起来,如果亮了,说明确实是反射信息缺失。
- 检查反射探针覆盖范围,大探针如果被模型包围可能烘不进有效Cube。
- 金属度是不是误调成了1,但反照率又给了纯黑,这样反射率也会很低。金属度越高,反照率越要保证是一个有灰度的颜色。
还有一种隐蔽情况:如果你给金属贴了黑色的反照率,其实相当于让“金属表面的固有反射率”降到只有5%左右,看起来就像涂了黑漆。要改成至少#4C4C4C这种中等灰度。
4.2 高光爆成一片白斑
飞船外壳在强光下如果出现一大片没有层次的白斑,通常是Smoothness给得过高,或者模型的面片过于平整,导致反射高光集中成一个很大的尖锐亮斑。真实金属即使很抛光,因为表面有微小凹凸,高光边缘也会有些过渡。
处理方法:
- 把Smoothness从0.95降到0.7,看高光面积是否自然分散。
- 用流程化噪声生成一张细微的粗糙度变化贴图,加在Smoothness通道里,打破高光的均匀性。
- 检查是不是用了CubeMap HDR光照后,反射探针里包含过亮的光源,这种反射噪点也会让高光显得脏。
另一个经常被忽略的点是光照强度与后期Bloom写实风格不匹配。维修场景的白色灯管本身不算强光源,如果HDR给得太高,再叠加Bloom,灯管边缘就会泛成一团白光。尽量让Bloom阈值高于大部分自发光的亮度值,只让焊接电弧和故障警示灯这类强效果亮起来。
4.3 法线贴图“搓衣板”纹路和眼睛反射乱跳
法线贴图如果烘焙参数不对,会在船体面板上出现重复的搓衣板条纹。原因大概率是低模UV面积太接近,而高模细节密度分布不均,或者烘焙分辨率不足。
我排查的时候会先把法线贴图关掉,纯看反照率范围是否干净。干净的话就逐步加回法线,一旦某块区域出现搓衣板,就在SP里单独修该区域的遮挡。还有一种情况:法线贴图导入Unity时没有勾选Create from Grayscale,但这其实对法线烘焙类型没影响,比较重要的是保持压缩格式不为Normal map时会出现错误。
经验之谈:如果法线贴图在材质球上看起来“过度起伏”,先看它的Strength,标准着色器默认法线强度是0,需要自己去Normal Map里点一下。很多人就是把法线贴图放进法线槽眼里,然后忘记勾选“Normal Map”选项,结果画面会变成低分辨率的浮雕状效果。
4.4 性能与DrawCall优化:别让标准着色器变成卡顿元凶
飞船维修场景的物件数量巨大,如果每块小铁板都有一套独立材质,DrawCall会直接爆炸。我常用的策略:
- 材质的Atlasing:把同一区域的多块小金属板合并到一张材质球上。
- LOD与着色器变体:远景物体使用不带法线贴图细节的标准着色器变体(去掉NORMALMAP、DETAIL,关掉Secondary Maps),减少指令数。
- 反射探针数量:反射探针数量太多,即使不实时更新,内存占用也很大,近景重要物体用探针,远景用统一环境反射。可以用反射探头加载和卸载脚本控制。
- Emission Overlay:大片自发光区域尽量用静态光照贴图烘焙,不要用实时面光源。
我在项目里做了一次大优化,把机库里380个独立材质球合并到220个,同时给所有中远距离物体降了法线细节等级,DrawCall降低了43%,而视觉上几乎看不出差别。这证明一件事:PBR材质后期的优化空间,主要达人是在资源分层上,而不是渲染参数上。
作为一个做渲染落地比较多的人,我最大的体会是:PBR标准着色器是一套把美术直觉翻译成物理规则的系统,它不会替你解决所有视觉问题,但能大大缩短“调材质”和“看结果”之间的反馈循环。你在飞船维修场景里看到的那些有说服力的金属旧化、焊点温度差、橡胶的哑光感,说到底都是能量守恒和反射信息做对了,而不是某一个特别鲜艳的贴图颜色堆出来的。
最后分享一个我自己一直在用的小习惯:每次调完一个材质,先固定摄像机视角,花二十秒观察它在不同光照角度下的响应,再快速切几个远景角度,确认材质没有在特定角度出现奇怪的跳变。PBR的价值就在于让你把更多精力放在“这个材质应该长什么样”,而不是“这个高光参数怎么算”。做场景,尤其是维修这种近看物特别多的场景,踏实把材质和光照的底子打好,后面渲染出来的每一帧都会省心很多。