OpenGL 圖形庫的使用(四十二)—— PBR之理論Theory

版本記錄

版本號 時間
V1.0 2018.01.20

前言

OpenGL 圖形庫項目中一直也沒用過烁焙,最近也想學著使用這個圖形庫,感覺還是很有意思施绎,也就自然想著好好的總結一下溯革,希望對大家能有所幫助。下面內容來自歡迎來到OpenGL的世界谷醉。
1. OpenGL 圖形庫使用(一) —— 概念基礎
2. OpenGL 圖形庫使用(二) —— 渲染模式致稀、對象、擴展和狀態(tài)機
3. OpenGL 圖形庫使用(三) —— 著色器俱尼、數據類型與輸入輸出
4. OpenGL 圖形庫使用(四) —— Uniform及更多屬性
5. OpenGL 圖形庫使用(五) —— 紋理
6. OpenGL 圖形庫使用(六) —— 變換
7. OpenGL 圖形庫的使用(七)—— 坐標系統(tǒng)之五種不同的坐標系統(tǒng)(一)
8. OpenGL 圖形庫的使用(八)—— 坐標系統(tǒng)之3D效果(二)
9. OpenGL 圖形庫的使用(九)—— 攝像機(一)
10. OpenGL 圖形庫的使用(十)—— 攝像機(二)
11. OpenGL 圖形庫的使用(十一)—— 光照之顏色
12. OpenGL 圖形庫的使用(十二)—— 光照之基礎光照
13. OpenGL 圖形庫的使用(十三)—— 光照之材質
14. OpenGL 圖形庫的使用(十四)—— 光照之光照貼圖
15. OpenGL 圖形庫的使用(十五)—— 光照之投光物
16. OpenGL 圖形庫的使用(十六)—— 光照之多光源
17. OpenGL 圖形庫的使用(十七)—— 光照之復習總結
18. OpenGL 圖形庫的使用(十八)—— 模型加載之Assimp
19. OpenGL 圖形庫的使用(十九)—— 模型加載之網格
20. OpenGL 圖形庫的使用(二十)—— 模型加載之模型
21. OpenGL 圖形庫的使用(二十一)—— 高級OpenGL之深度測試
22. OpenGL 圖形庫的使用(二十二)—— 高級OpenGL之模板測試Stencil testing
23. OpenGL 圖形庫的使用(二十三)—— 高級OpenGL之混合Blending
24. OpenGL 圖形庫的使用(二十四)—— 高級OpenGL之面剔除Face culling
25. OpenGL 圖形庫的使用(二十五)—— 高級OpenGL之幀緩沖Framebuffers
26. OpenGL 圖形庫的使用(二十六)—— 高級OpenGL之立方體貼圖Cubemaps
27. OpenGL 圖形庫的使用(二十七)—— 高級OpenGL之高級數據Advanced Data
28. OpenGL 圖形庫的使用(二十八)—— 高級OpenGL之高級GLSL Advanced GLSL
29. OpenGL 圖形庫的使用(二十九)—— 高級OpenGL之幾何著色器Geometry Shader
30. OpenGL 圖形庫的使用(三十)—— 高級OpenGL之實例化Instancing
31. OpenGL 圖形庫的使用(三十一)—— 高級OpenGL之抗鋸齒Anti Aliasing
32. OpenGL 圖形庫的使用(三十二)—— 高級光照之高級光照Advanced Lighting
33. OpenGL 圖形庫的使用(三十三)—— 高級光照之Gamma校正Gamma Correction
34. OpenGL 圖形庫的使用(三十四)—— 高級光照之陰影 - 陰影映射Shadow Mapping
35. OpenGL 圖形庫的使用(三十五)—— 高級光照之陰影 - 點陰影Point Shadows
36. OpenGL 圖形庫的使用(三十六)—— 高級光照之法線貼圖Normal Mapping
37. OpenGL 圖形庫的使用(三十七)—— 高級光照之視差貼圖Parallax Mapping
38. OpenGL 圖形庫的使用(三十八)—— 高級光照之HDR
39. OpenGL 圖形庫的使用(三十九)—— 高級光照之泛光
40. OpenGL 圖形庫的使用(四十)—— 高級光照之延遲著色法Deferred Shading
41. OpenGL 圖形庫的使用(四十一)—— 高級光照之SSAO

理論

