Cascaded Shadow Map(CSM)中的一些問題

Cascaded Shadow Map(CSM)是目前引擎中主流的陰影技術,效率與效果均不錯。它與傳統的單張Shadow Map的區別主要在於將視錐體進行了層次的分解,每一層單獨計算相關的SM,這樣在渲染大場景的陰影就可以避免傳統的SM的各種缺點。典型的CSM原理基本上如下圖所示:

雖然看起來原理簡單,但是在實際中想實現一個健壯的CSM並不容易,涉到各種問題,其中一些是這種方法本身就固有的,需要使用多種手段來解決或規避。

1. 計算緊密的投影矩陣

爲了提高SM的有效利用率(也即是要在生成的SM中儘量減少無關區域的面積),需要儘量減小生成SM時所使用的投影矩陣,這樣就需要計算出在當前Cascade下所對應的Frustum的較爲緊密的投影矩陣。這一般是在光源空間下計算出視錐體所對應的AABB包圍盒:

不過這樣直接使用AABB會帶來另外一個問題,由於Camera的屬性會實時改變,因而其對應的Frustum的屬性也會不斷改變,而AABB對Frustum的變化又較爲敏感,這樣就可能出現前後兩幀中Frustum所對應的AABB變化巨大,進而導致生成的SM的有效分辨率(是指對於某一固定物體來說的其投影到SM中後所佔用的pixel的數量,SM的大小並不變化)可能在連續兩幀中出現突變,這樣就會出現陰影的抖動(Flickering)的問題。關於這個問題有論文(Stable Cascaded Shadow Maps)提出了使用Sphere來代替AABB的解決方法,因Sphere對Frustum變化的敏感性相對較低,這樣一定程度上會解決抖動的問題。更好的解決方法是在Shader X7中的Practical Cascaded Shadow Maps中提到的漸進式變換Frustum的方法,而且也能同時在一定程度上解決Rasterization所帶來的抖動問題。

2. 計算優化的遠近裁剪平面

由於Shadow Map在使用時對Z值的精度較爲敏感,因而也就需要在生成SM時儘可能提高有效Z值的精度,這就引出了另外一個問題:那就是在生成SM時使用較爲優化的遠近平面。這裏的首要原則是使用保守的方法來儘可能得到相對優化的的遠近平面,太過於激進的方法容易過多地裁掉物體進而造成陰影漏洞。不能簡單使用光源視錐體所對應的AABB來計算遠近平面,這樣當場景過大時會使用漏掉近平面以內的一些物體。更爲合理的方法是使用兩端擴展的光線視錐體來與場景求交計算出合理的遠近平面。

3. Cascade間的冗餘物體剔除

一般來說需要將使用CSM時需要將View Frustum分割爲若干個Cascades,而且大多數情況下光源的方向與View的方向並不垂直,這樣一來就會在渲染每個SM時可能會出現Light所對應的視錐相互交疊的情形,這樣就導致了重疊部分的幾何體元被重複繪製,如下圖所示:

這種情況下可以選擇對兩者重疊的部分進行剔除,以便減少需要繪製的幾何體元的數量來提高SM的生成速度。但是這裏要注意:如果使用帶有剔除的SM生成方法的話則需要在SM的查找時使用Map-based cascade selection的方法來選擇最爲合適的SM,而不能使用基於Split索引的方法直接定位當前Pixel到其所在的SM上,否則會出現陰影的漏洞。另外,還需要對每個層級上的光源視錐的遠平面進行調整以便其可以包含到下一層級中的一些物體,否則就會出現一些Pixel定位到上一層級的SM 上,但其中並沒有生成實際包含在下一層級的視錐體中的物體,這樣同樣會漏掉一些陰影。

關於CSM,與D3D SDK中的示例相結合的兩篇文章很不錯:Cascaded Shadow Maps,Common Techniques to Imporve Shadow Depth Maps;另外,還有Shader X6中的Stable Cascade Shadow Map以及X7中的Practical Cascade Shadow Map。最後一篇論文中總結了CSM多個方面的優化問題(比如Shadow Map的Pack等),很不錯。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章