Voxel Cone Tracing based Global Illumination

來源:互聯網
上載者:User

之前很早就看到了UE4中的基於Sparse Voxel Octree的RTGI,效果很酷,一直嘗試作些研究與實現,但苦於沒機會。前段得空,抽時間學習了一下,這裡小結一下備忘。

整個演算法主要分類幾個過程:體素化、Mipmap OCTree、Cone Tracing。

1. Voxelization

體素化整個GI演算法的基礎。這裡體素化可以採用的方法也比較多,主要有以下幾種:

  1. 直接將體素與情境進行碰撞檢測。該方法比較原始,效率也較低,雖然也可以藉助於GPU進行加速,但是在該特定場合中使用起來還是諸多不便;
  2. 基於CUDA進行體素操作,這也是使用GPU進行加速的一種方法。比如這裡的一個使用CUDA進行光柵化方法,稍作修改就可以同樣用來實現體素化;
  3. 基於GPU Rasterization的方法,使用這種方法的好處就是不需要特殊的Pipeline,很容易將它往現有的遊戲或渲染引擎中進行整合;
由於整個演算法要搞定動態情境以及動態光源,因而這裡的體素化操作也是需要即時更新的,因而就需要效率儘可能高的體素化操作演算法;而且就盡可以地與現在的引擎緊密結合,如此一來基於CUDA的其實也是不太方便。對於第三種方法,結合當前最新的DX11或OGL4.0以上的一些新屬性,可以實現基於Rasterization和DirectCompute的體素化演算法。這裡有一篇文章就是Cone
Tracing演算法的作者發表在OpenGL Insight中介紹使用OpenGL來進行光柵化的方法,值得學習。體素化的過程主要如所示:
其主要流程是:
  1. 使用與體素化細分解析度相同的正交投影視窗來渲染三維網格中的每個三角形;
  2. 對於每個三角形計算出一個投影面積最大的投影矩陣,然在在此位置上做光柵化,這樣使得光柵化效率最大化;光柵化出的每個像素對應一個該方向上的體素;
  3. 在光柵化出的每個像素中執行Shader,利用OGL imageStore或DX11的RWTexture3D方法將像素對應的體素資訊寫入到3D Texture中;
  4. 對六個投影軸方向分別進行上述操作之後得到6張3D Texture;之後對其進行合并得到最終的3D Texture,其中就包含了整個情境的完整體素化結果。
使用上述方法進行體素化之後的結果如下:
注意情境上空中的柱子,其結果並不完全正確,在中間會漏掉相應的體素。這主要是因為上述體素化方法使用了保守的判斷操作,因而可能會漏掉若干體素。對於這種情況,一個可行的解決方案是對三角形向周圍進行擴充,如下:
在擴充後的三角形基礎上再進行同樣保守的判斷操作就會得到原始被裁掉的那些體素,這樣一來體素化的效果就會提高不少。

另外,這裡簡單也說一下對於體素情境的渲染(Voxel rendering)。如果想實現上述類似於Minecraft的塊狀體素渲染效果,也有幾種可選的方案:
  • 最簡單的一個方法是直接對於每個體素產生一個6個面的Cube,然後再繪製,但是這樣產生的冗餘面就太多了,繪製效率極低;
  • 另外一個方法是表面產生(Surface Extraction):其實體素繪製時的有效表面只會產生在相鄰兩個體素的狀態是由非空 變換為 的位置上。基於些,對於情境中的體素進行遍曆,通過每個體素及其相鄰體素之間的狀態切換關係,判斷相關位置上是否有體素表面,如果有的話就將其添加表面列表中以待繪製。這可以使體素內部的表面都被省略。不過對於256x256x256的體素解析度來說,在上述情境中進行表面產生後也得到了多達658240個體素表面,數量仍然不小。
當然,這兩種方法都是在體素化之後、即時渲染之前進行一次離線的操作完成的,並不能即時進行。為了達到體素化完成後即時繪製的目的,本人嘗試使用多個基本分割面來進行體素渲染(類似於slice based) 。方法就是在每個軸向上放置解析度(比如256)個Quad,三個軸一共就需要256 * 3個Quad,或是256 * 6個三角形。當繪製體素時,所有的體素表面其實都是落在這些個基本表面上的;如此一來就只需要在Shader中判斷每個基本表面上的像素是否是屬於一個不空的體素的(需要一次由像素位置到3D
Texture的讀取),如果是的話則將當前像素作為體素表面的像素來繪製,如果不是的話是discard掉。這種方法本身沒什麼問題,效率也要比表面產生後再繪製高,可以通過較少的表面繪製來完成最終的體素渲染,不過中間遇的一個情況就是3D Texture的採樣問題:微小的採樣誤差對應的結果是像素狀態判斷的高頻fliking,最終導致全屏的閃爍,嘗試失敗。。。2. Mipmap based OCTree做過情境管理的童鞋應該會對八叉樹很瞭解,這是一種很常用且簡單的空間分割方法,可以用來進行碰撞檢測等的加速操作,實用性很強。這裡的Cone Tracing演算法也是基於一個類似的八叉樹結構上進行的,這裡的主要問題是如何快速地建立出基於體素資訊的空間八叉樹結構。在第一步完成了體素操作之後,即可以得到儲存於3D Texture中的情境離散資訊,此時其相當於儲存了八叉樹的最底層資訊,也即每個葉子上的資訊。接下來需要通過這些葉子來得到整個樹的結構,這裡使用的方法即是自底向上的OCTree建立。通常,自頂向下的方法是對當前的每個結點進行八個子結點的分割;而自底向上則是對每八個子結點進行合并來得到它們對應的父結點,這樣一直到最頂層的結點結束即可。這裡利用了Mipmap的原理來對3D
Texture進行不同層級的Mipamp的產生,也就相當於得到不同深度下的八叉樹結構,如下:
當前Mipmap圖層中每個Texel就代表了一個情境體素結點,對其進行合并後就得到了上一級(也即上一層OCTree)的更大的結點,如此進行直到頂層。這樣一來,對於一個比如含有10級Mipmap的3D Texture中得到了對應深度為10的情境分割OCTree,這個作為下一步進行Cone Tracing的基本空間資料結構。在GI場合中使用時,每個體素中需要儲存的資訊只需要RGBA就夠了。注意:這裡直接使用了3D Texture來進行OCTree的儲存,並沒有使用Sparse OCTree的儲存方法,這個實現起來需要作些改動。
3. Cone Tracing