注意: 作者正在對PBR章節(jié)進行大的調整抖单,原文的內容時時可能有更新,建議仍是閱讀原文遇八。

PBR矛绘,或者用更通俗一些的稱呼是指基于物理的渲染(Physically Based Rendering),它指的是一些在不同程度上都基于與現實世界的物理原理更相符的基本理論所構成的渲染技術的集合刃永。正因為基于物理的渲染目的便是為了使用一種更符合物理學規(guī)律的方式來模擬光線货矮,因此這種渲染方式與我們原來的Phong或者Blinn-Phong光照算法相比總體上看起來要更真實一些。除了看起來更好些以外斯够,由于它與物理性質非常接近囚玫,因此我們(尤其是美術師們)可以直接以物理參數為依據來編寫表面材質,而不必依靠粗劣的修改與調整來讓光照效果看上去正常。使用基于物理參數的方法來編寫材質還有一個更大的好處堕油,就是不論光照條件如何,這些材質看上去都會是正確的,而在非PBR的渲染管線當中有些東西就不會那么真實了地啰。

雖然如此,基于物理的渲染仍然只是對基于物理原理的現實世界的一種近似后豫,這也就是為什么它被稱為基于物理的著色(Physically based Shading) 而非物理著色(Physical Shading)的原因。判斷一種PBR光照模型是否是基于物理的涌穆,必須滿足以下三個條件(不用擔心,我們很快就會了解它們的):

  • 基于微平面(Microfacet)的表面模型雀久。
  • 能量守恒宿稀。
  • 應用基于物理的BRDF。

在這次的PBR系列教程之中赖捌,我們將會把重點放在最先由迪士尼(Disney)提出探討并被Epic Games首先應用于實時渲染的PBR方案祝沸。他們基于金屬質地工作流(Metallic Workflow)的方案有非常完備的文獻記錄,廣泛應用于各種流行的引擎之中并且有著非常令人驚嘆的視覺效果越庇。完成這次的教程之后我們將會制作出類似于這樣的一些東西:

注意這次的理論教程是一個三部曲系列(目前還在創(chuàng)作中)的一部分罩锐,所以這部分教程的內容有可能隨著其他兩部還沒完成的教程的進展而發(fā)生變化。同樣卤唉,這部教程的源代碼也并不完整涩惑,所以上面的圖片是取自一個私人項目之中,而非本教程的代碼所生成的桑驱。不過在完成之后這個圖片看上去應該會好很多竭恬。

請注意這個系列的教程所探討的內容屬于相當高端的領域,因此要求讀者對OpenGL和著色器光照有較好的理解熬的。讀者將會需要這些相關的知識:幀緩沖痊硕,立方體貼圖Gamma校正押框,HDR法線貼圖寿桨。我們還會深入探討一些高等數學的內容,我會盡我所能將相關的概念闡述清楚强戴。


微平面模型

所有的PBR技術都基于微平面理論亭螟。這項理論認為,達到微觀尺度之后任何平面都可以用被稱為微平面(Microfacets)的細小鏡面來進行描繪骑歹。根據平面粗糙程度的不同预烙,這些細小鏡面的取向排列可以相當不一致:

產生的效果就是:一個平面越是粗糙,這個平面上的微平面的排列就越混亂道媚。這些微小鏡面這樣無序取向排列的影響就是扁掸,當我們特指鏡面光/鏡面反射時,入射光線更趨向于向完全不同的方向發(fā)散(Scatter)開來最域,進而產生出分布范圍更廣泛的鏡面反射谴分。而與之相反的是,對于一個光滑的平面镀脂,光線大體上會更趨向于向同一個方向反射牺蹄,造成更小更銳利的反射:

在微觀尺度下,沒有任何平面是完全光滑的薄翅。然而由于這些微平面已經微小到無法逐像素的繼續(xù)對其進行區(qū)分沙兰,因此我們只有假設一個粗糙度(Roughness)參數氓奈,然后用統(tǒng)計學的方法來概略的估算微平面的粗糙程度。我們可以基于一個平面的粗糙度來計算出某個向量的方向與微平面平均取向方向一致的概率鼎天。這個向量便是位于光線向量l和視線向量v之間的中間向量(Halfway Vector)舀奶。我們曾經在之前的高級光照教程中談到過中間向量,它的計算方法如下:

