ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

URP管线PBR材质实战:从光照原理到贴图配置的避坑指南

URP管线PBR材质实战:从光照原理到贴图配置的避坑指南 1. 从一次材质翻车说起为什么我要死磕URP下的PBR去年做一个小场景项目美术同学丢过来一套Substance导出的材质金属度、粗糙度、法线贴图一应俱全在离线渲染器里预览效果相当能打。结果一进Unity的URP管线整个画面直接“塑料感”拉满——金属反射像糊了一层灰粗糙度过渡生硬暗部死黑一片。当时我第一反应是贴图导错了反复检查sRGB勾选、通道打包、法线格式折腾了大半天才发现问题根本不在贴图而在于我对URP管线里PBR光照模型的理解还停留在“会连节点”的层面。这件事之后我花了大概两周时间把URP的PBR实现从Shader源码到光照方程重新捋了一遍。这篇笔记就是那段时间的产物不是教科书式的理论推导而是我在实际项目里踩过坑、验证过、能直接抄作业的经验总结。如果你也在用URP做项目被材质表现折磨过或者想搞清楚“为什么同样的贴图在不同管线里效果差这么多”那这篇内容应该能帮你省下不少试错时间。先明确一下范围这里讨论的是**基于物理的渲染Physically Based RenderingPBR**在Unity **通用渲染管线Universal Render PipelineURP**下的落地实践。核心关键词就两个——PBR和URP管线。我会从光照模型的基本原理讲起一路拆到URP的Shader结构、贴图配置、参数调优最后给出一套我在项目里反复验证过的材质制作流程。适合有一定Unity基础、想深入理解URP渲染机制的开发者也适合美术同学了解底层逻辑后更好地配合程序调参。2. PBR到底“物理”在哪先把底层逻辑捋清楚2.1 从经验模型到物理模型一次思维方式的转变很多人学PBR的时候第一反应是去记公式什么Cook-Torrance、GGX、Smith背得滚瓜烂熟但一到实际调材质就懵。我一开始也是这样后来才想明白PBR的核心不是公式而是一套约束条件。传统经验模型比如Blinn-Phong的问题是参数没有物理意义高光颜色、强度全靠手感调换个光照环境就得重来。PBR做的事情是把材质的表达限制在几个有明确物理含义的参数上——基础色Base Color、金属度Metallic、粗糙度Roughness然后通过能量守恒和微表面理论保证材质在任何光照下都“讲道理”。这里有个关键点容易被忽略PBR不是某一个具体的Shader而是一套着色模型规范。URP里的Lit Shader是PBR的一种实现但PBR本身不绑定任何引擎。理解这一点之后你就不会纠结“URP的PBR和HDRP的PBR哪个更物理”这种问题了——它们都是近似只是近似程度和适用场景不同。2.2 能量守恒为什么你的金属看起来像塑料能量守恒是PBR最基础也最容易被违反的原则。简单说反射出去的光不能比入射的光多。在URP的Lit Shader里漫反射和高光反射是此消彼长的关系金属度高的时候漫反射趋近于零所有能量都给了高光反射非金属则相反大部分能量进入漫反射高光反射很弱。我见过最常见的翻车场景就是美术同学把金属度拉到1但基础色还是给了一个很亮的颜色结果渲染出来金属像发光的塑料。原因就在于金属的基础色实际上定义的是高光反射的颜色而不是漫反射颜色。铁的基础色是偏灰的金是偏黄的铜是偏橙的这些颜色直接决定了金属的反射色调。如果你给一个金属度1的材质配上纯白基础色那它反射出来的就是纯白高光看起来自然不真实。实操建议做金属材质时基础色不要凭感觉调去查真实金属的反射率数据。铁大约在0.56左右金在0.94到1.0之间偏黄铝在0.91左右。这些数值直接填进基础色比你自己调半天准得多。2.3 微表面理论粗糙度到底在控制什么粗糙度Roughness控制的是微表面的法线分布。你可以把物体表面想象成由无数个微小镜面组成粗糙度低的时候这些微镜面朝向一致反射集中看起来就是清晰的高光粗糙度高的时候微镜面朝向杂乱反射分散高光就变得模糊。URP的Lit Shader里粗糙度是通过GGX分布函数来影响高光反射的。这里有个实际项目里很容易踩的坑粗糙度贴图的通道和sRGB设置。在URP里金属度和粗糙度通常打包在同一张贴图的R通道和A通道Metallic/Roughness Map但这取决于你的工作流。如果你用的是Metallic/Smoothness工作流那A通道存的是光滑度需要做1-x的转换。我见过太多人因为通道搞反导致材质要么全反射要么全哑光排查半天才发现是贴图通道的问题。另外粗糙度贴图不能勾选sRGB因为它是线性数据不是颜色信息。这个细节在Unity里特别容易忽略因为默认导入设置是勾选sRGB的一旦忘了取消粗糙度就会被伽马校正导致材质表现完全不对。3. URP的PBR实现和标准管线到底差在哪3.1 URP Lit Shader的结构拆解URP的Lit Shader和内置管线的Standard Shader在光照模型上其实是一脉相承的都是基于Cook-Torrance的BRDF。但URP做了大量精简和优化最明显的区别在于光照的计算方式。内置管线是前向渲染每个逐像素光源都会完整计算一次BRDFURP默认也是前向但它把光照拆成了主光源Main Light和附加光源Additional Lights附加光源在移动端默认是逐顶点或者关闭的。这个差异直接影响了材质在不同平台上的表现。你在PC上调好的金属反射到了移动端可能因为附加光源精度不够高光直接消失。解决办法是在URP Asset里把Additional Lights的Per Object Limit调高或者干脆用烘焙光照来补。但要注意每增加一个逐像素光源性能开销是线性增长的移动端要谨慎。另一个关键差异是环境反射的处理。URP默认使用Reflection Probe和Lightmap来提供间接光照但如果你没有放置Reflection Probe环境反射就会回退到一个默认的球谐函数SH效果非常平淡。我建议在任何有金属材质的场景里至少放一个Reflection Probe并且把Resolution调到128以上否则金属反射会糊得没法看。3.2 光照模式的选择Forward、Deferred和ForwardURP支持三种渲染路径Forward、Deferred和Forward。这个选择对PBR材质的影响非常大但很多人是默认用Forward一路到底根本没想过切换。Forward是最常用的每个物体在渲染时计算所有影响它的光源。优点是兼容性好支持透明物体缺点是光源多了之后每个物体的Shader都会变得很重Overdraw严重。Deferred把光照计算推迟到屏幕空间所有不透明物体先渲染到G-Buffer然后统一计算光照。优点是光源数量对性能影响很小适合光源密集的场景缺点是不支持MSAAURP里Deferred和MSAA不兼容透明物体还是要走Forward而且G-Buffer的内存带宽开销不小。**Forward**是URP 14之后引入的算是Forward的升级版。它用Compute Shader做光源剔除把光源按屏幕空间分块每个物体只计算影响它的光源。这个模式在光源数量中等几十个的场景里表现很好既保留了Forward的灵活性又避免了全量计算。我的经验是移动端优先ForwardPC端光源多就上Deferred光源中等且需要MSAA就用Forward。切换渲染路径之后一定要重新检查材质的反射和阴影表现因为不同路径下的光照计算精度是不一样的。3.3 环境光照IBL在URP里的正确打开方式基于图像的光照Image-Based LightingIBL是PBR材质表现的关键。URP里IBL的主要来源是Reflection Probe和Lightmap。Reflection Probe提供镜面反射Lightmap提供漫反射间接光。这里有个很容易被忽略的细节Reflection Probe的Type选择。Baked模式在烘焙时生成 cubemap运行时开销最小Realtime模式每帧渲染开销大但能反射动态物体Custom模式可以指定一张 cubemap适合做风格化反射。大部分场景用Baked就够了但如果你有动态的金属物体比如旋转的奖杯那就需要Realtime或者至少放一个Realtime的Probe在附近。另外URP的Lit Shader里有一个Environment Reflections的选项可以控制反射的强度。这个值默认是1但有时候为了风格化效果美术会把它调到0.5甚至更低。我的建议是除非有明确的美术需求否则不要动这个值保持物理正确性。4. 贴图工作流从Substance到URP的完整链路4.1 Metallic/Roughness vs Specular/Glossiness选哪个PBR有两种主流工作流Metallic/Roughness和Specular/Glossiness。URP的Lit Shader默认支持Metallic/Roughness这也是我推荐的工作流。原因很简单Metallic/Roughness的参数更少更不容易出错而且能量守恒是自动保证的。Specular/Glossiness工作流给了你更多的控制权可以单独指定高光颜色和强度但这也意味着更容易违反能量守恒。如果你从别的引擎或者旧项目迁移过来可能会遇到Specular/Glossiness的贴图这时候需要在Substance里做一次转换或者用URP的Lit Shader配合自定义节点来适配。转换的核心逻辑是Metallic 1 - (Specular的灰度值 / 0.08)但这个公式只是近似实际转换还是建议在Substance Designer里用专门的转换节点来做避免手动计算出错。4.2 贴图打包通道分配和sRGB设置URP的Lit Shader对贴图通道有明确的约定搞错了材质就会出问题。下面这张表是我整理的标准配置贴图类型通道分配sRGB说明Base MapRGB勾选基础色颜色信息Metallic MapR不勾选金属度线性数据Roughness MapA不勾选粗糙度线性数据Normal MapRGB不勾选法线线性数据Occlusion MapG不勾选环境光遮蔽线性数据Emission MapRGB勾选自发光颜色信息最常见的错误就是把Metallic/Roughness贴图勾了sRGB导致金属度和粗糙度被伽马校正材质表现完全偏离预期。另一个常见错误是法线贴图的Import设置里选了“Normal Map”但忘了把Texture Type改成Normal Map结果法线信息被当成颜色处理光照全乱。实操技巧在Unity里选中贴图看Inspector底部的预览。如果法线贴图预览是偏蓝紫色的说明设置正确如果是彩色的说明Texture Type没改对。4.3 从Substance Painter导出到URP的完整步骤我在项目里用的最多的是Substance Painter导出配置直接决定了贴图能不能在URP里正确工作。以下是经过多次验证的导出流程在Substance Painter的Export Config里选择Unity URP预设。如果没有这个预设手动配置输出模板。输出贴图包括Base Color、Metallic、Roughness、Normal、Height、AO、Emission。在Unity里导入后把Metallic和Roughness合并到一张贴图的R通道和A通道。可以用Photoshop的通道操作也可以在Substance里直接输出合并后的贴图。检查每张贴图的sRGB设置Base Color和Emission勾选其余全部取消。法线贴图的Texture Type设为Normal MapCreate from Grayscale不勾选。在材质面板里把Metallic Map和Roughness Map指向同一张贴图URP会自动读取R通道和A通道。这套流程看起来简单但每一步都有坑。比如Substance导出的法线贴图默认是OpenGL格式Y而Unity用的是DirectX格式Y-如果不做翻转法线方向就是反的。解决办法是在Substance的导出设置里把Normal Map的Format改成DirectX或者在Unity里把法线贴图的Import设置里的“Flip Green Channel”勾上。5. 参数调优那些文档里不会写的实战经验5.1 Smoothness的数值感知从0到1到底意味着什么URP的Lit Shader里Smoothness是Roughness的反面1表示完全光滑0表示完全粗糙。但很多人对这个数值的感知是模糊的不知道0.5和0.6到底差多少。我整理了一个经验对照表方便快速定位Smoothness视觉效果典型材质0.0-0.2几乎无高光完全漫反射粗糙布料、未处理木材0.2-0.4微弱高光反射模糊皮革、哑光塑料0.4-0.6中等高光反射可见但不清晰抛光木材、陶瓷0.6-0.8清晰高光反射较锐利光滑塑料、涂漆金属0.8-0.95镜面高光反射清晰抛光金属、玻璃0.95-1.0完美镜面镜子、平静水面这个表不是绝对的因为高光的锐利程度还受光照角度和反射探针分辨率的影响。但作为一个快速参考能帮你避免“凭感觉调数值”的盲目性。5.2 金属度的二值化原则为什么0.5最尴尬在物理正确的PBR里金属度应该只有0和1两个值——要么是金属要么不是。现实中不存在“半金属”材质。但在实际项目里很多人会把金属度调到0.5左右试图做出“半反射”的效果结果就是材质既不像金属也不像非金属看起来非常奇怪。如果你需要“半反射”的效果正确的做法是保持金属度为0通过降低粗糙度来增强高光反射。非金属材质也可以有很强的高光比如光滑的塑料或者上釉的陶瓷它们的高光反射虽然不如金属强烈但足够清晰。把金属度当成“反射强度”来用是新手最容易犯的错误之一。当然有一种情况例外材质过渡区域。比如一个生锈的铁管锈蚀部分是非金属未锈蚀部分是金属这时候金属度贴图会有渐变。但这种渐变应该由贴图控制而不是手动调一个0.5的全局值。5.3 法线贴图的强度控制Normal Scale的合理范围法线贴图的Normal Scale参数控制法线影响的强度默认是1。很多人为了“增强细节”会把它调到2甚至更高结果光照完全乱掉表面看起来像融化的蜡。Normal Scale的合理范围通常在0.5到1.5之间。超过1.5之后法线的扰动会变得过于剧烈导致高光断裂和阴影错误。如果你觉得细节不够正确的做法是回到Substance里重新烘焙更高精度的法线而不是在Unity里硬拉参数。另外法线贴图的强度还和模型的UV密度有关。UV密度低的地方法线贴图的细节会被拉伸这时候适当降低Normal Scale反而能让效果更自然。6. 性能与效果平衡移动端PBR的取舍策略6.1 移动端URP的PBR精度降级移动端GPU的算力和带宽都有限URP在移动端默认会对PBR做精度降级。比如高光反射的BRDF计算可能会用近似公式环境反射的cubemap分辨率也会降低。这些降级在URP Asset里是可以配置的但很多人不知道。在URP Asset的Quality设置里有几个关键选项Shader Precision可以设为Half或Float移动端建议HalfReflection Probe Resolution可以降到64甚至32Additional Lights可以设为Disabled或Per Vertex。这些设置直接影响PBR材质的表现调低了性能上去了但金属反射会明显变糊。我的建议是移动端项目里金属材质尽量少用或者用MatCap来模拟反射。MatCap是一种假反射不依赖环境探针性能开销极低虽然物理不正确但在风格化项目里效果很好。6.2 烘焙光照与实时PBR的配合移动端最有效的性能优化手段是烘焙光照。把静态物体的间接光和反射烘焙到Lightmap和Reflection Probe里运行时只需要采样不需要实时计算。但烘焙有个前提物体必须是静态的Static而且光照设置不能频繁变动。对于动态物体比如角色和可移动的道具可以用Light Probe来提供间接光。Light Probe是空间中的采样点动态物体经过时插值获取间接光信息。但Light Probe不提供镜面反射所以动态金属物体还是需要Realtime Reflection Probe或者接受一个比较平淡的反射效果。这里有个实战经验把Reflection Probe的Type设为Baked但把Dynamic Objects勾上。这样静态物体用烘焙的cubemap动态物体用实时渲染的cubemap兼顾了性能和质量。不过这个选项在URP里的位置比较隐蔽在Reflection Probe组件的下方。6.3 一个实际的移动端材质优化案例我之前做过一个移动端的展示项目场景里有一个金属奖杯需要比较清晰的反射效果。最初的方案是用Realtime Reflection Probe每帧渲染cubemap结果在中端机上直接掉到30帧以下。优化过程分了三步第一步把Reflection Probe改成Baked烘焙时渲染一次运行时不再更新第二步把cubemap分辨率从256降到128反射虽然糊了一点但在手机屏幕上几乎看不出来第三步把奖杯的材质从标准Lit Shader换成一个自定义的简化Shader去掉了清漆Clear Coat和次表面散射Subsurface Scattering的计算只保留基础的金属反射。三步下来帧率回到了60帧视觉效果损失在可接受范围内。这个案例说明移动端的PBR优化不是简单地降参数而是要根据实际视觉需求做取舍。7. 常见问题排查材质不对时先查这几项7.1 金属反射发灰或发黑这是最常见的问题通常有三个原因。第一Reflection Probe缺失或分辨率太低环境反射没有足够的信息金属只能反射默认的球谐函数看起来就是灰蒙蒙的。解决办法是放置Reflection Probe并提高分辨率。第二环境反射的Intensity被调低了。在URP的Lighting设置里有一个Environment Reflections的Intensity选项默认是1。如果被改成0.5或者更低金属反射会明显变暗。第三基础色太暗。金属的基础色定义的是反射颜色如果基础色是深灰甚至黑色反射自然也是暗的。检查基础色是否在合理的反射率范围内。7.2 粗糙度过渡生硬粗糙度贴图的过渡不自然通常是因为贴图分辨率不够或者压缩设置不当。URP默认的贴图压缩格式是DXT5或者ASTC这种压缩对有损的粗糙度数据影响很大容易出现块状伪影。解决办法是把粗糙度贴图的压缩格式改成高质量High Quality或者干脆不压缩适合小尺寸贴图。另外在Substance里导出粗糙度时确保没有做过度的手绘调整粗糙度的变化应该是平滑的。7.3 法线贴图导致光照错误法线贴图的问题通常表现为表面看起来凹凸方向反了或者高光位置不对。原因可能是法线贴图的Y通道方向反了OpenGL vs DirectX或者法线贴图的sRGB被勾选了。排查步骤先检查法线贴图的Import设置Texture Type必须是Normal MapsRGB必须取消勾选。然后检查Flip Green Channel是否需要勾选。如果还是不对在Substance里重新导出一张法线贴图确保格式是DirectX。7.4 材质在Scene视图和Game视图表现不一致这个问题通常和光照设置有关。Scene视图默认使用自己的光照环境可能和Game视图的URP Asset设置不同。检查URP Asset里的Lighting设置确保Scene视图和Game视图使用相同的Environment Lighting和Reflection Probe。另一个可能的原因是Shader变体。Scene视图可能使用了简化版的Shader而Game视图使用了完整版。在URP Asset里把Shader Variant Limit调高或者手动触发Shader编译可以解决这个问题。8. 我个人的PBR材质检查清单每次做完一套材质我都会按这个清单过一遍能挡掉大部分低级错误基础色贴图是否勾选sRGB金属度和粗糙度贴图是否取消sRGB法线贴图的Texture Type是否为Normal MapY通道方向是否正确Metallic/Roughness贴图的通道分配是否和URP的约定一致场景里是否有Reflection Probe分辨率是否足够金属材质的基础色是否在合理的反射率范围内粗糙度的过渡是否平滑压缩格式是否合适移动端项目是否检查了URP Asset的精度设置动态金属物体是否有Realtime Reflection Probe或Light Probe支持这套清单看起来简单但每一条背后都是踩过的坑。尤其是sRGB和通道分配这两项我至少见过五次因为这两个问题导致的材质翻车排查起来又特别费时间因为表面上看贴图都是对的问题藏在导入设置里。最后分享一个我最近才搞明白的细节URP的Lit Shader里有一个Specular Highlights的选项默认是勾选的。如果你做的是风格化项目想要完全平坦的漫反射效果可以取消这个选项高光会完全消失。但如果你做的是写实项目千万别动它否则金属就不像金属了。这个选项在URP的文档里只是一笔带过但实际影响很大值得注意。
返回列表