# 双向反射分布函数(BRDF)

双向反射分布函数(BRDF)是一个用于描述表面反射特性的函数。它是在微平面理论上建立的。

在下文中,我们约定:

  • nn 为宏观表面法线
  • vv 为观察方向
  • ll 为光照方向
  • hh 为半矢量(Half-vector),即 normalize(v+l)normalize(v + l)
  • α\alpha 为粗糙度参数(通常在引擎中定义为 α=roughness2\alpha = roughness^2

# Cook-Torrance BRDF 模型

为了在着色器中模拟微小镜面这种现象,我们通常使用 Cook-Torrance BRDF 模型。
其镜面反射部分由三个关键函数组成:法线分布函数(D)、几何遮挡(G)、菲涅尔(F)

fs=DGF4(nl)(nv)f_s = \dfrac{D \cdot G \cdot F}{4(n \cdot l)(n \cdot v)}

# 法线分布函数(Normal Distribution Function, NDF)

它描述了有多少比例的微平面法线正好对准了半矢量(Half-vector, h),从而能将光线反射到观察者眼中。这是最关键的部分。主流算法:GGX (Trowbridge-Reitz)。它在处理高光边缘时有非常漂亮的拖尾效果,是目前游戏行业的标配。
计算方法:

D=α2π((nh)2(α21)+1)2D = \dfrac{\alpha^2}{\pi((n \cdot h)^2(\alpha^2 - 1) + 1)^2}

# 几何函数(Geometry Function)

它描述了微平面之间的相互遮挡,表现为更窄小的高光峰值点,以及更长的衰减弥散,这让材质的高光看起来更加的真实。遮蔽描述了微平面挡住了反射给观察者的光。阴影描述了微平面挡住了入射的光。如果没有 G 项,粗糙表面在掠射角会显得异常明亮,不符合能量守恒。主流算法:Smith-GGX 高度相关几何遮蔽、可见性函数 V_Smith

Smith-GGX 高度相关几何遮蔽:传统的 Smith 几何函数假设遮蔽和阴影是独立的。但在现实中,如果一个点从观察方向被遮挡了,它从光照方向被遮挡的概率也会更高。高度相关版本修正了这一点。

G=2(nl)(nv)(nv)(nl)2(1α2)+α2+(nl)(nv)2(1α2)+α2G = \dfrac{2(n \cdot l)(n \cdot v)}{(n \cdot v)\sqrt{(n \cdot l)^2(1 - \alpha^2) + \alpha^2} + (n \cdot l)\sqrt{(n \cdot v)^2(1 - \alpha^2) + \alpha^2}}

可见性函数 V_Smith
在 Cook-Torrance BRDF 公式中,分母通常带有 4(nl)(nv)4(n \cdot l)(n \cdot v)。为了优化计算,我们会将 G 项与之合并,定义为 Visibility Term (V)。使用上述高度相关 G 项后,V 项可以简化。

V=G4(nl)(nv)=0.5(nv)(nl)2(1α2)+α2+(nl)(nv)2(1α2)+α2V = \dfrac{G}{4(n \cdot l)(n \cdot v)} = \dfrac{0.5}{(n \cdot v)\sqrt{(n \cdot l)^2(1 - \alpha^2) + \alpha^2} + (n \cdot l)\sqrt{(n \cdot v)^2(1 - \alpha^2) + \alpha^2}}

注意:使用 V_Smith 时,BRDF 模型中的分母会被约掉,此时计算方法变为:

fs=DVFf_s = D \cdot V \cdot F

UE4 的 GGX-Smith Correlated Joint 近似方案

V=0.5(nl)((nv)(1α)+α)+(nv)((nl)(1α)+α)V = \dfrac{0.5}{(n \cdot l)((n \cdot v)(1 - \alpha) + \alpha) + (n \cdot v)((n \cdot l)(1 - \alpha) + \alpha)}

Unity HDRP 的 GGX-Smith Correlated Joint 近似方案

β=roughness\beta = roughness

V=0.5(nl)((nv)(1β)+β)+(nv)(nl)2(1β2)+β2V = \dfrac{0.5}{(n \cdot l)((n \cdot v)(1 - \beta) + \beta) + (n \cdot v)\sqrt{(n \cdot l)^2(1 - \beta^2) + \beta^2}}

# 菲涅尔方程(Fresnel Equation)

描述了光线在不同角度下反射与折射的比例。几乎所有物体在接近 90° 观察时,反射率都会急剧上升。对于粗糙的表面,反射会更加地明显,但不会完全达到 100% 高光反射。反射的效果受每个微面元的法线与光的角度影响,而非取决于整个宏观面的法线与光的角度。表面粗糙时,光线被微面元进行不同角度的弥散反射,所以整个反射效果看起来会更加柔和。
常用近似:Schlick 近似。

F0=lerp(0.04,albedo,metallic)F_0 = lerp(0.04, albedo, metallic)

F=F0+(1F0)(1(hv))5F = F_0 + (1 - F_0)(1 - (h \cdot v))^5

F0F_0 是材质的基础反射率(垂直入射时的反射率),albedoalbedo 是反照率(通常为纹理采样值),metallicmetallic 是金属度。在游戏引擎中,电介质(绝缘体)的 F0F_0 通常硬编码为 0.040.04,而金属(导体)的 F0F_0 则是其自身颜色,或者像本文这样用金属度影响菲涅尔反射率。

# BRDF 与 Albedo 的计算

计算方式如下:

specular=fs=DVFspecular = f_s = D \cdot V \cdot F

kd=(1F)(1metallic)kd = (1 - F)(1 - metallic)

diffuse=kdalbedoπdiffuse = \dfrac{kd \cdot albedo}{\pi}

brdf=(diffuse+specular)(nl)brdf = (diffuse + specular)(n \cdot l)

关于 kdkd
1F1 - F 是为了排除镜面反射。FF 代表了光线被镜面反射的比例,根据能量守恒,剩下的 1F1 - F 就是进入物体表面的光线比例。
1metallic1 - metallic 是为了考虑金属度。对于纯金属 (metallic=1metallic = 1),kdkd 会变为 00。在 PBR 理论中,金属的所有漫反射颜色都会被吸收,它们只显示镜面反射的颜色(通常是受金属色调影响的 FF)。对于非金属 (metallic=0metallic = 0),kd=(1F)kd = (1 - F)。除了被镜面反射的那部分光,剩下的全部参与漫反射计算。
如果没有这个系数,当菲尼尔效应很强时(例如在掠射角观查物体),镜面反射 fsf_s 会非常大,如果此时漫反射依然保持满额强度,物体反射出的总能量就会超过入射能量,导致渲染出来的边缘看起来过亮且不真实。

关于 π\pi
在纯物理公式中,漫反射需要除以 π\pi 来保证能量守恒。但在 Unity 以及大多数游戏引擎中,光源的强度通常已经隐含了 π\pi 的补偿。如果你手动除以 π\pi,物体的亮度会下降。所以,是否除以 π\pi 要根据引擎的情况决定。