微平面的取向方向與中間向量的方向越是一致斋射,鏡面反射的效果就越是強烈越是銳利育勺。然后再加上一個介于0到1之間的粗糙度參數,這樣我們就能概略的估算微平面的取向情況了:

我們可以看到罗岖,較高的粗糙度值顯示出來的鏡面反射的輪廓要更大一些涧至。與之相反地,較小的粗糙值顯示出的鏡面反射輪廓則更小更銳利呀闻。


能量守恒

微平面近似法使用了這樣一種形式的能量守恒(Energy Conservation):出射光線的能量永遠不能超過入射光線的能量(發(fā)光面除外)化借。如圖示我們可以看到,隨著粗糙度的上升鏡面反射區(qū)域的會增加捡多,但是鏡面反射的亮度卻會下降蓖康。如果不管反射輪廓的大小而讓每個像素的鏡面反射強度(Specular Intensity)都一樣的話,那么粗糙的平面就會放射出過多的能量垒手,而這樣就違背了能量守恒定律蒜焊。這也就是為什么正如我們看到的一樣,光滑平面的鏡面反射更強烈而粗糙平面的反射更昏暗科贬。

為了遵守能量守恒定律泳梆,我們需要對漫反射光和鏡面反射光之間做出明確的區(qū)分。當一束光線碰撞到一個表面的時候榜掌,它就會分離成一個折射部分和一個反射部分优妙。反射部分就是會直接反射開來而不會進入平面的那部分光線,這就是我們所說的鏡面光照憎账。而折射部分就是余下的會進入表面并被吸收的那部分光線套硼,這也就是我們所說的漫反射光照。

這里還有一些細節(jié)需要處理胞皱,因為當光線接觸到一個表面的時候折射光是不會立即就被吸收的邪意。通過物理學我們可以得知,光線實際上可以被認為是一束沒有耗盡就不停向前運動的能量反砌,而光束是通過碰撞的方式來消耗能量雾鬼。每一種材料都是由無數微小的粒子所組成,這些粒子都能如下圖所示一樣與光線發(fā)生碰撞宴树。這些粒子在每次的碰撞中都可以吸收光線所攜帶的一部分或者是全部的能量而后轉變成為熱量策菜。

一般來說,并非所有能量都會被全部吸收,而光線也會繼續(xù)沿著(基本上)隨機的方向發(fā)散做入,然后再和其他的粒子碰撞直至能量完全耗盡或者再次離開這個表面冒晰。而光線脫離物體表面后將會協(xié)同構成該表面的(漫反射)顏色同衣。不過在基于物理的渲染之中我們進行了簡化竟块,假設對平面上的每一點所有的折射光都會被完全吸收而不會散開。而有一些被稱為次表面散射(Subsurface Scattering)技術的著色器技術將這個問題考慮了進去耐齐,它們顯著的提升了一些諸如皮膚浪秘,大理石或者蠟質這樣材質的視覺效果,不過伴隨而來的則是性能下降代價埠况。

對于金屬(Metallic)表面耸携,當討論到反射與折射的時候還有一個細節(jié)需要注意。金屬表面對光的反應與非金屬材料還有電介質(Dielectrics)材料表面相比是不同的辕翰。它們遵從的反射與折射原理是相同的夺衍,但是所有的折射光都會被直接吸收而不會散開,只留下反射光或者說鏡面反射光喜命。亦即是說沟沙,金屬表面不會顯示出漫反射顏色。由于金屬與電介質之間存在這樣明顯的區(qū)別壁榕,因此它們兩者在PBR渲染管線中被區(qū)別處理矛紫,而我們將在文章的后面進一步詳細探討這個問題。

反射光與折射光之間的這個區(qū)別使我們得到了另一條關于能量守恒的經驗結論:反射光與折射光它們二者之間是互斥的關系牌里。無論何種光線颊咬,其被材質表面所反射的能量將無法再被材質吸收。因此牡辽,諸如折射光這樣的余下的進入表面之中的能量正好就是我們計算完反射之后余下的能量喳篇。

我們按照能量守恒的關系,首先計算鏡面反射部分态辛,它的值等于入射光線被反射的能量所占的百分比麸澜。然后折射光部分就可以直接由鏡面反射部分計算得出:

float kS = calculateSpecularComponent(...); // 反射/鏡面 部分
float kD = 1.0 - ks;                        // 折射/漫反射 部分

