粉絲團文章連結:
https://www.facebook.com/life.is.kuso.game/posts/278181642573356
這個做法是看完GPU Pro7這本書的心得,在此要先感謝作者Anton Kai
Michels跟Peter Sikachev。
這次要介紹的是古墓奇兵:崛起(Rise of the Tomb Raider)中的雪地
做法,有玩這遊戲的人可能會注意到,雪景做得還不錯。這系列的文章
將分成上、中、下三篇,上篇會先講解如何做出腳踏下的深度,中篇則
會介紹周圍隆起的雪堆計算方式,來讓場景顯得更真實,下篇則會說明
雪地的腳印痕跡如何隨時間恢復。
用於古墓奇兵的雪地做法,是一種被稱為延遲變形(deferred deformation)
的新技術,地形變形在實時渲染中,一直是個已知的未解決問題,以往
的解法呈現的細節不夠讓人覺得真實。而延遲變形則提供了一個有擴充
性、低記憶體、又可精細到公分等級的解決方案,並且在任何地形都能
呈現任意數量的變形,其細節不只能呈現走過的凹陷,甚至能呈現邊緣
被影響所造成的隆起,以及根據條件決定是否慢慢回填凹陷。
提到雪景, 蝙蝠俠:阿卡漢始源(Batman: Arkham Origins)的效果其
實很不錯(註一),不過其雪景只發生在平面的地形,在此就不詳談,由
於GPU在DirectX 11中的硬體支援,這種技術基本上利用渲染流程中去
處理,因此能做出非常準確的變形,可是卻無法用在任意地形上,且只
會有凹陷而不會有邊緣的隆起。
(https://cdn-images-1.medium.com/max/1200/1*w539g2-wHVmSLvc-hd4K2Q.png)
在解說技術之前,需要先說明會用到的一些名詞,列舉如下:
雪地高度(snow height):
要變形的雪地的垂直座標(通常為vertex.z)
變形點(deformation points):
會造成變形的物件的3D座標位置
腳高度(foot height):
變形點的垂直座標(通常為point.z)
拖曳凹陷(trail depression):
拖曳痕跡的一部分,為雪地高度下踩下的部分
拖曳隆起(trail elevation):
沿著拖曳痕跡產生的小凸起,當推開雪時應該自然產生的效果
變形高度映射(deformation heightmap):
一張用來儲存變形的貼圖,32bit,1024*1024
凹陷深度(depression depth):
(雪地高地-腳高度)的絕對值
變形著色器(deformation shader):
將變形輸出到變形高度映射的著色器
填充著色器(fill shader):
用來計算在暴風雪中回填拖曳痕跡的著色器
雪地著色器(snow shader):
用於變形的雪的材質的著色器
想像一下原本的地形網格上,有一層雪的網格(mesh),然後有不定數
量的動態物件造成雪地變形,而要渲染雪的變形時,我們必須先得知
動態物件、雪跟地形之間的高度關係,所以必須先利用從正上方俯視
的方式,將這兩層網格分別渲染到兩個高度映射來得知高度,然後再
將動態物件渲染到一個變形高度映射,取得其在雪跟地形之間的逼近
值(clamp),當渲染雪的變形的時後,再從做好的變形高度映射取樣,
來取代雪原本的頂點與法線(normal)。
(作法的思路)
(https://cdn-images-1.medium.com/max/1200/1*tal2N7TYFrmzW-X6r7XonQ.png)
而這個簡單的做法有兩個缺點,一是必須先從鳥勘視角渲染一次來做
出兩張高度映射,二是每個動態物件需要一個繪圖指令(draw call),
解決的方式就是接下來要介紹的延遲變形。
延遲變形的思路,第一個就是不用先做一次雪網格的高度映射,而是
在雪的渲染流程中,去取用雪網格的頂點位置即是其高度,第二個是
變形的逼近值在被取樣時才計算,而非渲染時。所以精確的變形計算
是在渲染雪的時後,才稱之為延遲變形。重點是要將雪的高度從雪的
頂點著色器(vertex shader),傳到雪的像素著色器(pixel shader),
以計算每個像素的法線。其演算法如下:
(延遲變形演算法概要)
(https://cdn-images-1.medium.com/max/1200/1*M_xzTuHTQsm_BikvLawAqw.png)
延遲變形演算法中的一個重點就是:把變形當成一個二次曲線(quadratic
curve)。藉由近似動態物件形狀的點,去計算其變形高度。算法如下:
變形高度 = 點高度+ (到點的距離)平方 × 美術縮放值
這些變形點會被放到一個全域緩衝(buffer),而每個變形著色器則會
被分配到變形點周圍32像素平方的區域(1.64 m平方),然後利用原子
級同步最小值(atomic minimum)計算,輸出受影響的像素的變形高度
。由於可能有不同的動態物件去影響到同一個高度映射中的像素,所
以原子級同步取最小值是必須的。因為在DirectX 11中能夠做這種運
算的只有unordered access view(UAV),其形態是32-bit integer,
因此變形高度映射的型態也必須是R32_UINT。
註一:如果對蝙蝠俠的做法有興趣,可以參考GDC的資料
(http://www.gdcvault.com/play/1020177/Deformable-Snow-Rendering-in-Batman)