在剛剛結束的SIGGRAPH 2012上,Cyril Crassin提出的Sparse Voxel Octree(SVO)極其熱門,幾乎每個涉及到real time rendering的course和talk都免不了提及SVO。加上UE4將會采用SVO、idTech6早就說了將會采用SVO,更是起到了推波助瀾的作用。那么SVO是什么,它能解決什么樣的問題呢?
SVO簡介
Voxelization
傳統的mesh都表示成以三角形和四邊形為單位的圖元。而在SVO里,圖元是更為簡單和離散的voxel。每個voxel有其中心位置、大小等信息,但不需要考慮相互之間的拓撲關系。各種求交計算也變得簡單了。從mesh轉成voxel表達的過程就稱為voxelization。
Voxelization的方法也是逐步發展過來的。從基於CPU的方法,到NVIDIA基於一層一層渲染的方法,在SIGGRAPH Asia 2010上,Michael Schwarz和 Hans-Peter Seidel的paper “Fast Parallel Surface and Solid Voxelization on GPUs”可以在一個pass內直接把一個mesh分解成voxel。經過改進后,分解一個Stanford dragon的速度在5ms之內,相當高效。
Sparse Voxel Octree
Voxel的表達也有它的弱點,主要是存儲和訪問的不方便。如果把整個場景不管是否有voxel占用的地方都密集存儲,那么所需要的空間是驚人的。比如一個512x512x512分辨率的場景,一共有128M個voxel,如果每個voxel只有32字節的屬性,場景也輕松突破4GB。直接存在顯存里是不現實的。所以這里需要引入sparse voxel octree。通過把voxlization后的結果存放在octree的節點上,可以略過很多場景中的空區域,空間消耗可以減少到200MB-1GB。同時,因為有了層次結構,訪問起來只需要遍歷某個分支,速度也能提高。
通過在GPU上實現了全套octree維護的操作,octree可以不需要CPU的幫助,完全在GPU上添刪節點。用這種方法,初次建立一個場景的octree需要70ms,之后每次更新只需要4-5ms。
Cone tracing
在准備好了octree之后,渲染場景就需要用到cone tracing。ray tracing是對每一個像素發射一個ray,達到表面后根據BRDF反射和折射出新的ray。cone tracing與此類似,只是把ray換成了圓錐。因為有了SVO的數據結構,可以把irradiance先cache在octree里,view pass只要gather就可以了。
能解決的問題
有了SVO + cone tracing之后,很多長期以來一直很困難的實時渲染問題可以直接得到解決。如soft shadow、area light、multiple lights、multiple bounces global illumination、glossy reflection、refraction、AO等效果,就不再需要用各種不同的方法進行hack,只要進行一次tracing就全部搞定。
另外,通過對SVO的一些prefiltering,還可以完成電影級的depth of field、LOD和anti aliasing。甚至,和以往的技術不同的是,在SVO的框架中,模糊表示只要和樹的較粗層次節點求交,而忽略礁溪層次的節點,所以,這就意味着越模糊越快!對於一些體效果,比如煙霧和雲,也能通過修改cone tracing來實現。
其他一些有趣的應用包括:把signed distance field存入SVO,就可以進行procedural content creating和處理可破壞場景;用SVO做bake light map的工具;collision detection也可以容易地放入SVO框架。
總的來說,很少有一個技術能用同樣的框架同時解決這么多個領域的這么多問題。從這方面看,SVO確實很有效。
挑戰
當然,SVO也不是萬能的,在目前的軟硬件條件下仍有一些限制。下面看看SVO面臨的一些挑戰。
速度
對於實時渲染來說,速度提升是個永恆的主題。雖然SVO + cone tracing的速度在demo中已經能達到70fps,但對於游戲這樣的大系統來說,還是遠遠不夠的。這也是為什么UE4和idTech6都定位於未來硬件的原因之一。在這里,常見的優化是改用混合流水線:傳統方法渲染direct lighting(Forward和Deferred都可以),SVO負責indirect lighting。在indirect lighting本身,UE4也用了和KlayGE 4一樣的multiresolution的方法,能有2-3倍的提速。
空間占用
要把超大場景表示成SVO,空間的占用仍會是巨大的。好在SVO很適合streaming,可以隨着視角等因素動態載入需要的節點,類似於virtual texturing。idTech6所描述的方法類似於此。
動態物體
無動態物體不成游戲。如果把所有物體存在一起,如果有的物體需要每幀變化,就意味着需要把整個場景重新voxelization、重新建樹,開銷很大。在這里UE4的改進方法很直接,把動態物體和靜態物體分別放在兩個SVO上,靜態的只建立一次,動態的在變化后voxelization並更新樹的部分節點。
對於deformation型的動態物體,可以用shell texture的方式,把SVO建立在物體表面。每幀只要根據deform過的物體來平移/旋轉/放縮SVO,而SVO的內容本身保持不變。
KDTree?
對於tracing來說,KDTree在很多時候比Octree更平衡,但在GPU上建KDTree則較為復雜。所以不是沒有可能用KDTree取代Octree進行數據存儲和跟蹤,這就成了SVKD。