天天看點

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

目錄

概念:環境光照與全局光照(Environment Lighting & Global Illumination)

基于圖像的光照(Image Based Lighting,IBL)

The Split Sum Approximation

過濾環境貼圖

預計算BRDF積分

預計算輻射度傳輸(Precomputed Radiance Transfer,PRT)

球諧(Spherical Harmonics,SH)

球諧光照(Spherical Harmonic Lighting)

Diffuse 物體的球諧光照

Glossy 物體的球諧光照

球諧光照預計算 Interreflection TransferDiffuse 物體的 Interreflection Transfer

球諧的旋轉(SH Rotation)

光照探針(Light Probe)

Unity 四面體鑲嵌(Tetrahedral Tessellations)

UE4 間接光緩存(ILC) & 體積光照貼圖(VLM)

光照貼圖(Light Map)

Light Map 結合動态光照

Lighting Scenarios 實作晝夜天氣系統

總結

參考

先理清楚環境光和全局光照的概念,一個完整的光照效果往往包含:主光+間接光+環境光。

主光:主要的光源,例如 directional light、spot light、area light

間接光:任何光照射到物體後反彈出來的光,展現了物體與物體間的光照關系

環境光:本質屬于間接光,但可以被看成是一種特殊的光源,例如 skylight、background

雖然環境光很多情況下都被當成一種特殊的光源來處理,但我仍然把它歸類為間接光,這是因為: 在現實實體世界中,環境光意味着主光照射到遠處(即場景外)的物體(包括天空)後反彈出來的光;在實際 Rendering 上,也可以實時地将場景内物體的間接光照資訊包含進環境光。
基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

而 全局光照(Global Illumination,GI),嚴格意義上指主光+完整的間接光下的光照效果,實際上隻要有展現間接光效果(即使是部分效果)的光照都可稱為 GI。

是以本文将标題改成 Environment Lighting 以強調本文的算法是基于環境光這個角度出發的,但是所屬範疇仍然可算 GI 方法。

此外,GI 總體上分為兩派:

一派是通過一套統一标準的渲染流程把任何物體的 GI 計算出來,往往計算量極大但效果更加實體更加真實,典型的例子便是離線光線追蹤

另一派是把 GI 的效果看成一個個部分來組成,這樣我們可以選擇其中一些 GI 效果組合使用,适應不同的性能(往往計算量相對低些,尤其是實時渲染)的同時也能帶來能接受的 GI 效果(雖然往往不是嚴謹的實體正确),典型的例子就是這篇部落格所介紹的方法和另一些完全動态的 GI 方法(如 RSM、SSAO、SSRT)

基于圖像的光照(IBL),簡單的說就是一類通過 環境貼圖(Environment Map) 來儲存某個物體的環境光資訊,進而實作該物體的基于實體的物體渲染方法。

IBL 可用于 diffuse/glossy/specular 物體(基本上包含大部分物體了)渲染:這取決于環境貼圖,環境貼圖分辨率越大,那麼所能表示高頻資訊就越多,進而越适合 specular 物體的渲染;而分辨率越低,所表示的資訊更多是低頻資訊,則 diffuse 物體的渲染也足以滿足,而且還能節省一定存儲空間。

IBL 可以實作成動态環境光照:實時渲染出動态的環境貼圖。有一定開銷,一般隻用于少量的specular物體。

IBL 可以實作成靜态環境光照:預渲染環境貼圖。需要環境光是靜态的。

用 IBL 實作靜态環境光照就有點類似 Light Map的做法了,差別在于 IBL 存的是靜态環境光資訊,Light Map 存的是接受靜态環境光資訊後的着色結果。

為了表示來自四面八方的環境光資訊,IBL 使用 Spherical Map 或者 Cube Map 的方式來存儲:

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)
基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

IBL 中最常見的算法便是基于 The Split Sum Approximation 的算法。

我們知道,一般的渲染方程如下:

\(L_{r}\left(x, \omega_{r}\right)=\int_{\Omega^{+}} L_{i}\left(x, \omega_{i}\right) f_{r}\left(x, \omega_{i}, \omega_{r}\right)\left(n \cdot \omega_{i}\right) \mathrm{d} \omega_{i}\)

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

在實際渲染的時候,我們當然可以使用蒙特卡洛方法實作該渲染方程,然而這樣的開銷是巨大的(每個shading point都要做多重采樣,而且結果很容易是noisy的)。

為了進一步加快式子,這裡有一個很經典的近似公式:

\(\int_{\Omega^+} f(x) g(x) \mathrm{d} x \approx \frac{\int_{\Omega_{G}} f(x) \mathrm{d} x}{\int_{\Omega_{G}} \mathrm{~d} x} \cdot \int_{\Omega^+} g(x) \mathrm{d} x\)

積分域 \(\Omega_G\) :在原本 \(\Omega^+\) 的積分域範圍内剔除掉 \(f(x) = 0\) 的地方而剩餘的範圍。

想讓這個公式近似效果比較精确,那麼需要滿足以下一種或兩種條件:

積分域 \(\Omega_G\) 比較小

\(g(x)\) 比較光滑,即變化不是很大

而我們的觀察是:

如果 BRDF 是 glossy/specular 的,那麼它的 lobe 往往是花瓣狀,即隻有很小的積分域才能接受環境光。

