微表面模型思想:BRDF 的 D、G、F 项从哪来

Unity 知识 · Shader 区域 · 光照与材质 · 第 2 篇 更新于 2026-10-15

「粗糙度」为什么能同时控制高光的粗细和强度?PBR 参数为什么敢叫金属度?答案都在微表面模型里。这篇不写完整实现(下一篇写),只把反射方程和 BRDF 的 D、G、F 三项从物理直觉推到公式形状——每一项都会对应到一行代码。

反射方程:光照的总账

出射辐射 = 对所有入射方向积分:

Lo(x, ωo) = ∫_Ω  f_r(x, ωi, ωo) · Li(x, ωi) · (n·ωi)  dωi
  • Li:从方向 ωi 射来的光;f_r:该点把 ωi 的光反射到 ωo 的比例——BRDF。
  • 实时渲染没法积分整个半球,工程拆法:直接光对每个灯取一个采样点(就是 /notes/unity/lighting-1/ 里 dot(N,L) 在做的事);间接光预烘焙进 lightmap/light probe(见 /notes/unity/lighting-4/)或环境贴图 IBL。
  • 所以「PBR」在实时里不是更高级的光照算法,而是把 f_r 换成有物理约束的形式,让参数可以按物理标定。

微表面假设

肉眼平滑的表面,微观上是海量微小镜面(microfacet),每个小镜面按自己的法线做完美反射。表面「粗糙」= 小镜面法线方向分散;「光滑」= 法线集中朝向宏观法线 N。

高光为什么存在:只有法线恰好等于 半程向量 H(ωi 与 ωo 的角平分线,见 /notes/unity/lighting-1/)的那批小镜面,能把光反射进眼睛。粗糙度 α 就是小镜面法线的分散程度——这一个假设直接生出 BRDF 三项:

D — Normal Distribution(有多少镜面朝向 H)

D = 法线为 H 的微表面占比密度

常用 GGX/Trowbridge-Reitz:

D_GGX(N·H, α) = α² / π · 1 / ( (N·H)²(α²−1) + 1 )²

直觉:α 小 → D 在 N·H≈1 处极尖(锐利高光);α 大 → D 摊开(宽而柔的高光)。高光「粗细」全部由 D 决定——这就是粗糙度滑条的物理含义。GGX 的长尾比老式 Blinn 指数更重,所以 PBR 材质边缘有一圈淡淡的掠射反光,观感比 Blinn 更「真」。

G — Geometry/Masking(镜面互相遮挡)

小镜面不是都露着的:凹凸之间会互相挡光、挡视线。α 越大遮挡越严重,高光在掠射角额外衰减。工程用 Smith 分解 G = G_L · G_V,直接光常用 Schlick-GGX 近似(k 由 α 导出):

G_Schlick(n·v, k) = (n·v) / ( (n·v)(1−k) + k ),   k = α/2(直接光)

G 项肉眼效果:粗糙材质在边缘处高光明显变暗,Blinn-Phong 没有这个衰减。

F — Fresnel(掠射角反射更强)

F_Schlick(uv, F0) = F0 + (1 − F0)(1 − u·v)⁵

视线越贴近表面(掠射),反射比例越高——湖面远处比脚下更反光。F0 是正视反射率:电介质(塑料、水、木头)约 0.04,金属接近 1 且带颜色。F 项是「边缘高光」的物理来源,风格化写法见 /notes/unity/effects-2/。

组装:Cook-Torrance 的形状

f_r = D·G·F / ( 4 (N·L)(N·V) )

分母是微表面模型坐标变换的几何修正(把「微法线分布」换算回宏观立体角)。下一篇 /notes/unity/lighting-3/ 把这三项写成可跑的代码,并补上最后一块拼图:能量守恒与金属度。

与 Blinn-Phong 的对应关系

Blinn-Phong微表面
pow(N·H, shininess)D 项(指数分布 ≈ GGX 的近似)
无G 项
常数高光色F 项(Blinn 把 F 当常数,所以金属调不对)
高光色与漫反射色独立调,能量不守恒F 反射多少,漫反射就少多少

Blinn-Phong 不是「错」,是只实现了 D 的近似、砍掉了 G 和 F 的简化版——所以它调不出金属,也调不出「粗糙度」这一个统一参数。

自检三问

  • 粗糙度滑条在公式里控制哪一项?肉眼效果是什么?
  • 为什么 Blinn-Phong 材质在掠射角看起来「塑料」?
  • 反射方程的直接光/间接光,在实时管线里各由什么机制承担?