這樣我們就能在遵守能量守恒定律的前提下知道入射光線的反射部分與折射部分所占的總量了。按照這種方法折射/漫反射與反射/鏡面反射所占的份額都不會超過1.0因妙,如此就能保證它們的能量總和永遠不會超過入射光線的能量痰憎。而這些都是我們在前面的光照教程中沒有考慮的問題。


反射率方程

在這里我們引入了一種被稱為渲染方程(Render Equation)的東西攀涵。它是某些聰明絕頂人所構想出來的一個精妙的方程式铣耘,是如今我們所擁有的用來模擬光的視覺效果最好的模型∫怨剩基于物理的渲染所堅定的遵循的是一種被稱為反射率方程(The Reflectance Equation)的渲染方程的特化版本蜗细。要正確的理解PBR 很重要的一點就是要首先透徹的理解反射率方程:

反射率方程一開始可能會顯得有些嚇人,不過隨著我們慢慢對其進行剖析,讀者最終會逐漸理解它的炉媒。要正確的理解這個方程式踪区,我們必須要稍微涉足一些輻射度量學(Radiometry)的內容。輻射度量學是一種用來度量電磁場輻射(包括可見光)的手段吊骤。有很多種輻射度量(radiometric quantities)可以用來測量曲面或者某個方向上的光缎岗,但是我們將只會討論其中和反射率方程有關的一種。它被稱為輻射率(Radiance)白粉,在這里用LL來表示传泊。輻射率被用來量化單一方向上發(fā)射來的光線的大小或者強度。由于輻射率是由許多物理變量集合而成的鸭巴,一開始理解起來可能有些困難眷细,因此我們首先關注一下這些物理量:

輻射通量:輻射通量Φ表示的是一個光源所輸出的能量,以瓦特為單位鹃祖。光是由多種不同波長的能量所集合而成的溪椎,而每種波長則與一種特定的(可見的)顏色相關。因此一個光源所放射出來的能量可以被視作這個光源包含的所有各種波長的一個函數恬口。波長介于390nm到700nm(納米)的光被認為是處于可見光光譜中校读,也就是說它們是人眼可見的波長。在下面你可以看到一幅圖片楷兽,里面展示了日光中不同波長的光所具有的能量:

輻射通量將會計算這個由不同波長構成的函數的總面積地熄。直接將這種對不同波長的計量作為參數輸入計算機圖形有一些不切實際,因此我們通常不直接使用波長的強度而是使用三原色編碼芯杀,也就是RGB(或者按通常的稱呼:光色)來作為輻射通量表示的簡化端考。這套編碼確實會帶來一些信息上的損失,但是這對于視覺效果上的影響基本可以忽略揭厚。

立體角:立體角用ωω表示却特,它可以為我們描述投射到單位球體上的一個截面的大小或者面積。投射到這個單位球體上的截面的面積就被稱為立體角(Solid Angle)筛圆,你可以把立體角想象成為一個帶有體積的方向:

可以把自己想象成為一個站在單位球面的中心的觀察者裂明,向著投影的方向看。這個投影輪廓的大小就是立體角太援。

輻射強度:輻射強度(Radiant Intensity)表示的是在單位球面上闽晦,一個光源向每單位立體角所投送的輻射通量。舉例來說提岔,假設一個全向光源向所有方向均勻的輻射能量仙蛉,輻射強度就能幫我們計算出它在一個單位面積(立體角)內的能量大小:

計算輻射強度的公式如下所示:

其中I表示輻射通量Φ除以立體角ω碱蒙。

在理解了輻射通量荠瘪,輻射強度與立體角的概念之后夯巷,我們終于可以開始討論輻射率的方程式了。這個方程表示的是哀墓,一個擁有輻射強度Φ的光源在單位面積A趁餐,單位立體角ω上的輻射出的總能量:

輻射率是輻射度量學上表示一個區(qū)域平面上光線總量的物理量,它受到入射(Incident)(或者來射)光線與平面法線間的夾角θ的余弦值cosθ的影響:當直接輻射到平面上的程度越低時篮绰,光線就越弱后雷,而當光線完全垂直于平面時強度最高。這和我們在前面的基礎光照教程中對于漫反射光照的概念相似阶牍,其中cosθ就直接對應于光線的方向向量和平面法向量的點積:

