【UnrealEngine4】距離場的使用技巧與應用
原來想開一個專欄的
後來還沒搞懂怎麼開
就先寫下這篇文章
文章或者專欄都會分享一下我在虛幻四中的製作經驗,以藍圖和材質為主,講述如何在圖形學的思想中,不使用c++,不改動usf的情況下,藍圖和材質能做到的極限。
目前規劃的文章內容有:
一.虛幻四中的 距離場(本文)
二.材質中的偽體素(三維紋理)
1.【UnrealEngine4】材質系統中的偽三維紋理
2.【UnrealEngine4】體渲染和Tri-Planar Mapping
三.基於NS方程的流體模擬 在虛幻四中
1.用藍圖模擬pass,進行偽compute stage的運算
2.用藍圖模擬ubo,向材質系統傳輸數據
3.NS方程的解析和實際模擬
4.煙體、流體的渲染
四.metaball 在虛幻四中(本人的實例已在虛幻商城中上架)
原理與在材質中的實現
五.path tracing 在虛幻四中
1.相機內參、簡單物體變換信息的處理
2.path tracing的解析,temporal的思路
3.在材質中進行path tracing
六.透明材質造假技巧與解析
本文內容如下
一.距離場簡述
二.虛幻四中的距離場及作用
三.距離場梯度及應用
四.距離場梯度的計算
一.距離場簡述
距離場在文字渲染,矢量圖渲染中應用廣泛。本文提到的距離場為表示三維物體的距離場。關於其概念鄙人不在此多做闡述。

(圖源自 libgdx/libgdx Wiki)
二.虛幻四中的距離場及作用

在虛幻四中,如果在項目設置中開啟了自動生成模型距離場,重啟項目後將會構建網格物體的距離場。
這個過程雖然比較緩慢,但是不影響主線程工作,和編譯材質的情形類似。生成完後,場景中的所有網格物體都會被賦予一個距離場。換而言之,整個場景會被一個叫距離場的東西替代(正常渲染時不可見)
在顯示-可視化-中選擇預覽距離場
可以根據預覽的距離場質量來調整網格物體的距離場解析度。

有破漏:

無破漏:

距離場最直接的應用,在虛幻中可能是DFAO了(DFGI暫不考慮)
要開啟利用距離場進行加速的AO,可在SkyLight中找到該選項,並啟用。

使用距離場AO的好處與弊端:
AO的計算本質為被積表面上的半球積分。在屏幕空間上進行採樣積分不是均勻和完整的,因為屏幕空間中的信息不足,而且受限於採樣次數,和地毯式的搜尋(很多採樣點是無效的),屏幕空間的AO往往是近距離的(雖然現在也有新的方法可以計算遠距離AO,FFAO)。
而使用距離場進行AO的計算恰好可以避免此問題的出現,因為前面提到,距離場可以當作是一個物體的「替代」,原場景的高頻信息可以被很好地保留下來,並且是完整的,因此AO的計算可以算是全局性的,無論是近還是遠的幾何信息,一律能被積分到。
前面提到,場景是高頻信息,而距離場的表達實際上已經有信息的缺損。比如一個面片,或是一條縫隙,距離場是不能很好地表示的,因此在積分的過程中,這些高頻信息會被平均化,某些視角甚至會出現錯誤的信息,導致漏光。這個可以通過調整距離場的解析度來改善。
其次,由於距離場的採樣實際上是一個raymarch的過程。因此採樣次數對最終的精確度也會有影響。半球上的積分需要多條射線,射線的數目對最終結果的方差也會有影響。這裡會出現的問題是躁點。

(噪點和漏光等瑕疵在這張圖中很好地暴露出來了)
三.距離場梯度及應用
距離場梯度,可以算是距離場的進階內容。
首先我們需要了解梯度這個概念。梯度,拉普拉斯,旋度,在後面章節的流體中將會反覆提到,這裡不做贅述。
距離場梯度的意義。距離場是場景的「替代物」。將場景看作一個自變數為三維,因變數為一微實數的函數(可看作密度函數),其梯度的幾何意義是因變數的變化趨勢。在圖形學中其意義是對該函數按照一個閾值進行分割後得到的表面的法線(LevelSet)。但是對於一個世界坐標而言,他還有一個意義,便是周圍物體對他的遮擋程度和方向(距離場與密度函數的梯度方嚮應該是相反的)。

用距離場快速造假陰影
類似SSDO,我們可以通過對場景幾何信息的採樣來還原遮擋信息。SSDO的原理在這裡不具體闡述。由上面的幾何意義可以知道,給出一個世界坐標,我們可以根據距離場梯度來獲得這個點被遮擋的方向。(想像一個球體,表面上任何一點都會被法線以下部分遮擋,因此距離場梯度為法線相反方向)
根據距離場的梯度,和給出的光源位置(LightDirection),我們可以計算出遮蔽和陰影。

(對天光的遮蔽,每幀只對距離場進行4次採樣,不含Temporal)

(水面的天光遮蔽)

