做渲染工作的老哥们应该都有个共同感受:PBR 流程里想把金属质感调对,真正难的不是颜色,而是微表面行为。最近我在整理材质库,为了给一套金属材质做参数验收,专门搭了个很小的展示场景:用金属球在不同粗糙度、各向异性方向下的反光表现来做对照。结果这一组小球帮我解决了不少“拉丝方向不对”“高光形状奇怪”的疑难杂症,也让我把 GGX 各向异性的原理重新吃透了一遍。今天把整个思路、公式、实操步骤和踩过的坑整理出来,给同样被金属高光调不准、各向异性方向总是“拧巴”的朋友们做个参考。
这个项目不复杂,适合三类人看:刚学 PBR 想建立材质直觉的渲染新人,需要反复验证材质资产的 TA/美术,以及做自定义 Shader 想确认 BRDF 计算是否正确的引擎开发。不管你是用 Unity、Unreal 还是自研引擎,核心思路都能直接搬,差别只在参数名和管线写法。
1. 项目思路拆解:为什么用金属球做PBR各向异性展示
1.1 从标题反推需求:要展示的到底是什么
先别急着写 Shader,我把标题拆开了想了一遍。标题里有三个关键词:PBR、各向异性、粗糙度,而动作是“展示反光表现”。这三个词叠在一起,核心需求其实是:在一个可控的、可重复的环境里,快速看出不同材质参数对高光形态的影响。
这里有个很容易被忽略的点——“展示”不等于“渲染出正确的一帧”。你要让人一眼就看懂差异,所以场景要足够简单,参数要能独立变化,效果要被环境光“放大”。我把展示维度定为两个:粗糙度(决定高光面积和锐利度)和各向异性(决定高光是被拉长还是变成圆形)。至于各向异性方向,我把它当成第三个维度,用来验证切线是否正确,以及贴图控制方向是否生效。
这个需求用金属球来做是最合适的,原因我下一小节细说。但先记住一个结论:这个项目的目标是输出一组“可对照、可复现、一眼能看出差异”的测试图像,而不是做炫酷的作品集截图。
1.2 金属球为什么是测试各向异性渲染的最佳物体
我试过平面、圆柱、圆环、方块,最后发现球体是效率最高的测试物体,原因有三个。
第一,球面的法线覆盖了几乎全部方向。从正面看过去,球心附近的法线指向相机,边缘附近法线接近垂直于视线,这意味着一个球面就能逼出 BRDF 在多种入射角下的响应。很多在平面上看着正常的参数,放到球面上立刻暴露问题,比如边缘发灰、高光撕裂。
第二,球面在视觉上是一个“没有方向性的形状”。平面和方块本身带有方向,容易让你把几何方向误当成材质各向异性方向。球体自身没有棱线,高光的拉长方向完全由切线方向和相机位置决定,因此非常适合确认各向异性这个属性本身是不是生效了。
第三,球面的 UV 划分是公开的难点。球体极点处存在 UV 收敛奇点,这正好能帮你测试切线的处理是否健壮。如果一个 Shader 在球体上能完美处理极点、接缝和切线连续,那它在大部分角色、道具、硬表面上基本不会出大问题。
1.3 渲染方案选型:实时展示 + Shader 实现
我最终选择的是 Unity + URP(通用渲染管线)手写一个顶点片元 Shader 来做展示,顺便配合 HDRI 环境反射探针。
为什么不直接用内置 Lit/URP Lit 加一个 anisotropy 参数?因为标准 Lit 的 BRDF 参数映射是固定的,想单独控制各向异性方向旋转、输出调试视图、快速改粗糙度映射关系,都要额外写辅助逻辑。手写 Shader 虽然麻烦一点,但能完全掌控“粗糙度如何映射到 alpha”“各向异性系数如何拆分 ax/ay”这些关键步骤,后续想复用到别的引擎也更容易。
如果你只是想在项目里快速看效果,用 Unreal 的材质系统或者 Unity Shader Graph 也可以,原理一样。但如果你要理解背后发生了什么,我强烈建议手写一遍,你可以对照下文第 2 章的公式逐行核对。很多“高光形状不对”的问题,最终都是出在公式里的一个符号或者一项因子上。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 各向异性PBR原理入门:GGX微表面模型怎么影响反光
2.1 各向异性到底是什么:拉丝金属与圆形高光的区别
传统 PBR 里,微表面法线分布通常假定是“旋转对称”的,也就是说微表面的朝向在各个方向上的统计分布一致,高光形状是圆形或者随入射角度稍微改变形状的椭圆。但真实世界的金属表面往往有加工痕迹,比如拉丝不锈钢的细纹、CD 光盘的同心纹路、头发和丝绸的纤维走向,这些表面的微表面分布不再是圆形对称,而是沿着某个方向被“拉长”。这就是各向异性。
用生活里的话说,圆形高光就像你用砂纸把不锈钢表面打磨得毫无方向,一束光打上去,亮点是一个圆;而拉丝金属的表面有一道道规律划痕,光打上去,亮点会沿着划痕方向被拉成一条光带。各向异性方向则指的是这道划痕的方向,也就是高光被拉长的轴向。
在渲染方程里,各向异性不像普通粗糙度那样用一个标量描述,而是需要引入一个“切线方向(Tangent)”和一个“副切线方向(Bitangent)”,分别对应微表面在两个互相垂直方向上的不同粗糙