float cosTheta = dot(lightDir, N);  

輻射率方程很有用喷面,因為它把大部分我們感興趣的物理量都包含了進去星瘾。如果我們把立體角ω和面積A看作是無窮小的走孽,那么我們就能用輻射率來表示單束光線穿過空間中的一個點的通量。這就使我們可以計算得出作用于單個(片段)點上的單束光線的輻射率琳状,我們實際上把立體角ω轉變?yōu)榉较蛳蛄喀厝缓蟀衙鍭轉換為點p磕瓷。這樣我們就能直接在我們的著色器中使用輻射率來計算單束光線對每個片段的作用了。

事實上念逞,當涉及到輻射率時困食,我們通常關心的是所有投射到點p上的光線的總和,而這個和就稱為輻射照度或者輻照度(Irradiance)翎承。在理解了輻射率和輻照度的概念之后硕盹,讓我們再回過頭來看看反射率方程:

我們知道在渲染方程中L代表通過某個無限小的立體角ωi在某個點上的輻射率,而立體角可以視作是入射方向向量ωi叨咖。注意我們利用光線和平面間的入射角的余弦值cos?θ來計算能量瘩例,亦即從輻射率公式L轉化至反射率公式時的n?ωi。用ωo表示觀察方向甸各,也就是出射方向垛贤,反射率公式計算了點p在ωo方向上被反射出來的輻射率Lo(p,ωo)的總和∪で悖或者換句話說:Lo表示了從ωo方向上觀察聘惦,光線投射到點p上反射出來的輻照度。

基于反射率公式是圍繞所有入射輻射率的總和儒恋,也就是輻照度來計算的善绎,所以我們需要計算的就不只是是單一的一個方向上的入射光,而是一個以點p為球心的半球領域Ω內所有方向上的入射光诫尽。一個半球領域(Hemisphere)可以描述為以平面法線n為軸所環(huán)繞的半個球體:

為了計算某些面積的值禀酱,或者像是在半球領域的問題中計算某一個體積的時候我們會需要用到一種稱為積分(Integral)的數學手段,也就是反射率公式中的符號∫∫箱锐,它的運算包含了半球領域Ω內所有入射方向上的dωi 比勉。積分運算的值等于一個函數曲線的面積,它的計算結果要么是解析解要么就是數值解。由于渲染方程和反射率方程都沒有解析解浩聋,我們將會用離散的方法來求得這個積分的數值解观蜗。這個問題就轉化為,在半球領域Ω中按一定的步長將反射率方程分散求解衣洁,然后再按照步長大小將所得到的結果平均化墓捻。這種方法被稱為黎曼和(Riemann sum) ,我們可以用下面的代碼粗略的演示一下:

int steps = 100;
float sum = 0.0f;
vec3 P    = ...;
vec3 Wo   = ...;
vec3 N    = ...;
float dW  = 1.0f / steps;
for(int i = 0; i < steps; ++i) 
{
    vec3 Wi = getNextIncomingLightDir(i);
    sum += Fr(p, Wi, Wo) * L(p, Wi) * dot(N, Wi) * dW;
}

通過利用dW來對所有離散部分進行縮放坊夫,其和最后就等于積分函數的總面積或者總體積砖第。這個用來對每個離散步長進行縮放的dW可以認為就是反射率方程中的dωi 。在數學上环凿,用來計算積分的dωi 表示的是一個連續(xù)的符號梧兼,而我們使用的dW在代碼中和它并沒有直接的聯系(因為它代表的是黎曼和中的離散步長),這樣說是為了可以幫助你理解智听。請牢記羽杰,使用離散步長得到的是函數總面積的一個近似值。細心的讀者可能已經注意到了到推,我們可以通過增加離散部分的數量來提高黎曼和的準確度(Accuracy)考赛。

反射率方程概括了在半球領域Ω<內,碰撞到了點p上的所有入射方向ωi上的光線的輻射率莉测,并受到fr的約束颜骤,然后返回觀察方向上反射光的Lo。正如我們所熟悉的那樣捣卤,入射光輻射率可以由光源處獲得忍抽,此外還可以利用一個環(huán)境貼圖來測算所有入射方向上的輻射率,我們將在未來的IBL教程中討論這個方法腌零。

