本文最后更新于 2025年5月8日 晚上
【基于物理的渲染(2)】Cook-Torrance
BRDF
BRDF 直译为双向散射分布函数,是一种解释光反射强度的模型。双向散射是指其将反射光描述为由镜射光和漫射光两种。基于物理的 BRDF 说明该公式不能是传统的经验模型,而是遵循各种物理现象而设计的模型。
漫射光
漫射光是指光线射入物体内部,在内部多次反弹后返回的光,这类光容易被物体吸收,且反射的方向无序,因此反光将均匀的分布在照射区域。
镜射光
镜射光是指光线仅触碰表面一次就反射的光,这种光与多种系数有关,例如表面的光滑度,观察的角度等,故光斑可变,且有可能发生一定的全反射(光未被表面吸收)。
Cook-Torrance
CookTorrance 是最常用的基于物理的 BDRF,相比过去的一些经验模型,它的效果更加真实,符合物理规律。CookTorrance 中有很多过去 Lambert 和 Phong 的影子,可以说就是由它们为基础慢慢发展出的新时代光照模型,也是目前主流的光照模型。
微表面属性
从Phong开始就有了考虑不同表面光泽度而显示不同高光的效果,Cook-Torrance也不例外,用其计算光照,需先提供一些微表面属性信息。
- albedo(反射率):决定了物体表面对不同波段光的反射率(不被吸收率,也可简单理解为物体表面颜色)。
- metallic(金属度):控制漫射光和镜射光之间的比例,以及镜射光颜色。金属度越高,漫射越少,镜射越多,镜射颜色越接近物体表面颜色。
- smoothness(光滑度):物体表面的光滑程度,用于控制镜射光的形状特征。
基本公式结构
基本的 CookTorrrance 光照模型结构如下:
CookTorrance=kd+ks∗fs
- kd:表面对每单位漫射光的反射率。
- ks:表面对每单位镜射光的反射率。
- fs:镜射系数,表示有多少光会被直接反射进眼睛。
反射率计算
根据能量守恒 kd+ks=1,而两者之间的权重分配则采用金属度系数决定:
kd=lerp(1,0,metallic)ks=lerp(0,1,metallic)
但现实中的一般物体是不可能全漫射的,即使是黑色表面,遇到强光也会反射出镜射光,因此需要提供一定的保底全反射,该全反射的系数一般为 0.04(标准介电镜面反射):
kd=lerp(0.96,0,metallic)ks=lerp(0.04,1,metallic)
反射光的光不一定和入射光颜色一样,因为很多物体的表面也会吸收部分波段的光,因此计算时还需要考虑表面的基础反照率(表面颜色):
kd=lerp(0.96∗albedo,0,metallic)ks=lerp(0.04,1∗albedo,metallic)
镜射系数计算
镜射系数的计算公式如下:
fs=4(N⋅L)(N⋅V)D∗G∗F
- N:法线方向
- L:光源方向
- V:相机方向
在部分资料中该公式的分母系数 (N⋅Lm)(N⋅V) 可能会被去除,因为这部分可以被 G 中的分子约分。但如果不去除的话,可以确保 G∈[0,1],直观上看,这样会更能表现公式的物理效果。
其中 D、G、F 是三个可插拔的系数,用于反应 3 种物理现象。可插拔意味着它们是可以更换的,有多种计算方式可供选择,因此可以以此实现渲染效果的定制。
此外 D、G 的计算依赖一个新的系数叫粗糙度,粗糙度可以通过物体表面的光滑度计算得出:
a=(1−smoothness)2
法线分布
D 描述表面法线分布情况,具体而言它决定了镜面高光的光斑形状。下述是使用 GGX 计算 D 的方法:
- H=normalize(L+V):半角向量的缩写。
DGGX=π((H⋅N)2(a2−1)+1)2a2
其中 π 是为了归一化,使其光亮的总和符合能量守恒,但有些地方(如 Unity)会故意去掉该项。
几何遮蔽
G 用于表现微表面之间的遮挡导致的光线衰减现象,这在粗糙的表面尤为明显。下述是使用 Smith 计算 G 的方法:
GSmith=lerp(N⋅L,1,k)(N⋅L)∗lerp(N⋅V,1,k)(N⋅V)
k=8(a+1)2(直接光)或2a2(间接光)
从中可以观察到:
- 光线入射角或观察角度与表面越垂直,光线被遮挡的概率越小。
- 越光滑的表面,光线被遮挡的概率越小。
- 对于直接光始终会被吸收一部分,而环境光可以全反射。
此外还有一种效果接近,但性能更好的方法:
GSKSm=lerp((L⋅H)2,1,a)(N⋅L)(N⋅V)
菲涅尔效应
F 表示一个 0-1 的光线反射率,反应的是现实中的菲涅尔效应,描述了不同折射率的物体在不同观察角度下反射光线不同的特点。一般它的公式采用如下近似值:
F=lerp((1−(V⋅N))5,1,F0)
F0=(r+1)2(r−1)2
从中可以观察到以下几种现象:
- 折射率越高,菲涅尔效应越明显(如水面)。
- 菲涅尔效应发生时,物体正面反射光线少(能透过湖面看到底),掠角反射光线多(湖面变不透明)。
- 折射率为 0,没有菲涅尔效应,发生全反射。
不过上述菲涅尔公式只能用于透明物体,因为它会使物体表面反射为 0。对于不透明物体,可以需要采用另一种系数计算方法:
F0=ks
不过该方法将菲涅尔函数的输出由标量改为了向量,且携带了镜射光的反射率信息,因此要修改 CookTorrance 公式,使镜射光部分不要再乘 ks 了(kd+ksfs→kd+fs)。
Unity 中的镜射系数计算
https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/00-00-00-20-66/siggraph2015_2D00_mmg_2D00_renaldas_2D00_notes.pdf
Unity 中对于镜射系数的计算公式如下:
DG∗Ffs=((H⋅N)2(a2−1)+1)2a2=(L⋅H)2(a+0.5)1=4D∗G∗F
其中 D 就是 DGGX 方法,但去掉了用于归一化的 π ,使画面更亮。
G∗F 是拟合的近似公式。在原始公式中,G 使用的是 GSKSm,但 F 的公式不清楚,因为原始公式和最终公式的效果并不相同。
(N⋅L)(N⋅V)被从分子分母中约分以加快速度。
参考资料