上一篇文章我們講了Cook-Torrance BRDF模型,我們知道它由三個部分組成:法向分布函數、幾何函數以及菲涅爾(Fresnel)公式。這次我們講菲涅爾公式。
當光線碰撞到一個表面的時候,菲涅爾公式會返回被反射的光線所占的比例,根據能量守恆定律我們就可以相應地計算出折射的光線所占比。這種反射占比其實不僅和物體本身的材質有關,也和視線和物體本身的夾角有關。比如說,正對着看一個平面,看到的一定是只有很少的高光反射,但是如果從和平面近乎90°的角度觀察的話,那么高光的占比就會非常明顯。綜合以上觀察,用Fresnel-Schlick近似法求得菲涅爾公式的近似解:
\(\large{F_{Schlick}(h,v,F_0) = F_0 + (1 - F_0){(1-(n\cdot v))}^5}\)
\(F_0\)表示平面的基礎反射率,這是一個隨材質而不同的參數,在一些數據庫中可以查到不同材質的\(F_0\)值:
觀察上表可以發現一個有趣的點:金屬材料和非金屬材料的\(F_0\)值是存在差異的,非金屬材料的\(F_0\)三個通道的值一般不會高於0.17,金屬材料則可能到1.0;另外非金屬材料三個通道的值是不相等的,金屬材料相反。因為金屬和非金屬在菲涅爾效應上的不同特性,物理學上將金屬稱為導體(Conductor),非金屬稱為電介質(Dielectric),所幸通過\(F_0\)我們可以將導體和電介質的菲涅爾效應用Fresnel-Schlick近似的公式統一起來。
在實際編碼的時候,我們設定一個參數metalness,定義了物體材質的金屬程度,通過它計算出\(F_0\)。
vec3 F0 = vec3(0.04);
F0 = mix(F0, surfaceColor.rgb, metalness);
如果是電介質,我們可以輸入它自己的\(F_0\),對於金屬則應用默認的0.04(一個經驗值),然后根據metalness的值和物體自身的顏色做中和。也就是說,如果metalness為1,那么\(F_0\)完全用的是金屬自己的顏色(此時只有高光反射,沒有漫反射了)。
然后計算菲涅爾公式:
vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
其中cosTheta是表面法向量n與觀察方向v的點乘的結果。
Cook-Torrance反射率方程
介紹完了菲涅爾公式之后,我們就可以得到最終的基於Cook-Torrance BRDF的反射方程:
可以看到反射方程中的\(f_r\)替換成了Cook-Torrance BRDF,另外ks其實就是菲涅爾公式的F,kd=(1-ks)(1-metalness),這是因為金屬會更多的吸收折射光線導致漫反射消失,這是金屬物質的特殊物理性質。
所以上面那個積分實際應該這么寫:
之后會探討如何在實時渲染中求解該方程。