現在唯一剩下的未知符號就是fr了梯找,它被稱為BRDF,或者雙向反射分布函數(Bidirectional Reflective Distribution Function)益涧,它的作用是基于表面材質屬性來對入射輻射率進行縮放或者加權锈锤。


BRDF

BRDF,或者說雙向反射分布函數闲询,它接受入射(光)方向ωi久免,出射(觀察)方向ωo,平面法線nn以及一個用來表示微平面粗糙程度的參數aa作為函數的輸入參數扭弧。BRDF可以近似的求出每束光線對一個給定了材質屬性的平面上最終反射出來的光線所作出的貢獻程度阎姥。舉例來說,如果一個平面擁有完全光滑的表面(比如鏡面)鸽捻,那么對于所有的入射光線ωi(除了一束以外)而言BRDF函數都會返回0.0 呼巴,只有一束與出射光線ωo擁有相同(被反射)角度的光線會得到1.0這個返回值泽腮。

BRDF基于我們之前所探討過的微平面理論來近似的求得材質的反射與折射屬性。對于一個BRDF衣赶,為了實現物理學上的可信度诊赊,它必須遵守能量守恒定律,也就是說反射光線的總和永遠不能超過入射光線的總量府瞄。嚴格上來說碧磅,同樣采用ωi和ωo作為輸入參數的 Blinn-Phong光照模型也被認為是一個BRDF。然而由于Blinn-Phong模型并沒有遵循能量守恒定律遵馆,因此它不被認為是基于物理的渲染【ń迹現在已經有很好幾種BRDF都能近似的得出物體表面對于光的反應,但是幾乎所有實時渲染管線使用的都是一種被稱為Cook-Torrance BRDF模型货邓。

Cook-Torrance BRDF兼有漫反射和鏡面反射兩個部分:

這里的kd是早先提到過的入射光線中被折射部分的能量所占的比率秆撮,而ksks是被反射部分的比率。BRDF的左側表示的是漫反射部分逻恐,這里用flambert來表示像吻。它被稱為Lambertian漫反射,這和我們之前在漫反射著色中使用的常數因子類似复隆,用如下的公式來表示:

c表示表面顏色(回想一下漫反射表面紋理)。除以π是為了對漫反射光進行標準化姆涩,因為前面含有BRDF的積分方程是受π影響的(我們會在IBL的教程中探討這個問題的)挽拂。

你也許會感到好奇,這個Lambertian漫反射和我們之前經常使用的漫反射到底有什么關系:之前我們是用表面法向量與光照方向向量進行點乘骨饿,然后再將結果與平面顏色相乘得到漫反射參數亏栈。點乘依然還在,但是卻不在BRDF之內宏赘,而是轉變成為了Lo積分末公式末尾處的n?ωi 绒北。

目前存在著許多不同類型的模型來實現BRDF的漫反射部分,大多看上去都相當真實察署,但是相應的運算開銷也非常的昂貴闷游。不過按照Epic公司給出的結論,Lambertian漫反射模型已經足夠應付大多數實時渲染的用途了贴汪。

BRDF的鏡面反射部分要稍微更高級一些脐往,它的形式如下所示:

Cook-Torrance BRDF的鏡面反射部分包含三個函數,此外分母部分還有一個標準化因子 扳埂。字母D业簿,F與G分別代表著一種類型的函數,各個函數分別用來近似的計算出表面反射特性的一個特定部分阳懂。三個函數分別為正態(tài)分布函數(Normal Distribution Function)梅尤,菲涅爾方程(Fresnel Rquation)和幾何函數(Geometry Function)

  • 正態(tài)分布函數:估算在受到表面粗糙度的影響下柜思,取向方向與中間向量一致的微平面的數量。這是用來估算微平面的主要函數巷燥。
  • 幾何函數:描述了微平面自成陰影的屬性酝蜒。當一個平面相對比較粗糙的時候,平面表面上的微平面有可能擋住其他的微平面從而減少表面所反射的光線矾湃。
  • 菲涅爾方程:菲涅爾方程描述的是在不同的表面角下表面所反射的光線所占的比率亡脑。

