Unity PBR渲染全解析:从传统Blinn-Phong到URP/HDRP的实践指南
发布时间:2026/10/7 2:20:09 作者:尧图编辑部 阅读量:1,286

我最早在Unity项目里被PBR这个词忽悠过一阵。那时查资料翻到一篇讲PBR策略路由的文章差点以为Unity和路由器有什么合作后来才反应过来渲染圈说的PBR全名是Physically Based Rendering跟网络协议那个Policy Based Routing完全是两码事。这个误会在开发者社区里其实很常见隔三差五就有人发帖问两个PBR的区别。说回正题。我这几年的实际感受是Unity项目从Built-in渲染管线往URP、HDRP迁移的时候最卡壳的不是C#的代码架构也不是Shader的编写方式而是很多人还在用上一代线性光照模型思维去调材质。一个金属椅子在白天场景里调好了拖到夜晚场景立刻变成塑料同一个皮肤材质换个灯光角度就油光满面。这些问题并不是灯光的锅而是材质参数本身没有物理含义它只针对某个特定光照环境有效。等到我把团队的材质参数全面切到PBR体系之后灯光、材质、后处理三个环节才真正解耦可以分头推进了。这篇文章我想用项目实践的角度把Unity里的PBR技术拆开讲一遍它到底是什么、为什么现在非用它不可、比传统的Blinn-Phong那一套强在哪以及几个公开的商业项目是怎么用它落地写实或风格化渲染的。无论你刚接触Unity想搞明白材质面板上那一堆滑条还是正打算带团队做渲染升级下面这些内容应该都有一点参考价值。1. 从调参数调到怀疑人生说起PBR到底解决了什么问题1.1 传统光照模型下材质和灯光是一根绳上的蚂蚱如果你用过Unity内置的Legacy Shaders应该对Blinn-Phong模型的那些参数有印象Diffuse颜色、Specular颜色、Shininess、Glossiness。这套东西看起来简单真做项目的时候能折磨死美术。原因在于这些参数不是描述物体本身是什么材质而是描述物体在特定光照下看起来像什么。比如你为了让一个塑料零件在强主光下有一圈漂亮高光把Shininess调到256高光确实出来了但等关卡切换到阴天、霓虹灯或者烛光环境这个塑料零件的高光强度、宽度、颜色就全都不对了还特别容易和周边环境格格不入。这种材质与灯光强耦合的问题在多人协作的项目里会进一步放大。你定义了一个地面材质A美术在主光源下调好的参数B美术放到黄昏关卡里又要重调一遍等哪天主光源角度或者强度被策划调整了所有材质又得重新看一遍。我在一个中大型项目里见过一个基础材质被几十个场景引用任何一个灯光变更是版本管理里就能多出好几条材质相关的改动记录改完还不一定对。1.2 PBR的核心主张灯光负责给多少光材质负责是什么PBR的思路正好反过来它让你把材质的属性描述成物理上可测量的量比如金属度Metallic、粗糙度Roughness或平滑度Smoothness、反射率Base Color/Specular、环境光遮蔽AO然后再交给一个基于物理规律的光照模型去计算。灯光和材质在计算过程中是解耦的同一块金属你只需要告诉引擎这是铁、表面粗糙度0.5换到太阳底下它是金属换到蜡烛旁边它依然是金属只是反射的内容和亮度按物理规律变化了而不是看起来像另一种东西。这个转变的核心是两条物理规律。第一条是能量守恒一个表面反射出去的光能总量不可能超过入射光能。传统Blinn-Phong模型里漫反射加上高光很容易超过1材质会自己发光、亮到惨白PBR里则强制要求漫反射与镜面反射共享能量粗糙度越高高光越暗越宽但总能量不变。第二条是微表面理论现实中的物体表面在微观尺度上都是凹凸不平的所谓粗糙就是微观法线方向杂乱光滑就是微观法线方向基本一致。PBR的高光不是靠一个指数凭空捏出来的而是通过微表面的法线分布函数算出来的所以它天然能表现出金属刮痕、拉丝、旧化这些细节。1.3 一张白纸与一个金属球最适合理解PBR的类比我经常用一个类比来跟新人解释PBR你在同一个光源下看一张白纸和一个抛光金属球。白纸把光线漫反射到各个方向从哪个角度看亮度差异都不大金属球只在特定方向形成高光其它方向几乎是黑的。如果让一个完全没有PBR概念的人用Blinn-Phong去调白纸和金属球他多半会把纸的Diffuse调成白色、Shininess设成0把球的Diffuse调成灰、Shininess设成128。看起来对了可实际在白纸边缘拉一道亮光、或者让金属球扩散出柔和的漫反射立刻就穿帮。PBR的玩法就不是这样。白纸的Base Color是白色、Metallic0电介质、Roughness接近1金属球的Base Color是它的固有色、Metallic1、Roughness很低。这两个材质定义放到任何光照环境里都站得住灯一变结果也跟着物理规律变化。这就是PBR被叫做基于物理的原因它模拟的是材质对光的物理响应而不是针对特定灯光的手绘效果。2. Unity里的PBR是怎么组织的从Standard Shader到URP/HDRP的Lit2.1 Standard Shader的两条工作流金属度还是高光反射Unity从5.0开始引入Standard Shader这是绝大多数Unity开发者第一次直接接触PBR的入口。Standard Shader内部提供了两条工作流Metallic金属度和Specular高光反射。Metallic工作流是Unity默认推荐的一条核心参数就三个Base Map基础颜色贴图、Metallic金属度、Smoothness平滑度。它把材质分成金属和非金属两大阵营Metallic为0表示电介质比如木头、塑料、石头、皮肤Metallic为1表示导体也就是各种金属。金属与电介质的反射率差异非常大非金属材质的反射率通常在0.04左右金属往往能到0.5以上这就是为什么同一张Base Color金属度变成1之后立刻亮得发贼。Specular工作流则用Specular Color直接指定表面反射的颜色和强度好处是可以完全独立控制RGB三个通道的反射率适合一些特殊材料比如某些各向异性织物的高光部分有颜色偏移但这种工作流参数更多美术在团队配合时容易出现各调各的的问题。我个人的习惯是新项目、新团队一律走Metallic工作流因为它最符合直觉外包也好统一标准Specular工作流更适合维护老资源或者遇到材质比较复杂、需要单独控制反射色的情况。2.2 URP和HDRP里的Lit Shader有什么变化现在的Unity项目大多不会停留在Built-in管线里至少会切到URPUniversal Render Pipeline追求高画质的PC/主机项目则选HDRPHigh Definition Render Pipeline。URP和HDRP都提供了名为Lit的PBR ShaderMetallic和Smoothness这两个核心参数一直都在但渲染管线的能力上限完全不同。URP里的Lit Shader在默认情况下和Standard Shader的PBR核心差不了太多都是为了兼顾移动端性能。HDRP则把物理化做得更彻底灯光默认使用物理单位还有更完整的Diffusion Profile用于次表面散射、透射、清漆层、各向异性高光等等。Unity 6推出之后HDRP在材质表达、GPU Lightmass等方面的上限又抬高了一截。不过不管你用哪条管线PBR的底层数学框架是同一个只是公开出来的参数和效果范围不同。理解了这个项目从URP迁移到HDRP的时候就不会觉得怎么又来了一套完全不同的渲染本质上还是金属、粗糙度、反射那几件事。2.3 数据贴图的通道打包为什么Metalness和Smoothness能塞进一张图PBR项目里经常能看到一种做法Metallic贴图的R通道放金属度、A通道放Smoothness或Roughness甚至有些项目还会把AO塞进别的通道。之所以要这样打包一是省内存、省采样二是因为这些数据是灰度值根本不需要占用三个颜色通道。很多美术在Substance Painter里导出一套PBR纹理时默认设置就是Roughness在R通道、Metallic在B通道之类但不同DCC工具、不同引擎的约定并不统一。到了Unity里你必须按Shader的预期做通道重映射否则金属度可能就是反的。这里有个很容易踩的细节Unity的Standard/URP Lit Shader对Smoothness贴图的默认约定是认为Smoothness数据放在Metallic贴图的Alpha通道里。你在Substance Painter里导出的是Roughness还是Smoothness又决定了你在Unity的材质面板里要不要把数据取反Roughness 1 - Smoothness。这些转换看起来简单大批量调材质的时候却极其折磨人。我建议团队在项目启动第一天就定一张贴图通道映射表把Base Color、Normal、MetallicSmoothness、AO分别放在哪个文件的哪个通道写清楚美术、TA、程序各拿一份。2.4 反射探针PBR效果好的隐形支柱很多人以为PBR就是把Metallic拉高、Smoothness拉高材质就亮晶晶的这个理解只看到了一半。PBR之所以真实不仅仅是因为直接光高光算得准更大比例来自间接光也就是环境反射光。金属表面尤其依赖环境反射一块抛光的金属如果没有任何周围环境可以反射它看起来就是一块黑灰色的平面完全没有金属质感。在Unity里环境反射主要靠反射探针Reflection Probe提供。每个封闭的房间、走廊、室内空间都应该单独放置反射探针烘焙出该位置的Cubemap物体移动时Unity会根据它所在的Reflection Probe产生的反射信息来贡献镜面反射。金属越光滑对反射内容的位置越敏感你站在走廊尽头看地板上一条长长的金属栏杆如果反射里带着走廊尽头的灯光和墙面质感一下就出来了。只靠天空盒反射做金属效果会非常单薄这是新手最容易忽略的一环。3. 传统Blinn-Phong和PBR的正面差异到底在哪3.1 从高光形态到能量守恒差异是全方位的传统Blinn-Phong模型的高光是一个靠指数项控制的光斑指数越高光斑越窄越亮边缘平滑柔和。听起来挺好用但它缺少一个关键的东西微表面模型。Blinn-Phong的高光不区分粗糙表面的长尾巴高光也不考虑不同材质对不同波长的反射差异所以它的高光形态和真实世界差得很远。PBR里的高光一般用GGX/微表面BRDF来计算。直观上的区别是GGX高光在主角高光周围会拖出一个更长、更柔和的衰减尾巴这在拉丝金属、被刮花的漆面上特别明显Blinn-Phong的高光更像一颗贴上去的光斑说改就改效果不太经得起实物对照。另一个差异是能量守恒PBR材质在强光下不会无限变亮漫反射和镜面反射的总和有一个物理上限传统模型就没有这个约束你把Specular和Diffuse都调满材质立刻就成自发光体。3.2 金属像塑料的根源在于高光颜色被写死了以前做传统光照模型的项目我最常见的一个怪病是金属材质怎么调都像塑料。本质原因是Blinn-Phong的高光颜色通常是白色或者跟Specular Color绑在一起而真实金属的高光反射是会带有金属自身颜色的金的高光偏黄、铜的高光偏橙、铁的高光是灰色的。非PBR材质基于白光高光金属的固有色和反射色没有关系自然怎么看都不对。PBR里金属的反射率由Base Color直接参与BRDF计算高光颜色会自动带上金属固有色这是金属感的一个重要来源。3.3 一张表看明白新旧差异对比维度传统光照模型Blinn-Phong等PBRStandard/Lit Shader材质参数语义Diffuse、Specular、Shininess描述在灯光下的样子Metallic、Roughness/Smoothness、Base Color描述材质本身属性能量守恒不强制容易过曝、自发光强制反射能量不超过入射能量高光模型指数光斑边缘均匀过度GGX微表面高光带长尾衰减更接近真实材料间接光/环境光常用常量环境色比较平依赖环境贴图/反射探针环境光带方向和颜色跨软件一致性参数无标准DCC到引擎要重调材质参数可标准化Substance Painter/Maya/Unity打通跨平台表现换个平台或光照环境材质性格大变灯光与材质解耦换环境后按物理规则变化偏差小美术与程序协作依赖个人感觉口头沟通成本高参数范围明确可量化可制定规范这张表比较粗糙但覆盖了绝大多数项目里能遇到的差异。如果只是针对某个简单道具做一次性渲染传统模型确实也能混过去但放到一个长线项目里PBR在一致性和协作效率上的优势会指数级放大。4. 为什么项目非换PBR不可工作流收益比画面收益还重要4.1 DCC工具与引擎终于能所见即所得了我见过不少团队评估PBR时注意力全放在画面好不好看上其实PBR最大的价值在制作环节。在传统流程里美术在Maya或Blender里调好的材质导入Unity之后几乎肯定要重新调一遍因为两边的光照模型和参数体系根本不一样。到了PBR时代Substance Painter、Quixel、Marmoset Toolbag这些工具都采用了同一套基于物理的材质描述Substance里刷出来的金属锈迹、布料纹理、皮革褶皱导出PBR贴图后在Unity的Standard/Lit Shader里打开效果非常接近只需要根据引擎做小幅修正。这个所见即所得对项目进度的提升是实实在在的。以前一个角色材质从DCC到引擎要往返修改两三天现在基本当天就能定掉。即便是团队里有人用Unity的Shader Graph做材质PBR节点那一套输入也是同样的金属度、粗糙度、反射率切换工具的成本也很低。4.2 外包协作和跨平台一致性有了统一标准PBR参数对团队协作的改善可能比画面提升更重要。传统材质参数因为语义模糊外包团队给的金属高光和你的金属高光经常是两回事最后只能靠主美一版一版地返工。PBR参数可以写进规范金属度0到11代表纯金属粗糙度0到10代表镜面。数值本身就是标准美术之间可以不用反复看效果猜意图。跨平台差异方面PBR也让问题收敛了很多。不同硬件平台、不同渲染管线的差异主要体现在色彩空间、Tonemapping、光照烘焙精度上材质本身的性格是一致的而传统模型下同一个材质在PC上能亮瞎眼到了手机上可能直接一团黑。项目做多平台发行时这种一致性省下的QA时间非常可观。4.3 程序与TA团队能做的事变多了程序团队同样受益。因为PBR的材质语义统一Shader数量可以大幅压缩项目里不再需要五花八门的Legacy Shader变体性能预算更容易做。想做优化的时候也能基于物理规律做近似移动端可以用简化的高光模型替代完整GGX但对材质数据本身金属度、粗糙度不做破坏所以顶多损失一点细节不会破坏整体观感。很多团队把PBR理解成只能做写实这是最大的误解。现在市面上大把二次元风格化项目底层渲染数据就是PBR只是在上层用NPR非真实感渲染手段控制最终输出脸部阴影做柔化、头发高光改成风格化片状、把金属反射强度压低等等。PBR给这些项目提供的是物理正确的数据基础NPR负责审美表达二者不是对立关系。你去看Unity社区里讨论的shader npr 卡通渲染话题很大一部分都是在PBR渲染管线之上做风格化改装的。5. Unity项目落地PBR五大高频坑与排查思路5.1 颜色空间还停在GammaPBR效果直接打七折很多老项目从Built-in时代一路升上来Project Settings里的Color Space还是Gamma。在Gamma空间下做PBR计算纹理的颜色空间转换、光照的能量分布都不对最终画面容易发灰高光边缘发脏暗部细节糊成一片。这几乎是PBR项目最常见的第一个坑。排查方法很简单打开Edit Project Settings Player在Other Settings里看Color Space是不是Linear。不是Linear的话改成Linear然后重新烘焙光照、重新检查所有材质。我心里清楚改这一点在新项目里容易做老项目里阻力很大因为所有场景的光照、材质、后处理都会跟着变。但从PBR落地的角度来说这件事越早做越好。拖延的后果是团队会在一个错误的基础上疯狂调整材质参数越调越乱最后全项目返工。5.2 数据贴图的sRGB设置错了金属度和粗糙度全乱掉PBR项目里有两类贴图一类是颜色贴图比如Base Color、光照贴图这类要在导入设置里勾上sRGB作为颜色纹理处理另一类是数据贴图比如Metallic、Roughness/Smoothness、AO、法线贴图这些不是颜色而是数值导入时绝不能当作sRGB处理。如果你把金属度贴图留成了sRGB引擎会对它做一次Gamma到Linear的转换数值全部被提亮金属度的分布直接就变了。Unity的Texture Import Settings里法线贴图要设成Normal Map以sRGBGamma纹理这个选项在数据贴图上必须关掉。新来的同学经常在这个地方翻车看不出来问题在Shader还是贴图直到我让他们逐张贴图检查Type和sRGB标志改完就正常了。凡是出现金属区域大面积反光粗糙度表现异常的问题先查贴图导入设置别急着去调Material面板。5.3 金属物体发灰发黑反射探针布置不到位如果场景里放了一个Metallic1、Smoothness很高的球结果它看起来灰灰的没有光泽那大概率不是Shader的问题而是它没得反射。前面说过金属表面几乎是纯镜面反射它需要环境里有东西可以反射。场景里如果只有默认天空盒反射探针没烘焙金属物体就只能反射到天空的一个大体颜色自然没有任何金属感。正确的做法是在每个封闭空间放反射探针并设置好它的影响范围。对于动态物体可以在Mesh Renderer的Lighting设置里把Reflection Probes选成Blend Probes让多个探针平滑过渡对大空间或者动态变化的环境用Realtime模式的探针或者Time-Sliced更新来降低性能开销。另外金属越光滑反射内容的位置越真实如果探针位置和物体实际位置差距太大反射角度就会露馅。5.4 灯光强度单位混乱开了Tonemapping之后过曝发白PBR效果讲究灯光强度、材质反射率、摄像机曝光三者匹配。很多项目还是老思维Directional Light强度习惯性填1材质全调好之后一看亮部全爆白。这是因为PBR计算出的高光能量本身更高配合Tonemapping之后阈值超过1的亮度会被压缩甚至切开。我的经验做法是先固定一组基准灯光参数比如Directional Light的Intensity在1.5到3之间浮动再配合ACES Tonemapping。材质上Base Color保持真实的明度一张白纸是0.9到1纯黑是0.02左右不要为了更亮把Base Color拉到1以上让材质自发光。选Point Light或Spot Light时在URP/HDRP里可以开启物理灯光单位光度学计算更接近真实灯光但也别一下子给特别大的数值让灯光的衰减曲线和强度一起进Tonemapping再看效果。高光爆掉的时候先降灯光强度再考虑调Tonemapping的对比度顺序反了会越调越脏。5.5 移动端PBR性能翻车贴图爆炸、高光计算过重PBR不是没有代价的。对比传统Blinn-PhongPBR需要多采样金属度、粗糙度等贴图GGX高光计算的三角函数也比较重。如果在移动端直接套PC的材质方案帧率和发热很快会教做人。这里我个人的优化思路是贴图通道合并把Metallic、Smoothness、AO打包进一张贴图最多再加一张独立的Base Color和Normal Map把单材质贴图数量控制在4张贴图以内移动端直接用URP配合SRP Batcher让材质属性尽量统一批次场景多光源情况下优先用Baked Lightmap Light Probe减少逐像素实时灯光数量Shader层面可以去掉不必要的特性清漆层、各向异性这些炫技功能在移动端统统关闭。如果实在要压性能可以换一个简化高光版本的PBR Shader但保留Metallic和Roughness输入这样不同平台差异不会大到材质完全变样的程度。这些优化的顺序也值得讲一下先做材质属性与光照烘焙层面的优化再动Shader因为前者改动小、回归成本低后者动起来容易引入新的显示差异。6. 商业项目实例从写实军事到风格化二次元6.1 写实路线《逃离塔科夫》这类射击项目的PBR用法《逃离塔科夫》是目前市场上比较有代表性的Unity写实项目之一。从公开的技术分享和社区拆解来看它的武器、装备、室内场景大量使用基于物理的材质表现金属枪身对室内灯光的反射、木托的粗糙度差异、织物和尼龙材质的漫反射、旧化和磨损带来的AO细节。之所以这类游戏非PBR不可是因为玩家需要一眼读懂不同材质之间的区别哪把枪用了什么涂装、地面是金属板还是木地板这是写实潜行射击游戏里玩法和可读性的基础。做得好的军事写实类项目通常还会在PBR基础上叠加细节用详细贴图拆分金属脏污、锈渍的局部粗糙度差异用反射探针让枪械在不同房间里有不同的反射内容。这样一来玩家持枪走过不同区域时枪身会随环境灯光和墙面颜色实实在在地变脸这就是PBR材质在真实场景里的核心价值。6.2 风格化路线《原神》《崩坏星穹铁道》的PBR底层很多人觉得米哈游的项目是NPR二次元跟PBR没关系。其实从公开的分享和GDC、Unite相关材料来看它们的角色材质尤其皮肤和布料部分底层也是基于物理的数据组织方式只是在上层做了大量风格化改造面部阴影用SDF阴影头发高光变成多条风格化的硬色块衣服褶皱改成手绘感的AO金属部分也会刻意提亮或压暗来贴合作品审美。这说明一个关键点风格化不是不PBR而是把PBR数据当作材料清单再按风格需求重排最终输出。一个角色设定衣服是厚呢料、铠甲是哑光铁、头发是高光塑料质感有了PBR这套语义描述美术才能把这些材质属性管理清楚再递给shader做风格化处理。完全抛弃PBR、全手绘贴图的项目当然也存在但管理成本和跨平台差异都更大。6.3 Unity官方演示片与企业级应用Book of the Dead、汽车配置器Unity官方出过不少技术演示用HDRP跑PBR的《Book of the Dead》是最典型的一个。它展示了一片以写实树叶、地面、岩石和光影为主的森林场景PBR材质在自然光下的反射、漫反射响应非常可信。另一个是《The Heretic》它重点展示了次表面散射、皮肤材质和面部细节而皮肤材质的底色、粗糙度、高光分布这套数据组织方式同样是PBR的逻辑。企业级应用里汽车行业是PBR的重度用户。保时捷、劳斯莱斯这些品牌与Unity合作做车辆配置器、数字孪生演示最核心的需求就是车漆、真皮座椅、铝合金轮毂、玻璃在不同光照条件下要呈现几乎可以乱真的效果。车漆这种多层材料需要在PBR基础上叠加清漆层和金属微粒的反射效果没有物理正确的底层光是做不到的。这种材质保真需求也延伸到建筑可视化、文物保护、医疗仿真等领域Unity里的PBR技术在这些非游戏场景里反而成了标配。6.4 案例带来的统一结论PBR是一种数据组织方式而非审美模板看完这些案例我想强调一个容易被忽略的结论PBR并不等于写实化它更接近一种材质定义的通用语言。同一套Metallic/Roughness数据写实项目会拿去做物理正确的反射和明暗风格化项目会拿去控制非真实感输出的材质分界。正因为有了这套通用语言团队之间的协作、跨软件流转、跨平台适配才有了共同的语法。我做项目的时候最大的体会是PBR不要求你懂多少光学物理但它要求你对材质数据有敬畏心把贴图类型搞对、把通道打包规则定好、把反射探针放对位置比在Material面板上拉两下Smoothness重要得多。很多看起来PBR效果不好的抱怨查到最后都落在这些基础工程问题上。如果你也正在Unity里切换PBR别急着折腾Shader先按上面这五个坑逐项排查一遍多半能省下好几天调试时间。具体数值和规范怎么定每个项目可以根据美术方向灵活调整但语义正确、数据规范、灯光解耦这三条原则是PBR项目能跑通的地基。