(水下Caustics的遮蔽效果,不過此處SSR效果有BUG。。。。)
由於上面的著色模型均不是虛幻四中管線默認存在的,假陰影,或者說假陰影的質感對畫面起到錦上添花的作用。
四.距離場梯度的計算
距離場梯度在虛幻四的材質系統中有現成的函數,但是在這裡並不推薦使用。
根據梯度定義
我們可以得到

即在xyz三個方向對距離場進行採樣,然後求出xyz三個方向的導數。然後進行單位化。
這裡我們可以注意到步長是可控的。而自帶的距離場卻無法控制該數值。這個步長的意義,鄙人難以用語言描述,不過考慮導數的動態過程,類比可以得到那種「逼近」的感覺,即是ε-N,ε-δ語言的三維版本,在接近極限之前不斷做割線的感覺。
在渲染中步長也不一定有個最優值,自帶的函數我沒有發現控制步長的參數,因此得到效果很有可能是不是自己想要的。
受限於採樣點的數目(七個),得到的梯度會有瑕疵。如何利用虛幻四的特性進行改進,這是一個問題。虛幻四中使用了許多Temporal的演算法,其中在材質中暴露了一個叫DitherAA的函數。該函數給出了一個根據Pattern和楨畫面進行運算的期望值為E[a],(a為輸入值)的偽隨機數。
首先對該數值進行拆解,拆解為一個三維向量:

得到一個 的向量,然後將其轉換至半徑小於等於d/2的均勻分布的全球空間。
我們得到了一個隨機的偏移向量。只需將這個偏移向量作用在採樣點中,便能在每一幀對梯度進行多次採樣,得到採樣點d/2半徑周圍點的梯度的期望值,可以輸出為最終結果。
註:這裡全球半徑是否需要均勻分布待討論。因為這裡是一個Trick,如果按照DSSDO的演算法採樣出來的梯度應該與球半徑平方成反比,但是由於每楨只能採樣一次,最後單位化會得到相同結果。如果不進行單位化處理,全屏幕中一次梯度的計算得到的結果方差將會十分大,出現的結果就會是黑白燥點的混合。因此這裡採用了折中的辦法,對最大半徑球內進行均勻採樣)
最終效果

(經過處理,將 轉換為了
方便顯示出來(不要在意開閉區間了。。。))

(水面最終效果。採用了上述的陰影演算法。光源方向與落地窗垂直,能很好地模擬天光的照明,使更有質感)
9.13:註:密度場梯度應該與距離場梯度方向是相反的,如果物體內部密度為1的話。
另本文最後求的「梯度」實際只為一個割面法線,是再運算次數少的情況下近似周圍遮蔽方向的值(這裡是Trick,前面也有提到),而且可以將三個方向改為半球上任意方向,有興趣可以推導證明。這裡只是分享了我的一個經驗,不一定準確(事實上我想寫的全部都只是我的經驗),但從實驗結果上看是可行的。而且這種方法適用範圍小,舉幾個例子,煙霧渲染,水面渲染,都可以使用這個方法造假陰影。但是如果說同樣使用距離場來製作精確陰影,可能只支持一個光源方向,沿光源方向採樣,這樣做的採樣次數會更多(而遮蔽方向卻可以重複使用),並且會在材質系統里用到custom node(除非真的需要,我都會把之前寫的custom node全部拆解,但是循環無法拆解,因為循環次數不是硬編碼的)。因此我覺得,在本文出現的場景中,水下Caustic,水面,這兩個在虛幻裡面沒有的著色模型,可以適用。
另,場景未烘培,模型沒有分過UV和光照UV,因為沒什麼時間。所見到的全局光效果是LPV產生的,(並不是說烘培之後的效果就只有那麼簡陋)。
另感謝評論區提到的DFAO殘影的問題。殘影出現的原因可能有兩個,一是TAA的原因,二是DFAO本來就會分楨採樣(temporal)的原因。打開DFAO預覽,移動視角,會發現他的確需要經過幾幀的時間才能收斂完全。要減少這種情況的發生,可以將Tint從黑色調為灰色,或者適中得範圍,來中和因為天光遮蔽計算錯誤產生的噪點。
10.29
更新一下,關於局部距離場和全局距離場的解析度的問題,使用材質中到最近表面距離會獲取全局距離場,而默認的全局解析度是有上限的。可以通過控制台命令打破此上限。
再次感謝閱讀,鄙人不才,還望各位以後繼續指出紕漏和斧正 (???ω?? ?)
本期文章就到此為止了。鄙人寫下此文僅為了分享和交流經驗,無任何商業性質與目的,望各位斧正,提出想法,謝謝。
參考文獻:Approximating Dynamic Global Illumination in Image Space, TobiasRitschel
ScreenSpace FarField Ambient Obscurance,Ville Timonen
推薦閱讀:
※WonderList論文心愿單|數字製造(一)
※用C++畫光(二):折射和色散
※Demosplash演示聚會將在卡內基梅隆大學舉辦
※在《硬影像》與羅登導演聊渲染技術