以上的每一種函數都是用來估算相應的物理參數的,而且你會發(fā)現用來實現相應物理機制的每種函數都有不止一種形式邀跃。它們有的非常真實霉咨,有的則性能高效。你可以按照自己的需求任意選擇自己想要的函數的實現方法拍屑。英佩游戲公司的Brian Karis對于這些函數的多種近似實現方式進行了大量的研究途戒。我們將會采用Epic GamesUnreal Engine 4中所使用的函數,其中D使用Trowbridge-Reitz GGX僵驰,F使用Fresnel-Schlick近似(Fresnel-Schlick Approximation)喷斋,而G使用Smith’s Schlick-GGX

1. 正態(tài)分布函數

正態(tài)分布函數D蒜茴,或者說鏡面分布星爪,從統(tǒng)計學上近似的表示了與某些(中間)向量h取向一致的微平面的比率。舉例來說粉私,假設給定向量h顽腾,如果我們的微平面中有35%與向量hh取向一致,則正態(tài)分布函數或者說NDF將會返回0.35诺核。目前有很多種NDF都可以從統(tǒng)計學上來估算微平面的總體取向度抄肖,只要給定一些粗糙度的參數以及一個我們馬上將會要用到的參數Trowbridge-Reitz GGX

在這里h表示用來與平面上微平面做比較用的中間向量,而a表示表面粗糙度窖杀。

如果我們把h當成是不同粗糙度參數下漓摩,平面法向量和光線方向向量之間的中間向量的話,我們可以得到如下圖示的效果:

當粗糙度很低(也就是說表面很光滑)的時候入客,與中間向量取向一致的微平面會高度集中在一個很小的半徑范圍內管毙。由于這種集中性,NDF最終會生成一個非常明亮的斑點痊项。但是當表面比較粗糙的時候锅风,微平面的取向方向會更加的隨機。你將會發(fā)現與hh向量取向一致的微平面分布在一個大得多的半徑范圍內鞍泉,但是同時較低的集中性也會讓我們的最終效果顯得更加灰暗皱埠。

使用GLSL代碼編寫的Trowbridge-Reitz GGX正態(tài)分布函數是下面這個樣子的:

float D_GGX_TR(vec3 N, vec3 H, float a)
{
    float a2     = a*a;
    float NdotH  = max(dot(N, H), 0.0);
    float NdotH2 = NdotH*NdotH;

    float nom    = a2;
    float denom  = (NdotH2 * (a2 - 1.0) + 1.0);
    denom        = PI * denom * denom;

    return nom / denom;
}

2. 幾何函數

幾何函數從統(tǒng)計學上近似的求得了微平面間相互遮蔽的比率,這種相互遮蔽會損耗光線的能量咖驮。

與NDF類似边器,幾何函數采用一個材料的粗糙度參數作為輸入參數训枢,粗糙度較高的表面其微平面間相互遮蔽的概率就越高。我們將要使用的幾何函數是GGX與Schlick-Beckmann近似的結合體忘巧,因此又稱為Schlick-GGX

這里的k是α基于幾何函數是針對直接光照還是針對IBL光照的重映射(Remapping) :

注意恒界,根據你的引擎把粗糙度轉化為α的方式不同,得到α的值也有可能不同砚嘴。在接下來的教程中十酣,我們將會廣泛的討論這個重映射是如何起作用的。

為了有效的估算幾何部分际长,需要將觀察方向(幾何遮蔽(Geometry Obstruction))和光線方向向量(幾何陰影(Geometry Shadowing))都考慮進去耸采。我們可以使用史密斯法(Smith’s method)來把兩者都納入其中:

使用史密斯法與Schlick-GGX作為Gsub可以得到如下所示不同粗糙度的視覺效果:

幾何函數是一個值域為[0.0, 1.0]的乘數,其中白色或者說1.0表示沒有微平面陰影工育,而黑色或者說0.0則表示微平面徹底被遮蔽颅和。

使用GLSL編寫的幾何函數代碼如下:

float GeometrySchlickGGX(float NdotV, float k)
{
    float nom   = NdotV;
    float denom = NdotV * (1.0 - k) + k;

    return nom / denom;
}

float GeometrySmith(vec3 N, vec3 V, vec3 L, float k)
{
    float NdotV = max(dot(N, V), 0.0);
    float NdotL = max(dot(N, L), 0.0);
    float ggx1 = GeometrySchlickGGX(NdotV, k);
    float ggx2 = GeometrySchlickGGX(NdotL, k);

    return ggx1 * ggx2;
}

3. 菲涅爾方程

