1. 程式人生 > >基於物理的渲染技術(PBR)系列四

基於物理的渲染技術(PBR)系列四

筆者介紹:姜雪偉,IT公司技術合夥人,IT高階講師,CSDN社群專家,特邀編輯,暢銷書作者,國家專利發明人;已出版書籍:《手把手教你架構3D遊戲引擎》電子工業出版社和《Unity3D實戰核心技術詳解》電子工業出版社等。

接著上一篇部落格講解的內容基於物理的渲染技術(PBR)系列三,下面介紹菲涅爾(發音為Freh-nel)方程描述的是被反射的光線對比光線被折射的部分所佔的比率,這個比率會隨著我們觀察的角度不同而不同。當光線碰撞到一個表面的時候,菲涅爾方程會根據觀察角度告訴我們被反射的光線所佔的百分比。利用這個反射比率和能量守恆原則,我們可以直接得出光線被折射的部分以及光線剩餘的能量。

當垂直觀察的時候,任何物體或者材質表面都有一個基礎反射率(Base Reflectivity),但是如果以一定的角度往平面上看的時候

所有反光都會變得明顯起來。你可以自己嘗試一下,用垂直的視角觀察你自己的木製/金屬桌面,此時一定只有最基本的反射性。但是如果你從近乎90度(注:應該是指和法線的夾角)的角度觀察的話反光就會變得明顯的多。如果從理想的90度視角觀察,所有的平面理論上來說都能完全的反射光線。這種現象因菲涅爾而聞名,並體現在了菲涅爾方程之中。

菲涅爾方程是一個相當複雜的方程式,不過幸運的是菲涅爾方程可以用Fresnel-Schlick近似法求得近似解:

FSchlick(n,v,F0)=F0+(1F0)(1(nv))5

F0F0F0表示平面的基礎反射率,它是利用所謂折射指數(Indices of Refraction)或者說IOR計算得出的。然後正如你可以從球體表面看到的那樣,我們越是朝球面掠角的方向上看(此時視線和表面法線的夾角接近90度)菲涅爾現象就越明顯,反光就越強:



菲涅爾方程還存在一些細微的問題。其中一個問題是Fresnel-Schlick近似僅僅對電介質或者說非金屬表面有定義。對於導體(Conductor)表面(金屬),使用它們的折射指數計算基礎折射率並不能得出正確的結果,這樣我們就需要使用一種不同的菲涅爾方程來對導體表面進行計算。由於這樣很不方便,所以我們預先計算出平面對於法向入射F0)的反應(處於0度角,好像直接看向表面一樣)然後基於相應觀察角的Fresnel-Schlick近似對這個值進行插值,用這種方法來進行進一步的估算。這樣我們就能對金屬和非金屬材質使用同一個公式了。

平面對於法向入射的響應或者說基礎反射率可以在一些大型資料庫中找到,比如下圖所示的

,下面列舉的這一些常見數值就是從Naty Hoffman的課程講義中所得到的:


這裡可以觀察到的一個有趣的現象,所有電介質材質表面的基礎反射率都不會高於0.17,這其實是例外而非普遍情況。導體材質表面的基礎反射率起點更高一些並且(大多)在0.5和1.0之間變化。此外,對於導體或者金屬表面而言基礎反射率一般是帶有色彩的,這也是為什麼F0要用RGB三原色來表示的原因(法向入射的反射率可隨波長不同而不同)。這種現象我們只能在金屬表面觀察的到。

金屬表面這些和電介質表面相比所獨有的特性引出了所謂的金屬工作流的概念。也就是我們需要額外使用一個被稱為金屬度(Metalness)的引數來參與編寫表面材質。金屬度用來描述一個材質表面是金屬還是非金屬的。

通過預先計算電介質與導體的F0值,我們可以對兩種型別的表面使用相同的Fresnel-Schlick近似,但是如果是金屬表面的話就需要對基礎反射率新增色彩。我們一般是按下面這個樣子來實現的:
vec3 F0 = vec3(0.04);
F0      = mix(F0, surfaceColor.rgb, metalness);

我們為大多數電介質表面定義了一個近似的基礎反射率。F0取最常見的電解質表面的平均值,這又是一個近似值。不過對於大多數電介質表面而言使用0.04作為基礎反射率已經足夠好了,而且可以在不需要輸入額外表面引數的情況下得到物理可信的結果。然後,基於金屬表面特性,我們要麼使用電介質的基礎反射率要麼就使用F0來作為表面顏色。因為金屬表面會吸收所有折射光線而沒有漫反射,所以我們可以直接使用表面顏色紋理來作為它們的基礎反射率。