如果 BRDF 是 diffuse 的,那麼它的 lobe 往往是均勻的半球狀,即無論哪個方向的環境光打進來, \(f_r\) 函數的輸出幾乎沒多少變化(甚至是個常數)。

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

于是基于以上理論,Split Sum 方法對渲染方程改造成這樣的近似公式來獲得渲染的加速:

\(L_{r}\left(x, \omega_{r}\right) \approx \frac{\int_{\Omega_{f_{r}}} L_{i}\left(x, \omega_{i}\right) \mathrm{d} \omega_{i}}{\int_{\Omega_{f_{r}}} \mathrm{~d} \omega_{i}} \cdot \int_{\Omega^{+}} f_{r}\left(x, \omega_{i}, \omega_{r}\right) \cos \theta_{i} \mathrm{~d} \omega_{i}\)

對渲染方程拆分成兩個部分(環境光積分、BRDF積分)後就可以通過預計算的方式(後面兩節會介紹如何預計算)分别減少這些積分的運作時開銷,總結這種方法的好處是:

Split Sum 方法和原始蒙特卡洛方法的圖像效果幾乎一模一樣

由于不用對環境貼圖進行多重采樣,性能開銷大大減低了

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

環境光積分:\(\frac{\int_{\Omega_{f_{r}}} L_{i}\left(x, \omega_{i}\right) \mathrm{d} \omega_{i}}{\int_{\Omega_{f_{r}}} \mathrm{~d} \omega_{i}}\)

因為我們已經擁有一張環境貼圖(無論是實時的還是預渲染的)來存儲環境光資訊了,為了計算環境光部分的積分,需要在 \(\Omega_{fr}\) 範圍内做多次光線采樣。但是,可以有一個幾乎等價但避免運作時多重采樣的方式:

預先對紋理進行濾波操作(模糊),我們隻需要對濾波後的環境貼圖采樣一次光線方向就能得到積分。

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)
濾波後的環境貼圖實際上稱為 Irradiance Environment Map :原來環境貼圖中的機關是 radiance \(L(\mathrm{x}, \omega)\),貼圖積分後的機關則變成了 Irradiance \(E(x)\)。

當然,BRDF Lobe 的形狀越尖銳,即環境光積分範圍越小,就需要使用模糊程度更低的環境貼圖;反之 BRDF Lobe 的形狀越粗壯,即環境光積分範圍越大,就需要使用模糊程度更高的環境貼圖。

我們可以使用 MIPMAP技術 來生成不同Level的環境貼圖,通過三線性插值(Trilinear Interportion)的方式來得出任何模糊程度且任何2D位置的環境光濾波結果。

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

回顧 Microfacet BRDF 的組成:

Fresnel項(舉例 Schlick's approximation)

\(F=F_0 +(1-F_0)(1-(h \cdot \omega_{r}))^{5} = F_0 +(1-F_0)(1-(\cos\theta_{vh}))^{5}\)

NDF項(舉例 Beckmann NDF)

\(D(h)=\frac{1}{\pi \alpha^{2}({n} \cdot {h})^{4}} \cdot \exp {\left(\frac{({n} \cdot {h})^{2}-1}{a^{2}({n} \cdot {h})^{2}}\right)} = \frac{1}{\pi \alpha^{2}\cos^4 \theta_h } \cdot \exp {\left(\frac{\cos^2 \theta_h -1}{a^{2}\cos^2 \theta_h }\right)}\)

可以預想到,該BRDF 的積分結果依賴于三個參數:

\(F_0\)(Fresnel項系數)

\(\alpha\) (粗糙度 roughness)

\(\theta_v\) (反射方向與法線的夾角,實際上決定了 \(\theta_{vh}\)、\(\theta_{h}\))

我們可以把 \(F_0\) 項拆出來,讓BRDF 積分拆成兩個積分,但是這些積分都減少了一個依賴的參數:

\(\begin{align} \int_{\Omega^{+}} f_{r}\left(p, \omega_{i}, \omega_{o}\right) \cos \theta_{i} \mathrm{~d} \omega_{i}\approx & F_{0} \int_{\Omega^{+}} \frac{f_{r}}{F}\left(1-\left(1-\cos \theta_{vh}\right)^{5}\right) \cos \theta_{i}\mathrm{~d} \omega_{i} \\ & + \int_{\Omega^{+}} \frac{f_{r}}{F}\left(1-\cos \theta_{vh}\right)^{5} \cos \theta_{i} \mathrm{~d}\omega_{i} \end{align}\)

這樣,對于相同的材質(相同的BRDF),我們就可以針對剩餘兩個依賴的參數 \(\alpha\) 、\(\theta_v\) 建立一張 二維查詢表:

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

預計算輻射度傳輸(Precomputed Radiance Transfer,PRT) 是一類通過預計算輻射度傳輸的基于實體的物體渲染方法。所謂輻射度傳輸,可以了解成物體自身的陰影/AO(AmbientOcclusion)和表面互反射等有關于光路傳輸的資訊。是以 PRT 往往适用于動态光照下的靜态物體/靜态材質。

PRT 可以實作動态環境光照:僅預計算 transfer 部分

PRT 可以實作靜态環境光照:不僅預計算 transfer,還順便預計算環境光部分(可以稱為 radiance);這樣就能以更低性能開銷實作運作時基于實體的渲染,隻是光照動态性會有所限制(但不一定完全靜态)

順便一提,PRT 方法在2002年 Siggraph 會議被 Peter-Pike Sloan 首先提出,并從此掀起了一波 PRT 方法的研究浪潮。當時 Peter-Pike Sloan 論文所實作的 PRT 算法便是基于球諧(SH)的,實際上 PRT 不僅可以通過 SH 去表示低頻環境光場景,還可以有其它方法(如Wavelet)。不過本文仍将主要介紹球諧光照(SH Lighting)方法。

對于任意函數 \(f(x)\) ,不管是連續的還是不連續的,我們可以展開成一系列基函數(每項都帶某個系數)的線性組合:

\(f(x)=\sum_{i} c_{i} \cdot B_{i}(x)\)

例如,多項式展開可以看成是一系列基函數(多項式)的線性組合:\(f(x)=c_{0} +c_1\cdot x^1 + c_2 \cdot x^2 + ...\) 再例如,傅立葉變換也可以将 \(f(x)\) 表示成另一系列基函數(各種頻率的正弦諧波)的線性組合:
基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

而 球諧(Spherical Harmonics,SH) 便是定義在球面上的一系列2D基函數,它與2D傅裡葉序列有點相似,但非常适合球面函數 \(f(\omega)\)(即參數為機關球面向量)。

SH 是分階數的:在第0階(l=0)有1個基函數(m=0);第1階(l=1)有3個基函數(m=-1,0,1)...第n階(l=n)有2n+1個基函數(m=-l,...,0,...,l)。實際上,階數越低的基函數所代表的資訊就越是低頻。如果要完全複原一個任意函數,我們需要無窮階的 SH;而如果我們隻要複原一個任意函數的近似(換句話說隻重建出該函數的低頻資訊),那麼我們完全可以隻需要前幾階的 SH(包含 l=0,l=1,...,l=n 每一階的所有基函數)。

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

SH 的實數形式的基函數如下:

SH 基函數的形式比較複雜,隻建議看一眼就跳過。

\(y_{l}^{m}(\theta, \varphi)=\left\{\begin{array}{rl}\sqrt{2} \operatorname{Re}\left(Y_{l}^{m}\right) & m>0 \\ \sqrt{2} \operatorname{Im}\left(Y_{l}^{m}\right) & m<0 \\ Y_{l}^{0} & m=0\end{array}=\left\{\begin{array}{cc}\sqrt{2} K_{l}^{m} \cos m \varphi P_{l}^{m}(\cos \theta) & m>0 \\ \sqrt{2} K_{l}^{m} \sin |m| \varphi P_{l}^{|m|}(\cos \theta) & m<0 \\ K_{l}^{0} P_{l}^{0}(\cos \theta) & m=0\end{array}\right.\right.\)

其中, \(K_{l}^{m}=\sqrt{\frac{(2 l+1)(l-|m|) !}{4 \pi(l+|m|) !}}\) \(p^m_l\) 為勒讓德多項式(Legendre polynomials): $P_0^0= 1 $ $P_{m}^{m} =(1-2 m) P_{m-1}^{m-1} $ $P_{m+1}^{m} =(2 m+1) z P_{m}^{m} $ $ P_{l}^{m} =\frac{(2 l-1) z P_{l-1}^{m}-(l+m-1) P_{l-2}^{m}}{l-m} $ z為球面向量對應球面坐标的z值,該多項式不依賴x值y值。

以下是前3階的SH實數形式的基函數:

\(l=0\):

\(Y_{00}=s=Y_{0}^{0}=\frac{1}{2} \sqrt{\frac{1}{\pi}}\)

\(l=1\):

\(Y_{1,-1}=p_{y}=i \sqrt{\frac{1}{2}}\left(Y_{1}^{-1}+Y_{1}^{1}\right)=\sqrt{\frac{3}{4 \pi}} \cdot \frac{y}{r}\)

\(Y_{1,0}=p_{z}=Y_{1}^{0}=\sqrt{\frac{3}{4 \pi}} \cdot \frac{z}{r}\)

\(Y_{1,1}=p_{x}=\sqrt{\frac{1}{2}}\left(Y_{1}^{-1}-Y_{1}^{1}\right)=\sqrt{\frac{3}{4 \pi}} \cdot \frac{x}{r}\)

\(l=2\):

\(Y_{2,-2}=d_{x y}=i \sqrt{\frac{1}{2}}\left(Y_{2}^{-2}-Y_{2}^{2}\right)=\frac{1}{2} \sqrt{\frac{15}{\pi}} \cdot \frac{x y}{r^{2}}\)

\(Y_{2,-1}=d_{y z}=i \sqrt{\frac{1}{2}}\left(Y_{2}^{-1}+Y_{2}^{1}\right)=\frac{1}{2} \sqrt{\frac{15}{\pi}} \cdot \frac{y z}{r^{2}}\)

\(Y_{2,0}=d_{z^{2}}=Y_{2}^{0}=\frac{1}{4} \sqrt{\frac{5}{\pi}} \cdot \frac{-x^{2}-y^{2}+2 z^{2}}{r^{2}}\)

\(Y_{2,1}=d_{s z}=\sqrt{\frac{1}{2}}\left(Y_{2}^{-1}-Y_{2}^{1}\right)=\frac{1}{2} \sqrt{\frac{15}{\pi}} \cdot \frac{z x}{r^{2}}\)

\(Y_{2,2}=d_{x^{2}-y^{2}}=\sqrt{\frac{1}{2}}\left(Y_{2}^{-2}+Y_{2}^{2}\right)=\frac{1}{4} \sqrt{\frac{15}{\pi}} \cdot \frac{x^{2}-y^{2}}{r^{2}}\)

SH 與一般的基函數相比,具有以下性質:

基函數之間具有正交性(orthonormal)

\(\int_{\Omega} B_{i}(\omega) \cdot B_{j}(\omega) \mathrm{d} \omega=\mathbf{1} \quad(i=j)\)

\(\int_{\Omega} B_{i}(\omega) \cdot B_{j}(\omega) \mathrm{d} \omega=\mathbf{0} \quad(i\neq j)\)

通過 投影(Projection) 可以很友善得到 SH 系數(SH coefficients)

\(f_i = \int_{\Omega}f(\omega)\cdot B_i(\omega)d\omega\)

通過系數向量組與基函數組的點積(前n階的基函數/系數共有 n*n 個)可以很友善重建球面函數

\(f(\omega)\approx \sum^{n^2}_{i=1} f_{i} B_{i}(\mathbf{\omega})\)

product projection:\(c(\omega)=a(\omega)b(\omega)\) ,已知 \(a\) 的形式而 \(b\) 未知,有

\(\vec{c} = M\cdot \vec b\)

其中,\(\vec{c}\) 為 \(c(\omega)\) 的SH系數向量組,\(\vec{b}\) 為 \(b(\omega)\) 的SH系數向量組,\(M\) 為 \(n^2\) X \(n^2\) 的矩陣,其元素為

\(M_{ij}=\int_{\Omega}a(\omega)B_i(\omega)B_j(\omega)d\omega\)

這樣我們就可以預計算好 \(M\) ,等到知道 \(\vec{b}\) 後,乘起來就能得到 \(\vec{c}\)

推導: \(令 M_{i}(\omega)=a(\omega)B_i(\omega)\) \(\begin{align} c_i &= \int_{\Omega} a(\omega)b(\omega)B_i(\omega) d\omega \\ &= \int_{\Omega} M_i(\omega)b(\omega)d\omega \\ &= \int_{\Omega} \sum_{j=1}^{n^2} (M_{ij} B_j(\omega)) b(\omega) d \omega \\ &= \sum_{i=1}^{n^2} M_{ij} \int_{\Omega} B_j(\omega)b(\omega) d \omega \\ &= \sum_{j=1}^{n^2} M_{ij}\cdot b_j \end{align}\)

支援插值,對 SH 系數的插值相當于對重建的函數值的插值。

旋轉不變性(rotational invariance),對函數 \(f\) 的旋轉 \(R_{SH}\) 等價于對 \(f(\omega)\) 的自變量的旋轉 \(R_{3D}\):

\(R_{SH}(f(\omega))=f(R_{3D}(\omega))\)

紋理本質上也是一個函數(信号),輸入二維坐标,輸出對應紋素的RGBA值。傳統的環境光資訊往往使用環境貼圖(Environment Map)表示,這往往需要一個龐大的二維數組存儲各個紋素的值,十分耗費空間,而且采樣和紋理I/O也有一定開銷。

球諧光照(SH Lighting) 的思路:将渲染方程分為兩個球面函數(即 lighting function 和 transfer function),這些球面函數将使用 SH 方法來表示:

對于環境光(lighting)部分,隻需預先存儲若幹個 SH 系數而不必存儲一整張環境貼圖。

對于傳輸函數(transfer function) 部分,隻需預先存儲若幹個 SH 系數(diffuse情況下)或者矩陣(glossy情況下),預計算好傳輸率可以在實時渲染中以極低代價實作自陰影、互反射的效果。

不過 SH Lighting 一般采用3階SH,是以 SH 所能表示的 lighting 和 transfer 資訊是低頻的,隻适用于 diffuse 和 glossy 的物體而不适用于 specular 的物體。

SH lighting 效果(分别為 diffuse物體的無陰影情況、diffuse物體的陰影&互反射情況、glossy物體的無陰影情況、glossy物體的陰影&互反射情況):

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

Diffuse 物體的渲染方程:

\(L(r)=\int_{\Omega^+} L_e(\mathbf{\omega})\cdot \rho \cdot V(\mathbf{\omega}) \max (0, n\cdot \mathbf{\omega}) \mathrm{d} \mathbf{\omega}\)

\(L_e\) 代表環境光; \(\rho\) 為 BRDF 項;\(V\) 為 Visibility,表示不被遮擋的程度,往往表現為自遮擋産生的陰影現象。

由于物體是 diffuse 的,是以它的 BRDF 将是一個常數 \(\rho\) (無論從哪個方向觀察都得到相同的BRDF值),也是以 diffuse 物體的 \(L\) 将是一個常量值,而不受參數 \(r\) 影響

對于 lighting 部分 \(L(\mathbf{\omega})\),原本需要對 Environment Map 進行查詢,而現在可以換成使用 SH 函數去表示:\(L_e(\mathbf{\omega}) \approx \sum l_{i} B_{i}(\mathbf{\omega})\)

對于 transfer function 部分 \(T(\omega)=V(\mathbf{\omega}) \max (0, n\cdot \mathbf{\omega})\) , 也可以換成使用 SH 函數去表示:\(T(\omega) \approx \sum T_j B_j(\omega)\)

代入渲染方程整理後得:

\(\begin{align} L(r) &\approx \rho \int_{\Omega^+} \sum_{i=1}^{n^2}l_{i}B_i(\omega) \sum_{j=1}^{n^2}T_j\mathrm{B}_{j}(\mathbf{\omega}) \mathrm{d} \mathbf{\omega} \\ &= \rho\sum_{i=1}^{n^2} \sum_{j=1}^{n^2} l_{i}T_j\int_{\Omega^+} B_i(\omega) \mathrm{B}_{j}(\mathbf{\omega})d\omega \\ &= \rho\sum_{i=1}^{n^2} l_{i}T_i\int_{\Omega^+} B_i(\omega) \mathrm{B}_{i}(\mathbf{\omega})d\omega \\ &= \rho\sum_{i=1}^{n^2} l_{i}T_i \end{align}\)

這樣,我們隻需要預計算出 \(l_i\) 和 \(T_i\),就能讓運作時的diffuse物體渲染速度大大提升。

預計算過程:

對整個環境光資訊(環境貼圖),預計算 lighting 的 SH 系數向量組 \(\vec{l}\),其中一個元素為:\(l_{i}=\int_{\Omega^+} L_e(\mathbf{\omega}) B_{i}(\mathbf{\omega}) \mathrm{d} \mathbf{\omega}\)

對每個頂點,預計算 light transfer 的 SH 系數向量組 \(\vec{T}\),其中一個元素為:\(T_i=\int_{\Omega^{+}}V(\mathbf{\omega}) \max (0, n\cdot \mathbf{\omega}) \mathrm{B}_{i}(\mathbf{\omega}) \mathrm{d} \mathbf{\omega}\)

此時,我們可以了解成系數 \(l_i\) 代表了環境光照(lighting)的資訊,而系數 \(T_i\) 代表了在某個頂點上光路傳輸(light transfer)的資訊;整個模型預計算完成之後将會得到一個 lighting 系數向量和模型頂點數量對應的 transfer 系數向量。

運作時渲染過程:

在 vertex shding 階段計算頂點的 SH 顔色 \(L(r) \approx \rho \sum_{i=1}^{n^2} l_{i} T_{i} = \rho( \vec{l}\cdot \vec{T})\)

在 pixel/fragment shading 階段得到插值後的 SH 顔色即為該像素的顔色

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

Glossy 物體的渲染方程:

\(L(r)=\int_{\Omega^+} L_e(\mathbf{\omega})\cdot \rho(r,\mathbf{\omega}) \cdot V(\mathbf{\omega}) \cdot \max (0, n\cdot \mathbf{\omega}) \mathrm{d} \mathbf{\omega}\)

對于 glossy 物體,不同視角觀察物體表面同一點會有不同的光照。是以 glossy 的 BRDF 将是四維的函數(參數不僅包含\(\mathbf{\omega}\),還包含\(r\)),這次将 BRDF 算入 transfer,則 transfer function 将額外增加一個二維參數 \(r\)

對于環境光(lighting)即 \(L(\mathbf{\omega})\),原本需要對 Environment Map 進行查詢,而現在可以換成使用 SH 函數去表示:\(L_e(\mathbf{\omega}) \approx \sum l_{i} B_{i}(\mathbf{\omega})\)

對于傳輸函數(transfer function) \(T(r,\omega)=\rho(r,\mathbf{\omega}) V(\mathbf{\omega}) \max (0, n\cdot \mathbf{\omega})\) ,換成使用 SH 函數去表示:\(T(r,\omega) \approx \sum_{i=1}^{n^2} T_{i}(r)B_i(\omega)\approx \sum_{i=1}^{n^2} \sum_{j=1}^{n^2} T_{ij} B_j(r)B_i(\omega)\)

由于額外多了一個二維的參數,transfer 系數将是一個矩陣而非之前 diffuse 情況下的系數向量

\(\begin{align} L(r) & \approx \int_{\Omega^+} \sum_{i=1}^{n^2} l_{i} B_{i}\sum_{j=1}^{n^2}\sum_{k=1}^{n^2} T_{jk} B_j(\omega)B_k(r)\mathrm{d} \mathbf{\omega} \\ &= \sum_{i=1}^{n^2}\sum_{j=1}^{n^2}\sum_{k=1}^{n^2} l_iT_{jk }B_k(r) \int_{\Omega^+} B_{i}(\omega)B_j(\omega)\mathrm{d} \mathbf{\omega} \\ &= \sum_{i=1}^{n^2}\sum_{k=1}^{n^2}l_iT_{ik }B_k(r) \end{align}\)

對整個環境光資訊,預計算 lighting 的 SH 系數向量組 \(\vec{l}\),其中一個元素為:\(l_{i}=\int_{\Omega^+} L(\mathbf{\omega}) B_{i}(\mathbf{\omega}) \mathrm{d} \mathbf{\omega}\)

對每個頂點,預計算 light transfer 矩陣 \(T\),其中一個元素為:\(T_{ij}=\int_{\Omega^{+}}\mathrm{B}_{j}(\mathbf{\omega}) T_i(\omega) \mathrm{d} \mathbf{\omega}\) 、\(T_i(r) = \int_{\Omega^+}T(r,\omega)B_i(\omega)d\omega\)

由于 Glossy 物體需要每個頂點存儲一個矩陣 T,這使得空間開銷略大,是以不太實用。

在 vertex shding 階段計算頂點的 SH 顔色 \(L(r) \approx \sum_{i=1}^{n^2}\sum_{j=1}^{n^2} l_{i} T_{ij} B_j(r) = T\vec{l}\cdot \vec{B(r)}\)

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)
原論文實際上還有個 BRDF 卷積步驟。但是本身用SH表示環境光資訊已經足夠低頻(模糊)了,對這個卷積步驟,個人先存個疑。

而前面的渲染方程中:

\(L_{x}(r)=L^0_{x}(r)=\int_{\Omega^+} L_{e}(\mathbf{\omega})\cdot \rho(r,\mathbf{\omega}) \cdot V(\mathbf{\omega}) \cdot \max (0, n\cdot \mathbf{\omega}) \mathrm{d} \mathbf{\omega}\)

隻考慮幾何傳播關系的因素隻有 \(V(\omega)\cdot max(0,n\cdot\omega)\),即隻可實作陰影或者無陰影(令 \(V=1\))的效果,并不能實作互反射(interreflection)的效果。

所謂 interreflection,實際上就是某個點朝外圍環境看時,\(V=0\) 意味着有幾何部分遮擋住了直接的環境光,但實際上遮擋還意味着這些幾何部分上的出射光會反射給該點,這就形成了該點間接的環境光照。
基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

增加 1 次互反射的渲染方程(疊代):

\(L^n_x(r) := L^0_x(r)+\int_{\Omega^+} L^{n-1}_{x'}(\mathbf{\omega})\cdot \rho(r,\mathbf{\omega}) \cdot (1-V(\mathbf{\omega})) \cdot \max (0, n\cdot \mathbf{\omega}) \mathrm{d} \mathbf{\omega}\)

\(L^n_x\) 意味着在某個點 \(x\) 的 radiance,而 \(x'\) 則是從 \(x\) 朝 \(\omega\) 方向進行 raycast 而得到相交的其它點,而 \(n\) 則代表了疊代了多少次。

\(L^n_x := L^0_x + \rho\int_{\Omega^+} L^{n-1}_{x'} \cdot (1-V(\mathbf{\omega})) \cdot \max (0, n\cdot \mathbf{\omega}) \mathrm{d} \mathbf{\omega}\)

将上述式子左右兩邊同時分離出 \(\vec{l}\) (即對預計算出來的 lighting SH 系數不做改變 ),則意味着我們實作 Interreflection 的效果隻需要在所有頂點 \(x\) 的 transfer 系數向量做以下疊代:

\((T^{n}_x)_i := (T^0_x)_i + \rho \int_{\Omega^{+}}(T^{n-1}_{x'})_i \cdot (1-V(\mathbf{\omega})) \cdot \max (0, n\cdot \mathbf{\omega}) \mathrm{d} \mathbf{\omega}\)

PRT 的一個問題是如果 lighting 部分是預計算的,那就隻适用于靜态環境光下的靜态物體渲染;環境光或者物體隻要有變化,PRT 就不得不進行重新預計算;但得益于 SH 的旋轉不變性,我們至少可以讓 SH Lighting 适用于動态旋轉的情形而不必重新預計算。

環境光旋轉往往用來實作場景的晝夜輪轉效果,物體旋轉就比較常見了。順便注:環境光旋轉和物體旋轉在 PRT 渲染中是等價的(隻是說看相對于哪個東西來看待旋轉而已)

現在給定旋轉 \(R\) ,然後有SH投影函數 \(P\)(輸入一個球面向量,輸出第 \(l\) 層band的 SH 系數向量組)。假設我們有 \(2l+1\) 個任意的球面向量,我們需要想辦法求出能等價于旋轉 \(n_i\) 的矩陣 \(M\) 來旋轉 SH投影函數 \(P\) :

\(M P\left(n_{i}\right)=P\left(R\left(n_{i}\right)\right), i \in[-l, l]\)

整理得:

\(M\left[P\left(n_{-l}\right), \ldots, P\left(n_{l}\right)\right]=\left[P\left(R\left(n_{-l}\right)\right), \ldots, P\left(R\left(n_{l}\right)\right)\right]\)

記 \(A = [P_{(n−l)}, ..., P (n_{l})]\) ,如果矩陣 \(A\) 是可逆的,則:

\(M=\left[P\left(R\left(n_{-l}\right)\right), \ldots, P\left(R\left(n_{l}\right)\right)\right] A^{-1}\)

這樣,無論 \(R\) 怎麼變化,我們都可以即時根據 \(R\) 求出 \(M\) ,然後把最新的 \(M\) 應用到所有預計算好的 \(P(\omega)\) 上(即預計算好的SH系數上),而不必重新預計算 \(P(R(\omega))\) 。

SH 的快速旋轉實作:

對于第 \(l\) 層 band 需要做如下處理:

選取共 \(2l + 1\) 個 機關向量 \(n_i\),這些向量 \(n_i\) 投影在該層 band 上的基函數就能得到系數 \(P (n_i)\)。共 \(2l + 1\) 個 \(2l+1\) 維向量 \(P (n_i)\) 構成了矩陣 \(A\),并求出 \(A^{−1}\)

如何選取機關向量:要保證投影後構成的 \(A\) 矩陣可逆。

給定旋轉 \(R\) ,對所有 \(n_i\) 依次做旋轉 \(R(n_i)\) ,這些旋轉後的機關向量同樣投影在該層 band 上的基函數就能得到系數 \(P(R(n_i))\)。 共 \(2l + 1\) 個 \(2l + 1\) 維向量 \(P(R(n_i))\) 構成了矩陣 \(S\)

求出該層 band 上球諧函數的旋轉矩陣 \(M = SA^{−1}\)

用 \(M\) 乘以該層 band 上的 SH 系數向量組就可以得到旋轉後的 SH 系數向量組。

\(l=0\) 時隻有1個系數,故不需要處理;\(l=1\) 時需要處理3個系數,其中的 \(A、S、M\) 将會是 3X3矩陣;\(l=2\) 時需要處理5個系數,其中的 \(A、S、M\) 将會是 5X5矩陣......

最後,将每一層 band 的結果重新拼接起來即可得到完整的旋轉後的 SH 系數結果。

這樣我們對 lighting 的 SH 系數做 Rotation,就可以實作支援環境光旋轉或物體旋轉的實時 SH Lighting。

但是注意,不應當對 transfer 的 SH 系數做 Rotation,因為一個物體的 transfer function 隻考慮自身的幾何遮蔽(自身與自身的遮蔽關系),而非像物體與環境光那樣存在相對關系。

SH Rotation 效果圖:

光照探針(Light Probe) 是一類場景 GI 方案。它在場景裡設定若幹個Probe點(可以了解成向四面八方探測光照的點),為每個 Probe 預計算出環境光資訊後,在運作時通過物體周圍的 Probe 資訊來插值來得到物體此時受到的環境光。

實際上,PRT也算是一種基于Probe的GI方案:PRT物體上的每個頂點都是一個Probe,它所探測的環境光照資訊将預計算為 SH 系數,然後 shading point 可以根據三角形的頂點對 SH 系數做重心插值進而得到該點的 SH 系數(即代表了環境光)。隻是 PRT 的每個三角形頂點都是一個Probe,這些Probe綜合起來完成了單個物體的 GI 效果;而一般的 Light Probe 方案是在場景中每隔一段空間放置一個Probe,這些Probe綜合起來提供了場景中所有物體的 GI 效果。

不過 Light Probe 經常會遇到錯誤的 Bleeding 問題:受到幾何上不應該存在光照關系的 Probe 影響,常見于牆壁遮擋的内外側。

例如,下面的一個 Probe 生成在室内:

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

結果由于 Light Probe 方法沒有考慮遮擋,直接且錯誤地進行了對相鄰的 Probe 插值,進而室外本該明亮的一側變暗,室内本該黑暗的一側發生漏光:

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

是以一個好的 Probe 放置方案可以盡量減少這種 Bleeding 問題。

Unity 允許在場景中放置自定義位置的 Probe ,而且這些 Probe 将相連成一個個四面體。

為了增加這種GI方案的真實感和避免過多的Probe帶來的存儲開銷,還應當把 Probe 在光照發生明顯變化的地方(如明暗交接處)放密集些,而在光照不怎麼變化的地方可以稀疏地放置。

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

每個 Probe 從自身往四面八方看到的環境光資訊烘焙成3階SH系數(SH Lighting方法)并記錄之

Unity 曾經提供了一種動态實時GI方案,隻不過現在被廢棄了:它的 Probe 是運作時采樣并實時計算出最新的2階 SH 系數。

将這些 Probe 進行三角化(将空間切分成四面體),切分的算法是使用 Delaunay Triangulation 完美三角剖分。

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

在渲染物體的 shading point 時,通過四面體插值的方法取周圍4個 Probe 的結果的權重平均作為該點受到的 lighting

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)
四面體插值:假設 \(a,b,c,d\) 分别為四個 Probe 的權重,則 \(\left[\begin{array}{l}a \\ b \\ c\end{array}\right]=\left[\begin{array}{lll}\vec{P}_{0}-\vec{P}_{3} & \vec{P}_{1}-\vec{P}_{3} & \overrightarrow{P_{2}}-\vec{P}_{3}\end{array}\right]^{-1}\left[\vec{P}-\overrightarrow{P_{3}}\right]\) \(d=1-a-b-c\)

渲染效果:

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

Unity Tetrahedral Tessellations 的弊端:

運作時,查找所處四面體的CPU運算量較高:四面體的分布并不是均勻的,GPU很難做到查找,是以Unity需要通過CPU把每個使用GI的物體所處的四面體找到并将查找結果傳遞給GPU,這就帶來了性能瓶頸。

間接光緩存(Indirect Light Cache):與 Unity Light Probe 方案基本一樣,Probe 也是采用烘焙 SH 系數和插值的方案,隻是放置 Probe 的方式有所不同。ILC 基本上是在靜态物體表面法線向上均勻放置 Probe ,這是基于假設受環境光影響最大的地方都是在靠近靜态物體的地方。

當然實際上 ILC 還包含兩種 Probe 放置方式:通過手動放置 Lightmass Importance Volume(重要光照範圍) 來限制烘焙光照采樣範圍,或 Lightmass Character Indirect Detail Volume,來增加一段均勻放置 Probe 的區域。

ILC 通過 CPU 尋找物體周圍的 Probe:所有的 Probe 的資料将儲存到八叉樹中以友善物體找到周圍的 Probe。

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

體積光照貼圖(Volumetric Light Map,VLM):還是采用烘焙 SH 系數和插值的方案,也還是放置 Probe 的方式有所不同。VLM 使用網格(Grid)采樣點儲存 Probe 資料,在靜态物體表面附近,會對網格進一步細分。

VLM 将通過 GPU 來尋找物體周圍的 Probe :所有 Probe 的資料将烘焙至貼圖中,不同細分層度的網格将使用 level 不同的貼圖,這樣可以友善地在 GPU 中進行逐像素的三線性插值。

VLM 與 ILC 比較:

VLM 比 ILC 的 Probe 要多更多,進而 VLM 的 GI 效果更佳,但要存儲的資料更多

VLM 的存儲結構決定了可以通過 GPU 算法來尋找 Probe,這比傳統的 CPU 算法性能更加客觀(即是 VLM Probe 數量要多得多)

VLM 更适合将 Probe 應用到體積霧效果中,這是因為 ILC 往往不在幾乎沒什麼物體的空間放置 Probe

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)
UE 4.18 以後使用 VLM 代替了 ILC 方法作為 UE4 預設的 Light Probe 方案。

UE4 ILC & VLM 效果圖:

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)
有關 Light Map 的初步介紹可見 實時渲染基礎(4)紋理-光照貼圖

在 UE4 和 Unity 中,靜态物體的全局光照效果都采用了烘焙 Light Map 的方法。

Light Map 方法實際上就是把環境光被分成了靜态部分和動态部分,而 Light Map 記錄的正是受靜态部分環境光後着色結果,是以參與烘焙的物體(位置、形狀、材質)和光照都應當是靜态的,這樣的局限性很大。

為了讓靜态物體也能受到動态部分環境光的影響,将 Light Map 中對應位置的着色資訊解析出來,并與動态光照部分計算出來的着色進行混合。

這裡對Unity、UE4所實作的 Light Map 做一個更深入分析:

Light Map 一般記錄的是受靜态部分環境光後的着色結果,着色方法不限于Ray Tracing、輻射度、Shadow、環境光遮蔽(Ambient Occlusion,AO)等算法。

比較有意思的是,對于顔色存儲的方案,Unity采用了直覺的線性顔色存儲方式,而UE4則采用了非線性映射的顔色存儲方式:暗色區域的顔色可以有更多細節(更高精度)而明色區域的顔色則更少細節(更低精度)。這是因為在實際畫面中,我們更容易注意到暗色區域的細節而不容易注意到明亮區域的細節。

Light Map 也可以直接混合寫入正常紋理,這樣物體着色隻需要采樣一個紋理,但會極度影響紋理的重用(有别的物體使用了相同的紋理,但是光照結果卻是截然不同的;有些着色算法依賴原生紋理而非混合紋理的資料)

Light Map 對于帶 Normal Map 的物體,可能無法得到正确的結果(Normal Map沒有起作用)。這是因為光照烘焙系統隻使用了物體的頂點資料(而沒有使用 Normal Map)。而 Unity 和 UE4 的 Light Map 在啟動了高品質選項後會多額外一張紋理(稱為 Directional Light Map )來存儲入射光的主要方向(世界坐标空間):在對某個 shading point 着色時,通過解析出來的入射光主要方向與 shading point 的 normal(Normal Map 解壓出來的,且需變換成世界坐标空間下的)進行點乘,便可以得到對應 Light Map 顔色的貢獻權重。

Lighting Scenarios :一個物體使用多套 Light Map,常用于模拟天氣系統以及一天中不同時段的光照。實際上,就是烘焙幾個關鍵時間點的 Light Map, 根據時間進行線性插值。

UE4 的 Lighting Scenarios 效果:

基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)
基于預計算的實時環境光照(Real-time Environment Lighting Based On Precomputation)

個人歸納:

IBL 是半動态的 GI 方法(環境光可動可靜、動态物體、材質僅粗糙度參數可變),常用于 Specular 物體的渲染

PRT 是半動态的 GI 方法(環境光可動可靜、即使靜态環境光還可支援旋轉、物體不可形變、靜态材質), 常用于 Diffuse/Glossy 物體的渲染

Light Probe 是半動态的 GI 方法(靜态環境光、動态物體), 實時給場景中任何物體提供合适的靜态環境光資訊

Light Map 是全靜态的 GI 方法(靜态環境光、靜态物體),預先給場景中靜态物體提供受環境光靜态部分影響後的着色結果

[1] GAMES202-高品質實時渲染-闫令琪

[2] 《Real-Time Rendering 4th Edition》

[3] Precomputed Radiance Transfer for Real-Time Rendering in Dynamic, Low-Frequency Lighting Environments

[4] Stupid Spherical Harmonics (SH) Tricks

[5] Probe-Based Global Illumination | 知乎

[6] 遊戲中的全局光照(四) 漫反射GI

[7] Light probe interpolation using tetrahedral tessellations | GDC2012

[8] 虛幻引擎學習之路:渲染子產品之全局光照明

[9] UE4 Lightmap的解碼

作者:KillerAery

出處:http://www.cnblogs.com/KillerAery/

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。

繼續閱讀