官方網站:https://edu.battlefire.cn
簡介
我們先前已經實現了對漫反射部分的光線影響力做積分了,接下來我們要對鏡面反射部分進行積分,鏡面反射部分由於影響因子有兩個,一個是入射光線的角度,另一個是觀察視角,所以我們不能按照漫反射的那種做法來做。在這裡,我們依然不講解那些高端的原理,我們先講代碼怎麼碼,碼完代碼再去對照那些資料上的高端原理,我們先碼代碼看效果,show you the code。
參考資料不限於:
https://learnopengl.com/PBR/IBL/Specular-IBL
回顧漫反射
在介紹Diffuse Irradiance的時候,我們介紹了,為了對漫反射部分實現積分,我們把公式拆分成了這樣
至於為什麼可以這麼做,這是Epic Game研究出來的一套被稱為Split Sum Approximation的理論,作為一個碼農,如果你想知道這些,我們後面再慢慢講,我們先把公式碼成代碼再說。
PrefilteredEnvironmentMap
對於左邊的這一坨,我們需要進行ImportanceSampling,也就是給一個pdf函數,並且這個pdf函數是一個變種pdf函數,它帶有一個偏移,也就是以這個偏移為基準,在此基礎上對隨機採樣。那麼我們究竟怎麼把公式碼成代碼呢?
我們知道,我們需要對環境中的光線進行採樣對吧,所以我們需要入射光線,反射光線,法線。在我們的的代碼裡,我們把法線、觀察視線、反射光線都幹成一條線,也就是你垂直盯著某個玩意看,ViewDir、Normal、ReflectDir都是一樣的。至於為什麼我們這麼幹,那就是背後的Epic Game大佬研究的理論基礎了,我們在生成這個PrefilteredEnvironmentMap的時候這麼幹就可以了。
然後此處為何引入蒙特卡洛的那個pdf函數呢?那是因為,首先我們的反射光線具備這樣的特性,根據模型表面的粗糙程度,它的反射範圍是呈現下面這樣一撮一撮的那幢狀態,所以只有在這個範圍內才會有反射光線,因此其他地方大概率沒有高光。
如果你依然不清楚這些,那也沒關係,你只要知道,由於我們使用了這招,所以我們不用像Diffuse Irradiance裡面那樣採用黎曼和的方式對整個半球進行積分,而是通過少數幾個隨機的向量來實現對鏡面反射光線的描述。我們根據粗糙程度,來生成不同mipmap level的PrefilteredEnvironmentMap,並在後續的PBR渲染中,使用粗糙程度去在這些mipmap level之間選擇合適的數據出來渲染模型。
如果我們結合蒙特卡洛的思想,如何去積分出這個PrefilteredEnvironmentMap呢?我們可以這麼做:
隨機出來一個vec2
結合roughness和vec2這個隨機數通過φ和θ的方式來求得一個笛卡爾坐標(x,y,z)
這個(x,y,z)就是我們的隨機向量了,然後我們通過normal來把它從tangent空間轉到世界坐標系裡去叫G
轉完後,我們用ViewDir對G求反射,也就是reflect(-ViewDir,G),這個結果記做LightDir
我們用這個LightDir去從CubeMap中取顏色,並用上pdf對它進行處理
同志們,這就出來了,隨機數有了、pdf有了,剩下的就是蒙特卡洛一頓操作了。哇咔咔。然後那個權重嘛(1/pdf),我們就用LightDir和normal的點積來表示。
採樣總次數嘛,咱們就可以隨便,用個1024或者2048都可以。總之次數越多,數據越精確。最後還有一個在glsl中生成隨機數的函數怎麼辦呢?這個也有成熟的算法,比如Hammersley Sequence隨機算法。好了,現在所有的知識點都對上號了,上代碼:
上效果圖:
roughness分別是:0.0、0.25、0.5、0.75、1.0
完結、撒花,下一篇我們看看LUT怎麼弄