菲涅爾(發(fā)音為Freh-nel)方程描述的是被反射的光線對比光線被折射的部分所占的比率抄瑟,這個比率會隨著我們觀察的角度不同而不同峦甩。當光線碰撞到一個表面的時候软吐,菲涅爾方程會根據觀察角度告訴我們被反射的光線所占的百分比。利用這個反射比率和能量守恒原則怔接,我們可以直接得出光線被折射的部分以及光線剩余的能量搪泳。

當垂直觀察的時候,任何物體或者材質表面都有一個基礎反射率(Base Reflectivity)蜕提,但是如果以一定的角度往平面上看的時候所有反光都會變得明顯起來森书。你可以自己嘗試一下,用垂直的視角觀察你自己的木制/金屬桌面谎势,此時一定只有最基本的反射性。但是如果你從近乎90度(譯注:應該是指和法線的夾角)的角度觀察的話反光就會變得明顯的多杨名。如果從理想的90度視角觀察脏榆,所有的平面理論上來說都能完全的反射光線。這種現象因菲涅爾而聞名台谍,并體現在了菲涅爾方程之中须喂。

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

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

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

平面對于法向入射的響應或者說基礎反射率可以在一些大型數據庫中找到电谣,比如這個。下面列舉的這一些常見數值就是從Naty Hoffman的課程講義中所得到的:

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

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

理論上來說,一個表面的金屬度應該是二元的:要么是金屬要么不是金屬列牺,不能兩者皆是整陌。但是,大多數的渲染管線都允許在0.0至1.0之間線性的調配金屬度瞎领。這主要是由于材質紋理精度不足以描述一個擁有諸如細沙/沙狀粒子/刮痕的金屬表面泌辫。通過對這些小的類非金屬粒子/刮痕調整金屬度值,我們可以獲得非常好看的視覺效果九默。

通過預先計算電介質與導體的F0F0值震放,我們可以對兩種類型的表面使用相同的Fresnel-Schlick近似,但是如果是金屬表面的話就需要對基礎反射率添加色彩驼修。我們一般是按下面這個樣子來實現的:

vec3 F0 = vec3(0.04);
F0      = mix(F0, surfaceColor.rgb, metalness);

我們?yōu)榇蠖鄶惦娊橘|表面定義了一個近似的基礎反射率殿遂。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的點乘的結果咬荷。

4. Cook-Torrance反射率方程

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

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


編寫PBR材質

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

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

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

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

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

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

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

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


延伸閱讀

后記

本篇已結束逾礁,下一篇關于PBR - 光照说铃。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市嘹履,隨后出現的幾起案子腻扇,更是在濱河造成了極大的恐慌,老刑警劉巖砾嫉,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件幼苛,死亡現場離奇詭異,居然都是意外死亡焕刮,警方通過查閱死者的電腦和手機舶沿,發(fā)現死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來配并,“玉大人括荡,你說我怎么就攤上這事「刃” “怎么了畸冲?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我邑闲,道長算行,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任苫耸,我火速辦了婚禮州邢,結果婚禮上,老公的妹妹穿的比我還像新娘鲸阔。我一直安慰自己偷霉,他們只是感情好,可當我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布褐筛。 她就那樣靜靜地躺著类少,像睡著了一般。 火紅的嫁衣襯著肌膚如雪渔扎。 梳的紋絲不亂的頭發(fā)上硫狞,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機與錄音晃痴,去河邊找鬼残吩。 笑死,一個胖子當著我的面吹牛倘核,可吹牛的內容都是我干的泣侮。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼紧唱,長吁一口氣:“原來是場噩夢啊……” “哼活尊!你這毒婦竟也來了?” 一聲冷哼從身側響起漏益,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蛹锰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后绰疤,有當地人在樹林里發(fā)現了一具尸體铜犬,經...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年轻庆,在試婚紗的時候發(fā)現自己被綠了癣猾。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡余爆,死狀恐怖煎谍,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情龙屉,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站转捕,受9級特大地震影響作岖,放射性物質發(fā)生泄漏。R本人自食惡果不足惜五芝,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一痘儡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧枢步,春花似錦沉删、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至隘擎,卻和暖如春殴穴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背货葬。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工采幌, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人震桶。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓休傍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蹲姐。 傳聞我的和親對象是個殘疾皇子磨取,可洞房花燭夜當晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內容