有了情境的基本OCTree結構之後,接下來就到Cone Tracing了,這個是整個方法的核心,其主要是使用多層次的空間近似來降低傳統Irridiance計算的複雜度進而使得即時的快速計算變得可行。先來看個圖示意一下:

首先,在每個表面的每個點上,將傳統做GI計算時的半球積分空間給分割成多個獨立的Cones,用這些Cones組合得到的空間(中間會有重疊或裂隙)來近似原始的半球空間,並在其上做Irridiance的采積。

之後,對於每個獨立的Cone,又使用下述方法再進行近似:

也即是在每個Cone的內部又將其用多個密布排列的Cube來進行近似,使用Cube的方法是其會使得OCTree的Tracing變得很方便。 每個Cube大小的計算就可以根據具體Cone的屬性(比如夾角,最大長度等)來進行計算,一般來說從每個Cone內部分割出來的Cube個數不會太多.

對於每個Cube在OCTree中的Tracing,使用的方法也比較簡單:直接計算出的Cube的Size,然後根據此Size找出與其最適配的那層Mipmap,這裡的原則就是Cube的Size要儘可能地與Mipmap層中的結點Size接近。最後,直接使用此Cube的位置資訊來採樣Mipmap中的相應位置上的結點值,即可完成對此Cube的Tracing。

對Cone中的每個Cube完成Tracing之後,當前Cone方向上的Irridiance累積結果就可以認為是Cone中所有Cube採樣結果的疊加。這個看起來雖然有些不太合理,但是視覺效果上的近似已經很不錯了。此外,作者也對該近似方法進行了數學上的分析(step by step pre-integration):將每個Cube認為是Transparent屬性,然後Irridiance會在其中進行不斷的傳遞。具體可以見這論文裡邊的詳細內容。

 下面有個簡單的實驗,Tracing效果還是挺不錯的。

總體來說,基於SVO Cone Tracing的GI是一種蠻好的方法,其演算法本身跟CE中的LPV很相似,但增加了對情境的體素化加速結構的即時產生,並且在效率與效果中達到了較為不錯的平衡,與現有引擎的整合難度應該不是太大,未來應該還是有很好的發展趨勢。

後記. Pure run-time methods VS Hybrid methods

寫到了GI,這裡順便也對自己之前所瞭解的GI情況作一簡單總結。目前,主流遊戲引擎中對即時GI的支援逐漸層得普遍,總體來看,主要使用的即時GI演算法應該大體分為這兩類:

  • 純即時方法:這類方法的特點是全部GI相關的計算都是在即時更新時完成(這裡主要是指核心的計算),其面臨的最大挑戰是效率與效果的兼顧。該類方法中比較典型的有:Reflective Shadow map(以及各種改進版本)、Light Propgation Volume(CE中使用的方法),SVO GI(UE4中使用的方法);
  • 預先處理&即時結合方法:這類方法的特點是將Realtime Compute與情境預先處理進行結合,在預先處理階段中產生一些額外的資訊來加速即時GI更新時的計算,這樣的話可以將部分即時更新計算提前,進而減少動態更新部分的壓力。該類方法中比較典型的主要是:Enlighten(Frostbite中使用的方法);
對上述兩大類方法,主要作如下的對比:
  1. 效果和效率:Hybrid類的方法在GI的效率和品質上都更勝一籌(Enlighten的效果與效率比SVO與LPV都要好),畢竟其將一些複雜的計算都移動到了預先處理階段,然後在即時更新中直接使用就可以。
  2. 易用性:這個主要是從製作人員角度考慮,Hybrid方法需要前期美術資源製作時的支出一些人力成本用來協助預先處理過程,該部分的工作量也會視情況而變;而純即時的就不需要該部分工作。
  3. 使用代價:效果較好的Enlighten意味著不菲的使用授權;而上述純即時的GI演算法則都是免費使用(當然,開發整合也需要少量成本)。

其實,RTGI對於一款遊戲或引擎的意義也要視情況而定,對某些引擎或項目而言這些東西可能毫無意義;但對其它的來說,這些可能就是眾多亮點之一,需要辯證地看待吧。

 References[1]
GIgaVoxels: A Voxel-based Rendering Pipeline for Efficient Exploration of Large and Defailed Scenes
[2]
Octree based Sparse voxelization using the GPU hardware rasterizer[3]
Interactive Indirect Illumination using Voxel Cone Tracing[4] http://blog.csdn.net/ccanan/article/details/7882169

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.