# 双向反射分布函数(BRDF)双向反射分布函数(BRDF)是一个用于描述表面反射特性的函数。它是在微平面理论上建立的。
在下文中,我们约定:
n n n 为宏观表面法线v v v 为观察方向l l l 为光照方向h h h 为半矢量(Half-vector),即 n o r m a l i z e ( v + l ) normalize(v + l) n o r m a l i z e ( v + l ) α \alpha α 为粗糙度参数(通常在引擎中定义为 α = r o u g h n e s s 2 \alpha = roughness^2 α = r o u g h n e s s 2 )# Cook-Torrance BRDF 模型为了在着色器中模拟微小镜面这种现象,我们通常使用 Cook-Torrance BRDF 模型。 其镜面反射部分由三个关键函数组成:法线分布函数(D)、几何遮挡(G)、菲涅尔(F)
f s = D ⋅ G ⋅ F 4 ( n ⋅ l ) ( n ⋅ v ) f_s = \dfrac{D \cdot G \cdot F}{4(n \cdot l)(n \cdot v)} f s = 4 ( n ⋅ l ) ( n ⋅ v ) D ⋅ G ⋅ F
# 法线分布函数(Normal Distribution Function, NDF)它描述了有多少比例的微平面法线正好对准了半矢量(Half-vector, h),从而能将光线反射到观察者眼中。这是最关键的部分。主流算法:GGX (Trowbridge-Reitz)。它在处理高光边缘时有非常漂亮的拖尾效果,是目前游戏行业的标配。 计算方法:
D = α 2 π ( ( n ⋅ h ) 2 ( α 2 − 1 ) + 1 ) 2 D = \dfrac{\alpha^2}{\pi((n \cdot h)^2(\alpha^2 - 1) + 1)^2} D = π ( ( n ⋅ h ) 2 ( α 2 − 1 ) + 1 ) 2 α 2
# 几何函数(Geometry Function)它描述了微平面之间的相互遮挡,表现为更窄小的高光峰值点,以及更长的衰减弥散,这让材质的高光看起来更加的真实。遮蔽描述了微平面挡住了反射给观察者的光。阴影描述了微平面挡住了入射的光。如果没有 G 项,粗糙表面在掠射角会显得异常明亮,不符合能量守恒。主流算法:Smith-GGX 高度相关几何遮蔽、可见性函数 V_Smith
Smith-GGX 高度相关几何遮蔽:传统的 Smith 几何函数假设遮蔽和阴影是独立的。但在现实中,如果一个点从观察方向被遮挡了,它从光照方向被遮挡的概率也会更高。高度相关版本修正了这一点。
G = 2 ( n ⋅ l ) ( n ⋅ v ) ( n ⋅ v ) ( n ⋅ l ) 2 ( 1 − α 2 ) + α 2 + ( n ⋅ l ) ( n ⋅ v ) 2 ( 1 − α 2 ) + α 2 G = \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}} G = ( n ⋅ v ) ( n ⋅ l ) 2 ( 1 − α 2 ) + α 2 + ( n ⋅ l ) ( n ⋅ v ) 2 ( 1 − α 2 ) + α 2 2 ( n ⋅ l ) ( n ⋅ v )
可见性函数 V_Smith 在 Cook-Torrance BRDF 公式中,分母通常带有 4 ( n ⋅ l ) ( n ⋅ v ) 4(n \cdot l)(n \cdot v) 4 ( n ⋅ l ) ( n ⋅ v ) 。为了优化计算,我们会将 G 项与之合并,定义为 Visibility Term (V)。使用上述高度相关 G 项后,V 项可以简化。
V = G 4 ( n ⋅ l ) ( n ⋅ v ) = 0.5 ( n ⋅ v ) ( n ⋅ l ) 2 ( 1 − α 2 ) + α 2 + ( n ⋅ l ) ( n ⋅ v ) 2 ( 1 − α 2 ) + α 2 V = \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 = 4 ( n ⋅ l ) ( n ⋅ v ) G = ( n ⋅ v ) ( n ⋅ l ) 2 ( 1 − α 2 ) + α 2 + ( n ⋅ l ) ( n ⋅ v ) 2 ( 1 − α 2 ) + α 2 0 . 5
注意:使用 V_Smith 时,BRDF 模型中的分母会被约掉,此时计算方法变为:
f s = D ⋅ V ⋅ F f_s = D \cdot V \cdot F f s = D ⋅ V ⋅ F
UE4 的 GGX-Smith Correlated Joint 近似方案
V = 0.5 ( n ⋅ l ) ( ( n ⋅ v ) ( 1 − α ) + α ) + ( n ⋅ v ) ( ( n ⋅ l ) ( 1 − α ) + α ) V = \dfrac{0.5}{(n \cdot l)((n \cdot v)(1 - \alpha) + \alpha) + (n \cdot v)((n \cdot l)(1 - \alpha) + \alpha)} V = ( n ⋅ l ) ( ( n ⋅ v ) ( 1 − α ) + α ) + ( n ⋅ v ) ( ( n ⋅ l ) ( 1 − α ) + α ) 0 . 5
Unity HDRP 的 GGX-Smith Correlated Joint 近似方案
β = r o u g h n e s s \beta = roughness β = r o u g h n e s s
V = 0.5 ( n ⋅ l ) ( ( n ⋅ v ) ( 1 − β ) + β ) + ( n ⋅ v ) ( n ⋅ l ) 2 ( 1 − β 2 ) + β 2 V = \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}} V = ( n ⋅ l ) ( ( n ⋅ v ) ( 1 − β ) + β ) + ( n ⋅ v ) ( n ⋅ l ) 2 ( 1 − β 2 ) + β 2 0 . 5
# 菲涅尔方程(Fresnel Equation)描述了光线在不同角度下反射与折射的比例。几乎所有物体在接近 90° 观察时,反射率都会急剧上升。对于粗糙的表面,反射会更加地明显,但不会完全达到 100% 高光反射。反射的效果受每个微面元的法线与光的角度影响,而非取决于整个宏观面的法线与光的角度。表面粗糙时,光线被微面元进行不同角度的弥散反射,所以整个反射效果看起来会更加柔和。 常用近似:Schlick 近似。
F 0 = l e r p ( 0.04 , a l b e d o , m e t a l l i c ) F_0 = lerp(0.04, albedo, metallic) F 0 = l e r p ( 0 . 0 4 , a l b e d o , m e t a l l i c )
F = F 0 + ( 1 − F 0 ) ( 1 − ( h ⋅ v ) ) 5 F = F_0 + (1 - F_0)(1 - (h \cdot v))^5 F = F 0 + ( 1 − F 0 ) ( 1 − ( h ⋅ v ) ) 5
F 0 F_0 F 0 是材质的基础反射率(垂直入射时的反射率),a l b e d o albedo a l b e d o 是反照率(通常为纹理采样值),m e t a l l i c metallic m e t a l l i c 是金属度。在游戏引擎中,电介质(绝缘体)的 F 0 F_0 F 0 通常硬编码为 0.04 0.04 0 . 0 4 ,而金属(导体)的 F 0 F_0 F 0 则是其自身颜色,或者像本文这样用金属度影响菲涅尔反射率。
# BRDF 与 Albedo 的计算计算方式如下:
s p e c u l a r = f s = D ⋅ V ⋅ F specular = f_s = D \cdot V \cdot F s p e c u l a r = f s = D ⋅ V ⋅ F
k d = ( 1 − F ) ( 1 − m e t a l l i c ) kd = (1 - F)(1 - metallic) k d = ( 1 − F ) ( 1 − m e t a l l i c )
d i f f u s e = k d ⋅ a l b e d o π diffuse = \dfrac{kd \cdot albedo}{\pi} d i f f u s e = π k d ⋅ a l b e d o
b r d f = ( d i f f u s e + s p e c u l a r ) ( n ⋅ l ) brdf = (diffuse + specular)(n \cdot l) b r d f = ( d i f f u s e + s p e c u l a r ) ( n ⋅ l )
关于 k d kd k d 1 − F 1 - F 1 − F 是为了排除镜面反射。F F F 代表了光线被镜面反射的比例,根据能量守恒,剩下的 1 − F 1 - F 1 − F 就是进入物体表面的光线比例。1 − m e t a l l i c 1 - metallic 1 − m e t a l l i c 是为了考虑金属度。对于纯金属 (m e t a l l i c = 1 metallic = 1 m e t a l l i c = 1 ),k d kd k d 会变为 0 0 0 。在 PBR 理论中,金属的所有漫反射颜色都会被吸收,它们只显示镜面反射的颜色(通常是受金属色调影响的 F F F )。对于非金属 (m e t a l l i c = 0 metallic = 0 m e t a l l i c = 0 ),k d = ( 1 − F ) kd = (1 - F) k d = ( 1 − F ) 。除了被镜面反射的那部分光,剩下的全部参与漫反射计算。 如果没有这个系数,当菲尼尔效应很强时(例如在掠射角观查物体),镜面反射 f s f_s f s 会非常大,如果此时漫反射依然保持满额强度,物体反射出的总能量就会超过入射能量,导致渲染出来的边缘看起来过亮且不真实。
关于 π \pi π 在纯物理公式中,漫反射需要除以 π \pi π 来保证能量守恒。但在 Unity 以及大多数游戏引擎中,光源的强度通常已经隐含了 π \pi π 的补偿。如果你手动除以 π \pi π ,物体的亮度会下降。所以,是否除以 π \pi π 要根据引擎的情况决定。