介紹

本文介紹一種簡單的為環境照明計算球諧可見性的GPU演算法,可見性在頂點或紋素上進行計算並用來計算動態陰影。

技術方案

使用HDR環境貼圖來照明可以提供很高的視覺質量但它昂貴的預計算操作阻礙了它在動態環境的應用。而為了支援動態場景必然要犧牲環境貼圖的清晰度,但可以使用陰影來進行折衷。本文使用的演算法大致如下:

首先決定環境中投射最強烈陰影的方向,這裡對環境貼圖使用重要性取樣

為了找到遮擋物,接下來為取樣方向渲染正交的陰影貼圖,但每幀為每畫素評估陰影貼圖計算代價很大,所以將逐張陰影貼圖來定義遮擋物改為逐物體定義過濾後的可見性貼圖

然後使用可見性貼圖來渲染有陰影的影象,對於漫反射使用逐畫素的點乘來模擬,對於鏡面反射則使用基於Colbert的重要性取樣方法並新增陰影,陰影由可見性貼圖對樣本的貢獻進行衰減得到。

環境貼圖重要性取樣

重要性取樣用來生成建立陰影貼圖的方向,目標是在環境貼圖強度大的方向找到更多樣本,理由是環境中最明亮的部分投射最明顯的陰影。

首先計算用來取樣的光照環境的亮度貼圖。將2D座標對映為經緯度:φ=2πu, θ=π(1-v),再轉化為笛卡爾座標系的方向:x=sinθcosφ, y=sinθ sinφ, z=cosθ。並需要計算環境貼圖每個畫素的亮度:Y = 0。2126 R + 0。7152 G +0。0722 B,該亮度還要乘上sin Θ,其中Θ是畫素對應的仰角,用來補償極點附近的拉伸。

接下來需要對亮度貼圖歸一化。上一步生成的亮度貼圖屬於未歸一化的機率質量函式PMF,PMF指一系列事件發生的可能性,這裡的事件是取樣時在環境貼圖中選擇特定的畫素。歸一化需要對每個畫素的亮度值進行縮放使得總和為1,但計算代價太大所以轉而使用環境貼影象素的總和來對用於取樣的隨機數進行縮放,來達到歸一化的效果。

然後將2D取樣分為兩個1D取樣,首先使用marginal PMF即每行的亮度總和選擇某行,更亮的行更容易被選擇。再在該行中根據給定畫素亮度選擇某個畫素,如下圖所示

[ShaderX 7] 4.3 IBL的實時動態陰影

現在需要基於1D PMF來進行隨機取樣,現在有如下所示的堆疊的PMF,在0-1之間以相同的可能性取隨機數,那麼生成的隨機數更有可能對應於機率高的事件,因此會更經常取樣到更亮的方向。將堆疊的PMF稱為離散累積分佈函式CDF,對CDF的取樣可以使用二分搜尋,隨機數可以使用Hammersley序列的擬隨機數。

[ShaderX 7] 4.3 IBL的實時動態陰影

現在總結采樣步驟:

透過累計畫素亮度生成環境貼圖的每行的條件CDF

使用Hammersley序列生成元組(ξ0i, ξ1i ),元組的數量為取樣的數量

找到CDF大於ξ0i * Σ的行,其中Σ是PMF貼圖中所有畫素的和

使用ξ1i 在選擇行中選擇列得到畫素後使用公式計算取樣的方向

取樣結果如下:

[ShaderX 7] 4.3 IBL的實時動態陰影

生成可見性貼圖

為了捕獲取樣方向的可見性,在取樣方向上放置帶包圍球的正交相機來渲染陰影貼圖,但因此計算資源有限所以只能使用有限張陰影貼圖,從而需要對陰影貼圖進行插值得到任意方向的可見性資訊,這裡利用球諧的方向插值的特性來講陰影貼圖轉變為基於球諧的可見性貼圖。

可見性貼圖是和場景網格對應的球諧係數的紋理,因此場景中的每個物體都有對應的可見性貼圖,貼圖的每個紋素儲存球諧的16個係數用來近似任意方向的可見性方程。點p的可見性方程是一個將方向作為引數的球面函式,如下

[ShaderX 7] 4.3 IBL的實時動態陰影

球諧是用來近似任意球面函式的基底函式,如下所示。其中ω為方向,V為可見性方程,Yi是球諧函式。

[ShaderX 7] 4.3 IBL的實時動態陰影

首先需要根據陰影貼圖為可見性貼圖的每個紋素計算球諧係數。也就是使用陰影貼圖測試得到m個可見性樣本,然後在取樣方向上計算16個係數wi來最佳近似可見性,將這十六個係數作為一個w向量,最佳近似需要找到使下面方程結果最小化的係數向量w。(需要注意可見性方程需要乘上法線n和取樣方向ωj夾角的cosine值(即n · ωj)使其更適應漫反射表面。)

[ShaderX 7] 4.3 IBL的實時動態陰影

對其求導並把導數設定為0從而解得符合條件的w,以矩陣形式表示如下,其中Y中的一列代表一個對於m個取樣方向的球諧函式

[ShaderX 7] 4.3 IBL的實時動態陰影

[ShaderX 7] 4.3 IBL的實時動態陰影

此時則需要計算矩陣Y的Moore-Penrose偽逆矩陣Y+,令

Y=UΣV^{T}

,則

Y^+ =VΣ^+ U^T

,利用svdcmp()可以計算U, Σ, 和 V,再使用如下公式計算Σ+,從而可以計算Y+,得到Y+後和b相乘得到w

[ShaderX 7] 4.3 IBL的實時動態陰影

[ShaderX 7] 4.3 IBL的實時動態陰影

左上:前三個球諧係數以RGB形式視覺化;左下:可見性結果;右:場景

接下來需要對可見性貼圖進行過濾。球諧可以消除離散取樣造成的走樣,但無法消除陰影貼圖的低解析度造成的走樣,如下圖a所示。這裡透過在可見性貼圖中對球諧係數執行低通濾波來消除這些走樣,效果如下圖b。

[ShaderX 7] 4.3 IBL的實時動態陰影

具體做法是將可見性紋理和一個2D 9x9的高斯濾波進行卷積,其中將高斯濾波分為2個1D濾波來分別在水平和垂直進行卷積。這裡需要使用法線來衡量周圍畫素避免過濾超出邊緣。

在漫反射表面和光滑表面渲染陰影

為了渲染有陰影的漫反射表面,使用來自基於球諧的PRT的技術。將環境貼圖轉化成球諧係數向量,使得環境光照可以向球諧可見性方程一樣表示。渲染時將環境貼圖的球諧係數以著色器常量的形式傳給GPU,然後在畫素著色器中根據環境貼圖係數和可見性係數的點積來計算漫反射著色。

為了渲染環境照明下的光滑反射,這裡使用基於Colbert的過濾重要性取樣FIS技術。Colbert方法之前在GPU Gems3中已經介紹過,可見以下連結。

FIS中的著色計算包括生成和BRDF成比例的取樣方向,為每個取樣方向在環境mipmap中執行過濾的查詢,以及將取樣貢獻綜合到一起。此外為了生成陰影,這裡透過使用球諧係數重構的可見性來對取樣貢獻進行衰減。

結果如下:

[ShaderX 7] 4.3 IBL的實時動態陰影