Fresnel Schlick近似可以用程式碼表示為:

vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
    return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}

其中cosTheta是表面法向量n與觀察方向v的點乘的結果。

隨著Cook-Torrance BRDF中所有元素都介紹完畢,我們現在可以將基於物理的BRDF納入到最終的反射率方程當中去了:

Lo(p,ωo)=Ω(kdcπ+ksDFG4(ωon)(ωin))Li(p,ωi)nωidωi

這個方程現在完整的描述了一個基於物理的渲染模型,它現在可以認為就是我們一般意義上理解的基於物理的渲染也就是PBR。如果你還沒有能完全理解我們將如何把所有這些數學運算結合到一起並融入到程式碼當中去的話也不必擔心。在下一個教程當中,我們將探索如何實現反射率方程來在我們渲染的光照當中獲得更加物理可信的結果,而所有這些零零星星的碎片將會慢慢組合到一起來。

在瞭解了PBR後面的數學模型之後,最後我們將通過說明美術師一般是如何編寫一個我們可以直接輸入PBR的平面物理屬性的來結束這部分的討論。PBR渲染管線所需要的每一個表面引數都可以用紋理來定義或者建模。使用紋理可以讓我們逐個片段的來控制每個表面上特定的點對於光線是如何響應的:不論那個點是金屬的,粗糙或者平滑,也不論表面對於不同波長的光會有如何的反應。

在下面你可以看到在一個PBR渲染管線當中經常會碰到的紋理列表,還有將它們輸入PBR渲染器所能得到的相應的視覺輸出:


反照率:反照率(Albedo)紋理為每一個金屬的紋素(Texel)(紋理畫素)指定表面顏色或者基礎反射率。這和我們之前使用過的漫反射紋理相當類似,不同的是所有光照資訊都是由一個紋理中提取的。漫反射紋理的影象當中常常包含一些細小的陰影或者深色的裂紋,而反照率紋理中是不會有這些東西的。它應該只包含表面的顏色(或者折射吸收係數)。

法線:法線貼圖紋理和我們之前在法線貼圖教程中所使用的貼圖是完全一樣的。法線貼圖使我們可以逐片段的指定獨特的法線,來為表面製造出起伏不平的假象。

金屬度:金屬(Metallic)貼圖逐個紋素的指定該紋素是不是金屬質地的。根據PBR引擎設定的不同,美術師們既可以將金屬度編寫為灰度值又可以編寫為1或0這樣的二元值。

粗糙度:粗糙度(Roughness)貼圖可以以紋素為單位指定某個表面有多粗糙。取樣得來的粗糙度數值會影響一個表面的微平面統計學上的取向度。一個比較粗糙的表面會得到更寬闊更模糊的鏡面反射(高光),而一個比較光滑的表面則會得到集中而清晰的鏡面反射。某些PBR引擎預設採用的是對某些美術師來說更加直觀的光滑度(Smoothness)貼圖而非粗糙度貼圖,不過這些數值在取樣之時就馬上用(1.0 – 光滑度)轉換成了粗糙度。

AO:環境光遮蔽(Ambient Occlusion)貼圖或者說AO貼圖為表面和周圍潛在的幾何圖形指定了一個額外的陰影因子。比如如果我們有一個磚塊表面,反照率紋理上的磚塊裂縫部分應該沒有任何陰影資訊。然而AO貼圖則會把那些光線較難逃逸出來的暗色邊緣指定出來。在光照的結尾階段引入環境遮蔽可以明顯的提升你場景的視覺效果。網格/表面的環境遮蔽貼圖要麼通過手動生成,要麼由3D建模軟體自動生成。

美術師們可以在紋素級別設定或調整這些基於物理的輸入值,還可以以現實世界材料的表面物理性質來建立他們的材質資料。這是PBR渲染管線最大的優勢之一,因為不論環境或者光照的設定如何改變這些表面的性質是不會改變的,這使得美術師們可以更便捷的獲取物理可信的結果。在PBR渲染管線中編寫的表面可以非常方便的在不同的PBR渲染引擎間共享使用,不論處於何種環境中它們看上去都會是正確的,因此看上去也會更自然。