
1. 从“光照看起来不对劲”说起PBR到底在解决什么问题很多人第一次在URP里搭场景把材质往物体上一挂Directional Light一打发现效果跟想象中差得远——金属不像金属塑料不像塑料暗部死黑高光要么糊成一团要么刺眼得离谱。然后开始疯狂调参数Smoothness拉到0.9Metallic推到1结果更奇怪了。这个场景我见过太多次包括我自己早期也是这样过来的。问题的根源不在于参数没调对而在于没有理解PBR这套体系到底在做什么。PBRPhysically Based Rendering基于物理的渲染不是一个Shader的名字也不是某个特定效果它是一整套关于“光如何与表面交互”的数学建模框架。它的核心目标是让材质在不同光照环境下表现一致、让美术参数具有物理意义、让渲染结果可预测。URP管线下的PBR实现跟内置管线有相似之处但也有很多关键差异。URP用的是Lit Shader作为标准PBR材质底层基于BRDFBidirectional Reflectance Distribution Function双向反射分布函数模型具体来说是Cook-Torrance BRDF的简化版本。这套模型把反射拆成两大部分漫反射Diffuse和镜面反射Specular然后通过能量守恒把两者约束在一起。为什么这件事值得花时间搞清楚因为一旦你理解了PBR的底层逻辑调材质就不再是“试参数”而是“有目的地选择数值”。你知道Metallic1意味着什么、Smoothness0.5对应什么粗糙度、为什么非金属的Specular不能乱调。这些不是玄学是可以推导的。这篇文章适合谁看如果你已经在Unity里用过URP能搭基本的场景和光照但对PBR的理解还停留在“跟着教程调参数”的阶段那这篇笔记正好对路。如果你是完全的新手建议先把URP的基础渲染流程跑通再来看效果会更好。接下来我会从BRDF的数学结构讲起然后落到URP Lit Shader的具体参数再展开到Shader Graph里的自定义PBR实现最后聊一些实际项目中容易踩的坑。2. BRDF拆解Cook-Torrance模型里每一项到底在算什么2.1 漫反射项Lambert为什么“不够用”了最基础的漫反射模型是Lambert公式简单到不能再简单Diffuse Albedo / π * NdotL。这个/π很多人不理解为什么要除其实是为了能量守恒——半球积分下来入射能量等于出射能量不除π的话反射能量会凭空多出来。但在PBR体系里Lambert被保留了下来因为它对大多数非金属表面的漫反射描述已经足够好。URP的Lit Shader里漫反射部分用的就是Lambert的变体只不过Albedo会被Metallic参数调制——金属没有漫反射所以当Metallic1时Diffuse项直接归零。这里有个容易搞混的点Albedo在PBR里不是“颜色”而是“基础反射率”。对于非金属它表示漫反射颜色对于金属它表示镜面反射的F0垂直入射时的反射率。所以你在URP里调Base Map的时候实际上是在同时影响两个通道具体走哪条路取决于Metallic的值。2.2 镜面反射项D、G、F三项的物理含义Cook-Torrance的镜面反射项是PBR的核心公式长这样Specular (D * G * F) / (4 * NdotL * NdotV)分子里的D、G、F分别对应三个物理现象D项Normal Distribution Function法线分布函数描述微表面法线的统计分布。URP默认用的是GGX分布公式里涉及粗糙度参数α。α越小微表面法线越集中高光越锐利α越大法线越分散高光越模糊。Smoothness和α的关系是α (1 - Smoothness)^2这个平方关系是很多人没注意到的——Smoothness从0.9降到0.8α从0.01变到0.04高光面积直接翻了四倍。G项Geometry Function几何遮蔽函数描述微表面之间的自遮挡。当光线以掠射角入射时微表面的凸起会挡住部分反射光。URP用的是Smith-GGX联合模型跟D项共享粗糙度参数。这一项在掠射角下影响很大如果忽略它物体边缘会出现不自然的亮边。F项Fresnel菲涅尔项描述反射率随视角变化的现象。垂直看水面反射很弱斜着看反射很强。URP用的是Schlick近似F F0 (1 - F0) * (1 - NdotV)^5。F0对于非金属大约是0.04对应Specular0.5对于金属则等于Albedo。这三项乘在一起再除以4 * NdotL * NdotV做归一化就是完整的镜面反射贡献。分母里的4来自微表面模型的推导不是随便写的。2.3 能量守恒Metallic和Smoothness的联动逻辑PBR的能量守恒体现在Diffuse Specular 1。反射出去的能量不能超过入射能量。URP里通过两个方式保证这一点Metallic增大时Diffuse按(1 - Metallic)衰减Specular的F0按lerp(0.04, Albedo, Metallic)增大。Specular项本身在掠射角下会自然增强但不会超过1。这意味着你调Metallic的时候实际上是在“把能量从漫反射通道搬到镜面反射通道”。Metallic0.5不是“半金属”而是一个物理上不存在的混合状态实际项目中应该尽量避免中间值除非你在做特殊效果。Smoothness则控制高光的“锐度”不影响总能量。但它会通过G项间接影响能量分布——粗糙表面在掠射角下能量损失更多。注意URP的Lit Shader里有一个Specular Highights选项关闭后Specular项会被简化性能提升但物理准确性下降。移动端项目里常见这个取舍。3. URP Lit Shader参数面板每个滑条背后的物理量3.1 Surface Options不光是“表面类型”那么简单URP Lit Shader的Surface Options里有几个选项很多人直接默认不管但其实它们影响渲染路径和性能Workflow Mode有Metallic和Specular两个选项。Metallic模式用MetallicSmoothness控制Specular模式用Specular ColorSmoothness控制。两者在数学上等价但Metallic模式更直观Specular模式更适合非金属材质的精细调节。实际项目中金属材质用Metallic模式非金属用Specular模式这个分工比较合理。Surface Type的Opaque和Transparent影响渲染队列和深度写入。Transparent会关闭深度写入导致排序问题。如果只是需要简单的透明度优先考虑Alpha Clipping而不是Transparent前者保留深度写入性能更好。Render Face的Front/Back/Both控制剔除面。双面材质在URP里需要额外注意——Both会渲染两个Pass性能翻倍。如果只是需要单面透明效果用Front配合Alpha Clipping更划算。Alpha Clipping开启后Alpha低于阈值的像素直接丢弃。这个阈值Threshold的默认值是0.5但实际项目中要根据贴图调整。比如树叶贴图阈值太低会导致边缘残留太高会吃掉细节。3.2 Surface InputsBase Map和Normal Map的配合Base Map的Alpha通道在Opaque模式下会被忽略但在Alpha Clipping或Transparent模式下会参与计算。Normal Map的导入设置很关键——Texture Type必须设为Normal Map否则Unity不会做正确的解压和空间转换。Normal Map的强度通过Normal Map Scale参数控制但这个参数实际上是在Shader里对法线做lerp不是缩放贴图。强度为0时法线完全展平强度为1时使用原始法线。超过1的值会导致法线过强出现不自然的硬边。Occlusion Map影响间接光的遮蔽但在URP里它只影响GI部分不影响直接光照。如果场景没有烘焙GI这张贴图基本没用。Emission Map则是自发光配合Emission Color使用HDR颜色可以超过1配合Bloom后处理能出辉光效果。3.3 高级选项Specular Highlights和Environment Reflections这两个开关在Lit Shader的Advanced Options里默认都是开启的。关闭Specular Highlights会跳过D、G、F的计算直接用Albedo作为高光颜色性能提升明显但物理准确性下降。关闭Environment Reflections则跳过环境反射采样适合性能敏感的场景。Reflections的采样源取决于场景设置如果开了Reflection Probe就从Probe采样否则从Skybox采样。URP里Reflection Probe的混合模式有Simple和Blended两种Blended支持多个Probe平滑过渡但性能开销更大。提示移动端项目里如果场景没有Reflection ProbeEnvironment Reflections会从Skybox采样这可能导致室内场景出现不自然的天空反射。解决办法是在室内放一个Reflection Probe或者关闭Environment Reflections改用纯色环境光。4. 在Shader Graph里手搓一个PBR从节点到物理4.1 为什么要在Shader Graph里重写PBRURP自带的Lit Shader已经够用了为什么还要在Shader Graph里自己搭原因有几个需要自定义光照模型比如卡通渲染的阶梯高光、需要加特殊的材质效果比如清漆层、各向异性、或者需要优化性能去掉用不到的功能。Shader Graph里的PBR实现核心是把Cook-Torrance的公式用节点连出来。URP提供了BRDF节点和Lighting节点但如果你想完全控制可以自己用数学节点搭。4.2 关键节点的连接逻辑一个基础的PBR Shader Graph大概长这样Normal Vector节点获取世界空间法线经过Normal Map的扰动后输出。View Direction节点获取视线方向用于计算NdotV。Light Direction节点获取主光方向用于计算NdotL。Fresnel Effect节点可以直接算F项但URP的Fresnel节点用的是简化模型不如手写Schlick准确。Custom Function节点可以嵌入HLSL代码适合实现GGX分布和Smith几何项。D项的实现用Custom Function比较方便因为涉及幂运算和除法用节点连会很乱。G项和F项可以用节点搭但要注意精度问题——Shader Graph默认用half精度在移动端可能导致高光断裂。4.3 自定义光照的接入点Shader Graph里的Lighting节点负责把BRDF结果和光照颜色乘起来。如果你想改光照模型比如把Lambert换成Half-Lambert需要替换Diffuse的计算部分。URP的Lighting节点有一个Custom Light节点可以接入自定义的光照计算。实际项目中我一般会把PBR拆成两部分直接光照用自定义节点算间接光照用URP自带的SHSpherical Harmonics采样。这样既能控制直接光的BRDF又能保留URP的GI系统。注意Shader Graph里手搓PBR的性能不一定比Lit Shader好因为节点生成的HLSL代码可能有多余计算。如果只是需要微调优先考虑修改Lit Shader的源码或者用Material Property覆盖。5. 实际项目里的PBR踩坑记录5.1 金属材质在暗环境下“消失”这是最常见的问题金属材质在暗部完全看不见因为金属没有漫反射只有镜面反射而镜面反射依赖环境光。如果场景没有Reflection Probe金属在暗部就是一片黑。解决办法有两个一是放Reflection Probe二是给金属加一点Emission作为“伪环境光”。但Emission会破坏能量守恒所以数值要很小通常0.01到0.05就够了。5.2 Smoothness贴图的通道问题很多美术给的Smoothness贴图是灰度图但URP的Metallic Map把Metallic放在R通道Smoothness放在A通道。如果直接导入灰度图Smoothness会从Alpha通道读取而灰度图的Alpha通常是1导致Smoothness全为1高光锐利得不自然。解决办法是在导入设置里把Texture Type设为Default然后取消sRGB勾选再在Shader里用Remap节点把灰度值映射到Smoothness。或者让美术直接输出正确的通道打包贴图。5.3 法线贴图的绿色通道翻转不同软件对法线贴图的绿色通道定义不同OpenGL是YDirectX是Y-。Unity用的是OpenGL标准如果从其他软件导入的法线贴图看起来凹凸相反需要在导入设置里勾选Flip Green Channel。这个问题在URP里比内置管线更常见因为URP的Normal Map解压方式有变化。如果翻转后还是不对检查一下Normal Map的压缩格式——URP默认用DXT5nm这个格式只保留了两个通道第三个通道是重建的。5.4 透明材质的排序问题URP的Transparent模式默认按物体中心排序对于大面积的透明物体比如水面排序经常出错。解决办法是用Sorting Priority手动指定渲染顺序或者改用Alpha Clipping加Dither。如果必须用Transparent可以在Shader里开启Depth Write但这样会导致半透明物体互相遮挡时出现硬边。折中方案是用Depth Priming在URP Asset里开启后不透明物体先写深度透明物体再渲染能减少大部分排序问题。提示URP 12以上的版本支持Forward渲染路径透明物体的排序质量比Forward好很多但需要硬件支持Compute Shader。移动端项目要谨慎评估。6. 从BRDF到画面一些调参之外的经验PBR的数学框架是固定的但实际画面效果还受很多因素影响。后处理里的Color Grading、Tonemapping、Bloom都会改变PBR的最终表现。比如ACES Tonemapping会压缩高光让金属的高光不那么刺眼Bloom则会放大高光区域让金属看起来更“亮”。光照强度的单位也很关键。URP默认用Lux作为光照单位但很多人习惯用Intensity的任意值。如果光照强度不对PBR的参数再准也没用。一般来说Directional Light的Intensity在1到3之间比较合理Point Light要根据距离衰减调整。环境光的设置容易被忽略。URP的Environment Lighting有Skybox、Gradient、Color三种模式。Skybox模式最真实但性能开销大Gradient模式适合风格化场景Color模式最简单但容易让暗部死黑。实际项目中我一般用Gradient模式Sky颜色稍亮Equator颜色接近地面反射色Ground颜色稍暗。最后说一个反直觉的经验PBR材质在风格化场景里不一定好看。卡通渲染、低多边形风格、像素风这些场景用PBR反而会让画面显得“脏”。这时候要么改用Unlit Shader要么把PBR的Specular和Smoothness压到很低让画面更干净。工具是死的画面是活的知道什么时候不用PBR比知道怎么用PBR更重要。