ARTICLE DETAIL

资讯详情

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

Unity URP管线PBR材质制作:从BRDF原理到移动端性能优化实战

Unity URP管线PBR材质制作:从BRDF原理到移动端性能优化实战 1. PBR 与 URP 管线的基础认知重构1.1 为什么选择 URP 管线做 PBR 学习很多人入门 PBR 的第一反应是直接上 HDRP觉得效果越华丽越好。我一开始也是这个思路结果在 HDRP 里折腾了两周连一个正确的金属球都没调出来。后来退回到 URP 重新梳理才发现问题不在管线本身而在于我对 PBR 的基础认知是断裂的。URP 管线做 PBR 学习有几个非常实际的优势。第一它的 Shader 代码结构清晰Lit Shader 的源码量适中不像 HDRP 那样被大量的体积雾、光线追踪、次表面散射等高级特性包裹导致你很难看清 BRDF 的核心计算流程。第二URP 的渲染路径相对简单Forward 和 Deferred 的切换逻辑明确方便你对照理解不同路径下 PBR 计算的差异。第三URP 的跨平台兼容性好你在编辑器里调好的材质参数打包到移动端后偏差相对可控这对建立“参数直觉”非常重要。我个人的建议是如果你刚接触 PBR先把 URP 的 Lit Shader 吃透再去碰 HDRP 或自定义 SRP。这就像学做菜先把一道番茄炒蛋做到火候精准再去研究分子料理。1.2 PBR 核心参数到底在控制什么PBR 的全称是 Physically Based Rendering基于物理的渲染。这句话的关键词不是“渲染”而是“物理”。它意味着材质的每一个参数都对应着现实世界中的某种物理量而不是美术凭感觉随便拉的滑块。在 URP 的 Lit Shader 里最核心的参数就那几个Base Map基础贴图、Metallic金属度、Smoothness光滑度、Normal Map法线贴图、Height Map高度图、Occlusion环境光遮蔽。很多人会把 Metallic 和 Smoothness 混在一起理解觉得“金属就是亮光滑就是反光”这其实是不对的。Metallic 控制的是材质的“导电性”。金属度接近 1 的材质漫反射几乎为零所有入射光要么被镜面反射要么被吸收。金属度接近 0 的材质比如塑料、木头、皮肤漫反射占主导镜面反射很弱。Smoothness 控制的是微观表面的平整程度它直接决定高光斑的锐利程度和反射的清晰度。一个粗糙的金属Metallic1, Smoothness0.2看起来是哑光的一个光滑的塑料Metallic0, Smoothness0.9看起来是亮面但反射模糊。这里有一个我踩过的坑很多人会把 Smoothness 和 Roughness 搞混。URP 用的是 Smoothness值越大越光滑而有些引擎或教程用的是 Roughness值越大越粗糙。两者是反关系即 Roughness 1 - Smoothness。你在看教程时一定要先确认对方用的是哪个。1.3 BRDF 在 URP 中的实际计算流程BRDF 是 Bidirectional Reflectance Distribution Function 的缩写双向反射分布函数。这个名字听起来很学术但它的本质就是回答一个问题一束光打到表面上有多少能量被反射到观察者方向在 URP 的 Lit Shader 中BRDF 的计算被拆分成两部分漫反射项Diffuse和镜面反射项Specular。漫反射项用的是 Lambert 模型简单说就是光线方向与法线方向的点积再除以圆周率 π 做归一化。镜面反射项用的是 GGX 分布这是目前实时渲染中最主流的微表面模型。GGX 的核心思想是把表面看成由无数微小的镜面组成每个微镜面的朝向服从某种统计分布。Smoothness 越高微镜面朝向越集中高光越锐利Smoothness 越低微镜面朝向越分散高光越模糊。这个分布函数叫 D 项再加上几何遮蔽项 G 和菲涅尔项 F合起来就是著名的DFG 模型。URP 的 Lit Shader 里这些计算被封装在Lighting.hlsl和BRDF.hlsl两个文件中。你可以在 Package Manager 里找到 Universal RP 包然后定位到Shaders/LitForwardPass.hlsl顺着UniversalFragmentPBR函数一路跟下去就能看到完整的 BRDF 计算链路。我强烈建议你至少手动跟一遍这个流程比看十篇理论文章都管用。2. URP 中 PBR 材质制作的核心细节与实操要点2.1 金属度与光滑度的参数搭配逻辑在 URP 的 Lit Shader 里Metallic 和 Smoothness 是分开的两个滑块但它们在物理上是有关联的。现实世界中纯金属的 Smoothness 通常较高因为金属表面容易抛光而氧化或粗糙的金属 Smoothness 较低。非金属材料的 Smoothness 范围很广从橡胶的 0.1 到玻璃的 0.95 都有。我整理了一份常用材质的参数参考表这些值是我在实际项目中反复调试后总结的可以直接拿来用材质类型MetallicSmoothness备注纯金1.00.85-0.95颜色贴图用金色不要用默认白纯银1.00.90-0.95颜色贴图用浅灰白铝1.00.80-0.90比金和银稍粗糙铁1.00.70-0.85未抛光时更低塑料0.00.60-0.90看表面处理哑光塑料 0.3-0.5橡胶0.00.10-0.30几乎无高光木材0.00.20-0.50清漆处理后可到 0.7皮肤0.00.30-0.50需要配合次表面散射玻璃0.00.90-0.98需要透明模式陶瓷0.00.70-0.90釉面陶瓷更高注意这张表里的 Smoothness 是 URP 的取值如果你用的是 Roughness 工作流记得做 1-x 转换。这里有一个非常关键的实操心得金属材质的颜色贴图必须是有颜色的而非金属材质的颜色贴图应该是去饱和的。很多新手会把金属的 Base Map 做成灰色然后指望 Metallic 滑块来出金属感结果渲染出来像一块灰铁。正确的做法是金属的 Base Map 直接给金色、银色、铜色等Metallic 拉到 1Smoothness 根据粗糙程度调整。非金属的 Base Map 给实际颜色Metallic 保持 0。2.2 法线贴图与高度贴图的正确使用姿势法线贴图在 URP 里有一个容易忽略的细节法线贴图的导入设置必须正确。在 Unity 的 Texture Import Settings 里Texture Type 要选 Normal MapCreate from Grayscale 不要勾除非你确实是从灰度图生成法线。如果导入设置错了法线方向会完全乱掉表面看起来像被扭曲了一样。法线贴图的强度由 Normal Map 旁边的滑块控制默认是 1。这个值不是越大越好。我见过很多项目把法线强度拉到 2 甚至 3结果表面细节看起来像刀刻的一样生硬。一般来说0.8 到 1.2 之间是比较自然的范围。如果你觉得细节不够应该去改法线贴图本身而不是无脑拉强度。高度贴图在 URP 的 Lit Shader 里叫 Height Map它需要配合 Parallax 参数使用。Parallax 是一种视差效果让表面看起来有真实的凹凸深度。但这里有一个性能陷阱Parallax 在移动端非常昂贵因为它需要在像素着色器里做多次纹理采样。如果你的项目要上移动端建议用 Normal Map 代替 Height Map或者把 Parallax 的采样次数降到最低。我个人的经验是对于大多数场景法线贴图已经足够表达细节了。高度贴图只在特写镜头或需要强烈立体感的物体上才值得用。比如一面砖墙法线贴图能表现砖缝的凹凸但如果你想要砖块边缘有真实的遮挡感那就需要高度贴图加 Parallax。2.3 环境光遮蔽与反射探针的配合Occlusion Map 在 URP 里叫 Occlusion它控制的是环境光在缝隙处的衰减。很多人会把 Occlusion 和阴影搞混其实它们完全不同。阴影是直接光被遮挡Occlusion 是环境光被遮挡。一个物体在阴影里但它的缝隙处仍然可能接收到环境光Occlusion 就是用来压暗这些缝隙的。在 URP 里Occlusion 的强度由 Occlusion Strength 滑块控制默认是 1。如果你发现模型缝隙处太黑可以适当降低这个值。但要注意Occlusion 贴图应该是烘焙出来的而不是手绘的。手绘的 Occlusion 往往不符合物理规律会导致光照看起来不自然。反射探针是 URP 里做 PBR 反射的关键组件。没有反射探针金属材质只能反射天空盒看起来会很假。反射探针的放置有几个原则第一探针要放在场景中反射影响最明显的区域第二探针的 Type 要根据场景大小选择Baked 适合静态场景Realtime 适合动态物体但性能开销大第三探针的 Resolution 不要盲目拉满128 或 256 在大多数场景下已经足够。提示在 URP 里反射探针的强度可以通过 Lit Shader 的 Specular Highlights 和 Environment Reflections 两个开关分别控制。如果你想要金属反射更明显确保 Environment Reflections 是开启的。3. 从零搭建一个 URP PBR 测试场景的完整流程3.1 项目初始化与 URP 配置第一步创建一个新的 Unity 项目模板选择 3D (URP)。如果你用的是 Unity Hub在创建项目时直接选 URP 模板即可。如果你是在已有项目里切换管线需要先安装 Universal RP 包然后创建 URP Asset再在 Project Settings 的 Graphics 里指定这个 Asset。URP Asset 的配置有几个关键点。Lighting 部分Main Light 的 Shadows 要开启Additional Lights 的 Per Object Limit 根据场景灯光数量调整一般 4 到 8 够用。Quality 部分Anti Aliasing 建议选 MSAA 4xHDR 要开启这样高光才不会过曝。Shadows 部分Shadow Distance 不要设太大50 到 100 米足够太大反而会让阴影贴图精度下降。这里有一个我踩过的坑URP 的 Render Scale 默认是 1.0但如果你在移动端做测试可以降到 0.8 或 0.9 来提升性能。不过要注意Render Scale 降低后法线贴图的细节会丢失因为法线贴图对分辨率很敏感。3.2 创建测试材质与场景布置在 Project 窗口右键Create Material然后在 Inspector 里把 Shader 改成 Universal Render Pipeline/Lit。这就是 URP 的标准 PBR Shader。场景布置我建议用一个经典的“PBR 测试球阵”一排球体每个球体用不同的 Metallic 和 Smoothness 组合。比如 Metallic 从 0 到 1 分五档Smoothness 从 0 到 1 分五档一共 25 个球。这样你可以直观地看到参数变化对最终效果的影响。灯光方面用一个 Directional Light 做主光强度 1 到 2角度调成 45 度左右。再加一个 Point Light 做补光强度 0.5 到 1放在球的侧后方。环境光用 Gradient 或 SkyboxIntensity 控制在 0.5 到 1 之间。如果你想要更真实的反射可以在场景里放一个 Reflection ProbeBake 一下。注意测试场景的背景不要用纯黑纯黑会让金属反射看起来像黑洞。用深灰色或渐变天空盒这样金属表面能反射出环境细节。3.3 逐参数调试与效果对比调试 PBR 材质时我习惯按固定顺序来先调 Base Map再调 Metallic然后调 Smoothness最后加法线贴图。这个顺序很重要因为前面的参数会直接影响后面参数的视觉效果。Base Map 阶段先给一个纯色确认颜色在光照下的表现。如果是金属给金色或银色如果是非金属给实际颜色。这时候 Metallic 和 Smoothness 都先保持默认Metallic0, Smoothness0.5。Metallic 阶段把 Metallic 从 0 慢慢拉到 1观察漫反射的消失和镜面反射的增强。你会看到Metallic 到 0.5 左右时材质看起来既不像金属也不像非金属这就是所谓的“半金属”在物理上是不存在的。所以实际项目中Metallic 要么是 0要么是 1中间值只用于过渡区域。Smoothness 阶段把 Smoothness 从 0 拉到 1观察高光斑的变化。Smoothness 低时高光斑大而模糊Smoothness 高时高光斑小而锐利。对于金属Smoothness 还会影响反射的清晰度。你可以放一个 Reflection Probe然后旋转视角看反射内容的变化。法线贴图阶段最后加法线贴图强度从 0.5 开始慢慢加。法线贴图会改变表面的微观朝向从而影响高光的形状。如果法线贴图太强高光会碎成很多小块看起来很不自然。3.4 性能分析与优化建议URP 的 PBR 性能开销主要来自三个方面像素着色器的 BRDF 计算、纹理采样、阴影和反射探针。BRDF 计算在 URP 里已经做了不少优化比如用近似公式代替精确计算。但如果你在移动端还是要注意 Additional Lights 的数量。每多一盏 Additional Light像素着色器就要多做一次 BRDF 计算。我建议移动端 Additional Lights 的 Per Object Limit 设为 2 到 4。纹理采样方面Lit Shader 最多会采样 Base Map、Normal Map、Metallic/Smoothness Map、Occlusion Map、Height Map 五张纹理。如果你用了 Height Map 加 Parallax采样次数会翻倍。移动端建议把 Metallic 和 Smoothness 打包到同一张纹理的 R 和 A 通道Occlusion 打包到 G 通道这样可以减少纹理采样次数。阴影和反射探针是性能大户。Shadow Distance 每增加一倍阴影贴图的渲染开销就增加一倍。Reflection Probe 如果是 Realtime 的每帧都要渲染六面 cubemap开销非常大。我建议静态场景用 Baked 探针动态物体用 Realtime 但降低 Resolution 和 Update Frequency。4. 常见问题排查与避坑经验实录4.1 材质发黑或过曝的排查思路材质发黑是最常见的问题原因通常有这几个法线贴图导入设置错误、Metallic 和 Smoothness 不匹配、环境光强度太低、反射探针缺失。排查顺序我建议这样先检查法线贴图的 Texture Type 是不是 Normal Map如果不是改过来重新导入。然后检查 Metallic 是不是 1 但 Base Map 是灰色如果是把 Base Map 改成有颜色的。接着检查环境光在 Lighting 窗口里看 Environment Lighting 的 Intensity 是不是太低。最后检查反射探针如果场景里没有探针金属只能反射天空盒看起来会很暗。材质过曝通常是 Smoothness 太高加上 HDR 没开导致的。Smoothness 到 1 时高光会非常集中如果 HDR 没开高光会直接截断成白色。解决办法是开启 URP Asset 里的 HDR或者把 Smoothness 降到 0.9 以下。4.2 金属反射不清晰的解决方法金属反射不清晰通常是因为反射探针的 Resolution 太低或者探针的位置不对。Reflection Probe 的 Resolution 默认是 128对于大场景来说太低了。你可以提到 256 或 512但要注意性能开销。探针的位置也很关键。探针应该放在场景中反射影响最明显的区域比如金属物体附近。如果探针离金属太远反射内容会不准确。另外探针的 Box Size 要覆盖金属物体的范围否则反射会错位。还有一个容易被忽略的点URP 的 Lit Shader 里有一个 Environment Reflections 的开关在 Specular Highlights 下面。如果这个开关没开金属不会反射环境探针只会反射天空盒。很多人找不到这个开关以为反射探针坏了其实就是没开。4.3 移动端 PBR 的性能陷阱移动端做 PBR 有几个硬性限制。第一纹理采样次数移动端 GPU 的纹理采样带宽有限五张纹理全采样会非常吃力。建议把 Metallic、Smoothness、Occlusion 打包到一张纹理Base Map 和 Normal Map 保留Height Map 去掉。第二Additional Lights 数量移动端建议不超过 4 盏。如果场景需要更多灯光考虑用 Lightmap 烘焙静态光动态光只保留主光。第三阴影质量移动端的阴影贴图分辨率不要超过 1024Shadow Distance 不要超过 30 米。软阴影在移动端也很昂贵建议用硬阴影或低质量的软阴影。第四反射探针移动端尽量用 Baked 探针Realtime 探针只在必要时用并且 Resolution 降到 64 或 128。我实测下来一个中等复杂度的移动端场景如果严格按照上述限制来配置URP 的 PBR 可以在中端手机上跑到 30 帧以上。但如果放开限制帧率会直接掉到 15 帧以下。4.4 常见问题速查表问题现象可能原因解决方法材质发黑法线贴图导入错误检查 Texture Type 是否为 Normal Map材质发黑Metallic1 但 Base Map 为灰色给 Base Map 上金属色材质发黑环境光强度太低提高 Environment Lighting Intensity材质过曝Smoothness 太高且 HDR 未开开启 HDR 或降低 Smoothness金属反射模糊反射探针 Resolution 太低提高到 256 或 512金属无反射Environment Reflections 未开在 Lit Shader 里开启该开关法线效果生硬法线强度过高降到 0.8-1.2 范围移动端帧率低纹理采样过多打包 Metallic/Smoothness/Occlusion移动端帧率低Additional Lights 过多降到 4 盏以下移动端帧率低Realtime 反射探针改用 Baked 探针提示这张表里的问题我几乎都遇到过尤其是“金属无反射”这一条当时排查了两个小时才发现是 Environment Reflections 没开。建议你遇到问题时先对照这张表过一遍能省不少时间。4.5 一些不那么常见但很关键的细节关于 Gamma 和 Linear 空间URP 默认使用 Linear 颜色空间这是 PBR 正确工作的前提。如果你在 Player Settings 里把颜色空间改成了 GammaPBR 的光照计算会完全错误材质看起来会发灰。所以永远不要在 URP 项目里用 Gamma 空间。关于纹理的 sRGB 设置Base Map 和 Occlusion Map 应该是 sRGB 的因为它们是颜色信息。Normal Map、Metallic Map、Smoothness Map、Height Map 应该是 Linear 的因为它们不是颜色信息。如果搞反了法线方向会错金属度会偏。关于 Shader Graph 和手写 Shader 的选择如果你只是做标准 PBR 材质用 Lit Shader 就够了。如果你需要自定义效果比如双面材质、卡通渲染、特殊的高光形状可以用 Shader Graph 或手写 HLSL。但要注意自定义 Shader 很容易破坏 PBR 的物理正确性除非你很清楚自己在做什么。关于双面材质URP 的 Lit Shader 默认是单面的。如果你需要双面材质比如树叶、布料、纸张可以在 Shader Graph 里把 Render Face 设为 Both。但双面材质会有法线翻转的问题背面法线需要手动翻转否则光照会错误。关于视图渲染和渲染队列URP 的渲染队列控制着物体的绘制顺序。Opaque 物体默认在 Geometry 队列2000Transparent 物体在 Transparent 队列3000。如果你发现透明物体遮挡了不透明物体或者渲染顺序不对检查一下材质的 Render Queue 设置。我在实际项目中还遇到过一个坑URP 的 Lit Shader 在移动端不支持 Parallax 的某些高级模式。如果你在编辑器里调好了 Parallax 效果打包到移动端后发现效果不对大概率是因为移动端不支持某些 Parallax 变体。解决办法是改用 Normal Map 加简单的视差偏移或者直接在移动端关掉 Parallax。最后分享一个小技巧如果你想要快速验证一个 PBR 材质的物理正确性可以把它放在一个纯白环境里用一盏标准强度的平行光照射。物理正确的材质在纯白环境下应该看起来和现实中的同类材质非常接近。如果看起来像塑料但你想做金属或者看起来像金属但你想做塑料那一定是 Metallic 或 Smoothness 设错了。这个方法我用了很多次比任何理论推导都直观。
返回列表