Shadow Caster Culling

最近讀到去年I3D上面的一篇論文,Shadow Caster Culling for Efficient Shadow Mapping,覺得不錯,這裏簡單總結一下。對於算法的基本原理還是比較容易理解的,可以見下圖所示。從圖中可以看出對於當前某特定幀下的Camera來說,其可見的幾何體元是整個場景的一個有限子集,而需要做陰影計算的也必然是這些可見幾何體元集的一個子集,因而在生成Shadow Map時就可以只將那些對於當前需要計算SM的Shadow receiver有所影響的Shadow Caster投影繪製到SM中去(比如在下圖所示中就可以只繪製C到SM中去,而C0,C1...Cn都是可省去的)。

這個算法的核心就是計算出這樣一個優化的Caster集合來避免無謂的Caster繪製。算法的基本流程如下所列:

  1. 首先需要確定Shadow Receiver的集合
  2. 利用Receiver來創建Caster的Mask以供下一步Caster向SM中的渲染時使用
  3. 利用Caster Mask並結合Culling操作來進行高效的Caster渲染
  4. 常規的Shadow Mapping操作

其中最關鍵的就是第二步,即如何使用Receiver集合來創建Caster的Mask以供下一步陰影投射體的渲染時使用。這裏的Mask其實也就是一張包含需要繪製的Caster的投影的Stencil Buffer或貼圖,其使用原理與Occlusion Culling是一樣的。這裏的Receiver集合是對場景在當前Camera下進行裁剪的結果集,這也就要求引擎的裁剪系統有這麼樣的一個集合提取功能。關於Caster mask的生成文中給出了四種方法:

Bounding Volume Mask

這是一種最直接同時也最爲保守的方法,直接使用幾何體元的包圍體來投影生成Mask。這裏包圍體的類型也就可以有多種選擇,比如AABB,Sphere,OBB等,當然不同類型的包圍盒對最終的精度也是會產生不同影響的。

Geometry Mask

這種方法在包圍體的基本上進一步提高了精度,直接使用幾何體元本身進行繪製來生成Mask。其相對於BVM來說精度提高了很多,但隨之而來的問題就是渲染的效率,但是其也有另外的一個好處就是對於那些既是Caster又同時是Receiver的體元來說在生成Mask的同時就可以更新寫入depth到SM中去,省去了下一步SM生成時的一些操作。

Geometry & Bounding Volume Mask

鑑於BVM與GM兩者的優缺點,也可以將兩者進行結合進行使用。這種方法需要將Reciver集合進行分類並從中提取出Receiver和Caster的交集,對於這些幾何體使用GM的方法來操作,這樣就避免了下一步SM中的depth寫入;而對於其它的幾何體則直接使用BVM的方法進行操作。這裏對於需要使用Geometry Mask進行繪製的體元的判斷採用了Temporal coherence的方法來實現,如果一個Receiver在上一幀的SM中可見那麼在當前幀中將其視爲既是Receiver&Caster,使用GM的方法來更新Mask。

Fragment Mask

在上述三種方法是最爲精確的應該是Geometry Mask的方法了,但是其在某些情況下仍然會得到過於保守的Mask結果,這樣就對後續的SM生成並沒有多少效率上的提升,比較極端且典型的情況如下圖所示:

圖中很大的曲面可能是場景中的一個較大的地形(整個地形屬於一個單一的幾何體元,也即上述的一個Geometry單位),在當前的Camera下,其可能只有很少一部分可見。但是這種情況下不管是BVM還是GM都需要將其完全繪製到Mask 中去,而由於其本身很大,所以可能直接將整個Mask填滿,如此一來所有的Caster就都需要繪製,沒有起到Caster culling的作用。此時更加精確的方法是提取出其中的Camera可見部分並將其寫入到Mask中去。這裏又有兩種方法:

  1. 將較大的物體進行細分然後處理成多個獨立的、較小的幾何體元來進行操作。這樣雖然不能達到完全精確,但卻至少可以減少寫入到Mask中的無用區域的範圍以便提高下一步Caster culling的裁剪力度。
  2. 使用逐Pixel比較的操作來精確提取可見部分,這其實也相當於提前進行了一次Quasi Shadow Mapping的操作。比如對於上圖中幾何體元中的像素A,需要判斷其是否是Camera中的Receiver點,這可能就需要記錄一些當前Camera下的幾何體元投影信息(如果有G-Buffer就可以直接使用),然後在Light Space中投影A到Camera space下並做一系列的判斷得到結果。如果其是Receiver則將其更新到Mask中,若不是則丟棄之。如此一來就可以計算了精確的Mask。

上述幾種方法中,最後一種方法雖然精度高但是操作起來較爲複雜,而且對引擎的改動影響較大,最後得到的結果可能會得不償失。個人覺得還是第三種方法比較實用些,如果現有的引擎中有比較完善的Culling系統的話那麼其應用起來不是太複雜,而且性能應該有不錯的提升。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章