
早在做内置渲染管线Built-in项目的时候我就开始用Standard Shader调材质那时候对PBR的认知基本停留在“拉一拉金属度、光滑度看起来像就行”。直到把项目切到URP管线才发现旧材质球全部变洋红、Shader失效一批键盘、金属零件得重做。也就是在这个被迫重构的过程里我决定系统地啃一遍PBR把底层的物理逻辑和高层的光照流程串起来。这篇文章就是把那段时间的学习笔记整理成一套可复用的实操流程适合刚接触URP、或者正在从内置管线迁移项目的朋友也适合那些已经在用PBR但说不出“为什么要分金属度和平滑度”的人。坦白说搜索PBR资料时总会顺带看到一个网络技术同名热词“策略路由”一开始我也担心是不是有某种联动读完发现那就是路由策略的简称跟图形渲染的PBR八竿子打不着本文只聊渲染领域这一套基于物理的光照模型。下面直接进入正题我会按照“原理理解 → 管线变化 → 材质实战 → 问题排查 → 性能优化”这条路线带你完整过一遍URP下的PBR工作流。1. PBR的核心思路从经验公式到物理模拟1.1 传统渲染为什么难调在PBR普及之前游戏渲染主要靠Blinn-Phong这类经验模型。美术要调的是一堆“高光颜色”“高光强度”“光泽指数”说白了就是纯经验值拼凑。同一个物体换个灯光角度高光位置可能还凑合但强度、衰减和对环境色的反馈经常完全不统一一个场景里有十个金属桶就得为每个桶单独调一组参数。更麻烦的是不满足能量守恒。传统模型里你可以同时把漫反射调得很亮、高光调得刺眼两者叠加后的反射能量在物理上已经超过入射光了但画面只是让人觉得“有点假”又说不上哪里不对。PBR的第一条规矩就是能量守恒反射出去的能量加上折射、散射、吸收的能量不能超过照进来的总量。金属因为没有折射反射率又高所以看起来干净且通透非金属则有一层漫反射加上一点高光。也就是说PBR不是为了“让画面更亮”而是想用同一套规则来约束所有材质叫它们在不同光线下都能一致地表现。这个东西的核心不是某个函数而是三个底层假设微平面理论、能量守恒、菲涅尔效应。1.2 微平面理论、菲涅尔与BRDF的直觉理解微平面理论并不难。你放大看任何物体表面都能看到大量朝向各异的小平面哪怕看起来光溜溜的塑料外壳也有微小的凸凹。粗糙度高的面这些微小平面法线方向散得厉害反射光就糊成一片光滑金属表面的微平面几乎平行反射就会形成锐利高光。对应到BRDF就是那套描述“光从哪个方向进来又会往哪个方向反射多少”的函数。常用的是Cook-Torrance BRDF里面由法线分布函数D、菲涅尔函数F和几何遮蔽函数G组成D管高光形状G管凹凸造成的自遮挡F管掠射角的反射强度变化。菲涅尔效应你用肉眼就能观察比如站在湖边低头看水面能大概看到水底往远处看水面上却是大片的波光那就是因为视线从垂直往掠射角移动时水面反射率越来越高。PBR里金属和非金属的菲涅尔基准值不同金属在垂直入射时反射率就已经很高非金属则从4%左右开始到掠射角才接近100%。这个差异直接决定了金属度参数的本质。生活化类比金属表面像一面高反射率镜子包括反射范围和亮度它都有自己的“底线”非金属更像磨砂亚克力板正面看接近半透明斜着看却会有一层明显的反光。PBR只是把这个直觉写成了可计算的数学公式。1.3 URP里的“物理”是简化物理需要先泼一盆冷水URP里的Lit Shader并不是学术意义上的完整光线追踪它是把PBR的核心参数金属度、平滑度、法线、AO等映射到一套近似光照模型上。好处是直观、性能可控坏处是别指望用它做折射、次表面散射这类进阶效果那需要额外定制Shader或者使用HDRP。理解这一点能避免后面踩“为什么我的玻璃没折射”的坑。URP体系里绝大多数材质都基于URP/Lit或其Shader Graph版本它们共享同一套PBR主节点。学会一个就能看懂一片。2. 从内置管线迁移到URPPBR有了哪些变化2.1 Shader和材质不兼容是第一个坎内置管线里的Standard Shader在URP下会直接“失效”材质球变成洋红色。原因是URP基于SRPScriptable Render Pipeline每个Pass的LightMode标记、Shader关键字、雾效处理都变了老Shader的语义不再匹配。迁移时不要一个个手动改Unity提供了批量转换工具Edit - Rendering - Materials - Convert Selected Built-in Materials to URP。选中一批旧材质它会自动把Standard/Standard (Specular setup)换成URP/Lit贴图通道基本能对应上但要记得转换后重新检查一遍金属贴图的颜色空间设置我下面会细说。这里先说结论URP/Lit的Metallic通道、Smoothness通道、Normal通道和Occlusion通道和内置Standard是一致的不存在重新拆通道的问题。注意批量转换工具不会处理你代码里通过Material.SetTexture动态赋的贴图尤其那些用脚本改主纹理的UI或者特效材质转换后要按Shader变更重新绑定属性名。2.2 URP渲染路径怎么选URP管线里有Forward、Forward、Deferred三种渲染路径PBR材质的表现和性能受这个选择影响很大。Forward最简单的逐物体光照URP最多只保证一定数量的逐像素光超出部分要么变成顶点光要么直接被舍掉。做移动端小项目够用但场景里放几盏点光源金属表面的高光就开始飘了。ForwardURP 14及以上版本的主推项它把相机的视锥体切分成一个个Cluster每个Cluster记录影响它的光源列表不需要逐物体遍历所有灯。这样可以在单Pass里支持更多实时光并且金属材质对多光源的响应正确很多代价是构建Cluster需要额外GPU开销。Deferred延迟渲染早期URP版本不支持后来加了但限制较多比如只支持Lit和SimpleLit Shader部分平台尤其移动端表现一般。我自己在PC项目里用Forward在移动端项目里老老实实用Forward而不是一上来就上Deferred。原因很简单URP的Deferred是为了PC游戏设计的移动端GBuffer带宽成本太高PBR贴图本身就是四张Full RGBA贴图再存一遍GBuffer很容易把带宽榨干。2.3 光照环境对PBR的影响被很多人低估同样一个材质球在灯光参数完全相同但环境光不同的场景里看起来会完全不一样。PBR里的金属材质反光非常依赖环境信息如果场景只有一盏方向光、没有反射探针金属表面除了一个太阳高光其余部分会呈现很脏的深灰或黑色这是正常的物理表现但很多人会误以为材质有问题。URP里要为PBR提供两样东西环境光Environment Lighting和反射探针Reflection Probe。环境光在Window - Rendering - Lighting - Environment里可以在Unity 2022以上的Lighting窗口配置通常靠Skybox生成的环境反射默认只能提供很模糊的全局反射对于金属、光亮塑料这类强镜面材质来说完全不够。所以尽量在关键物体周围摆Reflection Probe并把Type设为Realtime或Baked烘焙后金属表面的环境色才能明显变丰富。人物、动态道具这类不固定位置的物体搭配Light Probe Group补上漫反射探针信息即可。Light Probe管漫反射和间接光Reflection Probe管镜面反射。很多项目只拉亮环境光结果镜面反射还是很平就是因为没加反射探针。3. URP下PBR材质的贴图与节点实操3.1 贴图通道解构URP/Lit的默认PBR贴图组看起来复杂实际就是四张图加一张备用贴图Base MapAlbedo物体固有色不包含光照信息。金属的Albedo整体很暗因为金属吸收光并重新反射没有漫反射散射。如果你给金属做了很亮的Base Map出来的效果会很“塑料”。Metallic Map灰度图0表示非金属1表示金属。这通道不负责控制颜色控制的是反射特性和漫反射权重。Smoothness MapURP里直接叫Smoothness和传统粗糙度是倒数关系。贴图里白色表示光滑黑色表示粗糙。Substance Painter导出的是Roughness你要反色或者勾选Invert才符合美术习惯。Normal Map切线空间法线贴图给表面加细节凹凸。Occlusion环境光遮蔽贴图通常用在缝隙、底面让它更暗提升立体感。这里最容易出问题的是颜色空间。Base Map是颜色贴图必须走sRGB。Metallic、Smoothness、Normal、AO是数据贴图不是颜色导入设置时要关闭sRGB否则数值会被做一次Gamma变换导致金属度偏灰、平滑度失真。URP迁移工具偶尔会漏掉这个设置所以材质转换后一定要手动检查这份数据贴图的Texture Import Settings。3.2 Shader Graph里的连接方式用Shader Graph创建URP Lit Shader是更灵活的方式我的习惯是直接创建URP/Lit的Shader Graph然后按下面的节点连PBR主节点创建属性PropertiesBaseMapTexture2D、MetallicMapTexture2D、SmoothMapTexture2D、NormalMapTexture2D、AO MapTexture2D。每种贴图都需要Sample Texture 2D节点采样并把Type改对应。BaseMap的采样结果连到Fragment基础颜色。MetallicMap的采样结果连到Metal度。这里要注意URP默认允许Metallic和Smoothness共用一个通道如果美术只提供了一张Metallic贴图可以在采样后通过Split节点取R通道连Metallic取A通道连Smoothness。NormalMap采样后连NormalTangent Space需要时再连一个Normal Strength节点放大强度。AOMap采样结果连Occlusion。很多初学者会直接把贴图alpha通道连Opacity去调透明度URP/Lit默认是Opaque这样做没反应。要透明材质必须先把Surface Type设为Transparent再用Alpha连到Alpha通道。这也是为什么在URP里把“贴图明明带透明通道却不透明”的问题记得单独排查。3.3 亲手配一个金属螺栓材质我们来做一个最简单的螺栓金属材质作为练手第一步新建Shader Graph类型选URP/Lit命名Bolt_Metal。第二步在Graph Inspector里创建属性BaseMap和MetallicMap各自的Reference名字不要乱改后面做Prefab变体和代码SetTexture时要用。第三步把MetallicMap的Import Settings里的sRGB关掉作为数据贴图。第四步在图上连接BaseMap - Base ColorMetallicMap的R通道 - Metallic并用同一张贴图的Alpha通道连Smoothness如果这张贴图的Alpha刚好是光滑度。第五步设定Smoothness默认值为0.65左右晶格斗不够光滑的值往下拉到0.3再配合一张Reflection Probe看高光形态。实操心得调金属材质时不要急着堆高光强度先把Smoothness拉到0.7观察一遍高光边缘再拉金属度到0到1区间看漫反射消失的变化。先粗调大关系再精修细节比对着数值瞎试省时间得多。材质连完把它拖到一个简单的球体和圆柱上放一盏区域光Area Light或者矩形灯你会看到高光呈现长条状这就是BRDF里D项和G项在起作用。如果看到的高光是均匀圆形并且金属区域泛灰多半是缺少反射探针或者贴图sRGB没关。把这两点修复金属感立刻出来。4. 常见渲染问题与排查记录4.1 物体太黑或太亮不少朋友在URP里调好PBR材质放进场景发现暗得没法看。第一反应是调灯光强度但更要紧的是检查颜色空间。Project Settings - Player - Color Space建议设为Linear。Gamma空间下PBR的反射计算仍然使用线性数据再转换但光照衰减较多时容易出现暗部发灰、高光过亮的问题。如果你的项目直接开了Gamma换到Linear后很多材质观感会明显改善也顺手解决“金属像涂了黑漆”的现象。另一个过暗原因就是金属材质缺乏环境反射。金属物体几乎看不到漫反射你把Base Map调亮是没用的它不会像非金属那样散射。正确做法是给场景烘焙反射探针或在环境面板里接入HDR天空盒。过曝问题通常来自多方向光叠加或者HDR环境下Color Intensity超过了合理范围排查时使用Render Pipeline DebuggerWindow - Analysis - Rendering Debugger切到Material或Lighting模式可以直观看到哪个通道数值爆了。4.2 金属度和平滑度的常见误用最常见的问题是把粗糙度贴图直接当Smoothness用。很多在线资源导出的是Roughness黑色光滑白色粗糙。如果插到URP的Smoothness通道上你会发现所有高光全部糊掉金属变成粗糙塑料。解决方式有两种要么在贴图导入设置里勾选Invert让黑色变白色要么在Shader Graph里加一个One Minus节点。还有一个容易被忽略的点Metallic贴图的灰色值。正常金属应该是纯白或接近纯白非金属是纯黑。如果美术给了0.5灰度的金属贴图材质会显示出“半金属、半非金属”的混合状态表现成生锈或脏污。这种混合效果不是错但有些时候它只是错误贴图压缩导致的插值检查贴图格式是BC5或者BC7时某些通道的精度会下降灰度值被压缩到0.3-0.7之间看起来就像脏乱差。解决思路是在材质球上把Metallic贴图放大采样或者另建一张纯黑白Mask固定边界防止压缩造成的灰度漂移。实用检查法选中贴图后在Inspector里按住鼠标左键是直接预览像素值而不是色块。把鼠标放到金属区域Metallic通道读数应该在0.9以上Smoothness也要稳定在当前范围内这样你才能确认是通道配错还是数据本身有问题。4.3 粒子、地形和特殊材质坑URP下粒子的默认材质不是PBR它通常只支持sprite光照直接用来做金属碎片、火花这类效果会非常平。要模拟金属火花或碎石可以在Shader Graph里建一个URP/Lit材质Surface Type设为Opaque并把粒子系统的Renderer里的Material换成这个新材质。但注意粒子颜色会再乘到BaseColor上如果粒子是黑色的会乘成接近黑色。地形方面URP自带的Terrain Shader在URP 14以后支持Terrain Lit模式但默认的Terrain Layer如果不勾选Metallic/Smoothness地形会偏哑光。如果你想让路面在雨后显得湿润要新建一个URP/Terrain/Lit材质并且在Terrain Layer里手动贴Metallic或Smoothness图否则光调Albedo反光是没有任何反应的。我还在项目遇到过一个问题给模型加了Mesh Collider之后材质在URP下正常但进入VSync或某些后处理管线时轮廓突然出现银边后来发现是禁用HDR导致高光阈值被截断。这个现象在Reflection Probe反射比较强烈的时候特别明显建议开启HDR并在后处理Bloom里控制Bloom阈值而非直接关闭HDR。5. 性能考量与优化经验5.1 SRP Batcher与PBR材质的配合URP做性能优化的第一大杀器是SRP Batcher。它可以把不同材质球里相同Shader的材质属性合并提交大幅减少Draw Call的CPU开销。PBR材质四张贴图加一堆数值参数如果每个材质都不同Shader就没法合批Draw Call很容易飙到几百。要启用SRP Batcher在URP Asset的Inspector里勾选SRP Batcher即可。但材质必须满足Shader里所有材质属性都声明在CBUFFER_START(UnityPerMaterial)里而不是用传统的Properties直接进寄存器。URP/Lit和Shader Graph默认兼容自定义Shader如果不兼容Frame Debug里会显示“Objects are not SRP Batcher compatible”。实操心得判断优化空间时先开Frame Debug看Draw Call里哪类对象占大头。如果是纯静态摆放的金属道具可以用Static Batching优先合并如果是会动态旋转的角色和武器就靠SRP Batcher降低CPU开销两者不冲突。材质数量相同的情况下SRP Batcher往往能直接把Draw Call砍掉一半以上。5.2 材质变体和贴图开销PBR材质在Shader里默认会生成大量Keyword变体尤其URP/Lit有光照模式、雾效、阴影贴图等一系列开关。材质球的Metallic、Smoothness这类数值属性不会增加变体但Normal Map、Emission、Masquerade其实是Mask贴图勾选却会增加Keyword组合。在Quality Settings的URP Asset里可以关闭用不到的Feature比如不透明度贴图或者Detail Normal。资源维度的优化也很重要。金属反射依赖环境反射探针探针数量太多会直接拉高渲染开销。经验做法是静态金属物体烘焙成一层Cubemap探针动态道具用Light Probe Group和少量Realtime Reflection Probe即可。四张贴图尽量用压缩格式BC7常见于PCASTC更适合移动端不要一个材质贴四张4096那对内存和带宽都不友好。5.3 我建议的优化优先级如果项目突然变卡按下面的顺序排查别一上来就调画质材质合并与Atlas。先把场景里重复的金属碎片、箱子材质合并减少不同材质球数量。开启SRP Batcher并检查兼容。光影方面明确无需实时全局光照时把Realtime Global Illumination关掉用烘焙光照替代。反射探针数量限制。太密的探针比多两盏点光源更吃性能。变体裁剪。URP Asset里去掉用不到的渲染特性。一次实际项目优化中我通过材质合并把140个不同材质球减到52个再开SRP BatcherDraw Call从460降到210移动端帧率从27帧回到55帧以上。这中间PBR材质并没有牺牲任何视觉质量只是把资源组织方式理顺了。回到开头说的PBR不是万能药。URP里的PBR材质是接近物理规律的一套成熟方案但不是真正的物理正确渲染。想追求更写实的金属、玻璃、皮肤或者多层材质URP会逐渐不够用那时候可以考虑HDRP或者自定义Lit Shader但PBR这套“金属度-粗糙度-菲涅尔”的基础逻辑不会变。最后分享一个小技巧拿到任何材质球我都习惯先把它放到一个带粗糙灰环境、一盏硬光的测试房间看高光形态再放到真实场景看环境反射这样能快速区分“材质本身有问题”还是“光照环境没给够”。你的金属贴图再怎么调离了反射探针和环境光就是一坨黑灰这跟参数无关跟PBR原理有关。把这些基础理解透了后续不管是调角色皮肤还是做硬表面机甲都能少走很多弯路。