天天看點

PCSS 簡介

本文簡單介紹一下Percentage Closer Soft Shadow的原理,由于本人對于這個東西了解很淺,是以有些想法可能是不成熟的。

談到PCSS,首先我們要介紹一下PCF(Percentage Closer Filtering),最早在1987年就被人提出的一種過慮算法,當時作者的初衷是用這種算法來改變Shadow Map的走樣問題。

PCSS 簡介
PCSS 簡介

我把SDK中的Shadow Map簡單改了一下,生成了上面兩幅圖檔。左邊的渲染圖是經過PCF處理的,而右邊是最普通的shadow map算法(注意:sdk中的shadow map也是有PCF的,不過隻有4個采樣點,效果不是很好,而右圖中是去除了PCF的效果圖)。我們把紅框中的像素放大來看,得到下面結果:

PCSS 簡介
PCSS 簡介

可以看到,經過PCF處理的Shadow邊緣會被模糊,不會有很嚴重的鋸齒。是以PCF可以用來為shadow map做抗鋸齒,而且效果還可以接受。

其實PCF的原理并不複雜,無非就是一種采樣方式而已,大緻原理如下:

PCSS 簡介

點采樣會根據uv值,找到最近的整數坐标,用該位置的texel作為采樣結果。而線性采樣則對附近的四個texel進行一定的插值運算。而在Shadow map采樣,如果利用點采樣或者線性采樣得到一個深度值,然後在于即将渲染的pixel的深度進行比較的話,最終結果是二值化的。就是說即将渲染的pixel隻有兩種情況,在陰影内部或者外部。這種二值化的特性直接導緻shadow map是沒有半影現象了,加上shadow map的分辨率有限,當其被放大的時候,經常會有精度不足的情況出現,是以會導緻出現嚴重的鋸齒。這也是shadow map算法最緻命的一個問題了。

PCF的工作方式大緻如下,把即将渲染的pixel的深度值與shadow map中的周圍像素一一對比,然後shadow map的一個局部會出現一個二值化的空間。根據1與0數量比例,就可以判斷出目前像素與陰影的關系。這種采樣方式的一個很重要的優點就是結果不是二值化的,而是從0到1的浮點型數值。換個角度了解,就是說這種采樣的結果可以描述目前像素被陰影覆寫的程度,而不是簡單的是否被陰影覆寫。從理論上講,就賦予了shadow map渲染半影的能力了,至少可以簡單解決shadow map算法中的邊緣走樣問題。

在把目标點變換到Light Space之後,我們需要确定都讀取shadow map中的哪些像素。最簡單的辦法就是按照規律均勻讀取一定的采樣點,不過這種辦法可能會産生一些規律性的東西,是以用泊松分布來讀取周圍的采樣點更靠譜一些。而周圍的采樣點的範圍,我們可以用一個參數kernel_size來線性變換。這個值可以控制半影的大小,當然,半影越大,需要的采樣點也越多一些,否則會有明顯的走樣問題。

上面簡單描述了下PCF的算法原理。那麼PCSS相對于PCF多做了些什麼工作呢?實際上,如果PCF能夠動态适應半影的大小,那麼就可以直接做成soft shadow了,PCSS也正是這樣工作的。

PCSS的算法分成三個步驟:

首先,把目标點變換到Light space,然後找到周圍點中的遮擋該目标點的點,記錄其與光源的距離。在搜尋了一定的遮擋點之後,我們會根據這些遮擋點計算出一個平均遮擋距離。如果目标點不在陰影中,平均遮擋距離為0,PCSS算法直接傳回1.0。

然後,我們假設光源、遮擋物和目标接受點所在平面都是平行的,通過相似三角形的原理,計算出半影的大小。

PCSS 簡介

最後,根據半影的大小,我們可以動态的調節PCF中的搜尋範圍,進而改變半影的大小。

上面的步驟沒有詳細說明,想深入了解的朋友建議還是看看paper裡面的描述吧。

PCSS 簡介

上圖是我根據sample裡面的代碼,加入了PCSS算法所生成的結果。我們看到,飛機距離牆面比較遠,是以陰影的很模糊。而距離牆面最近物體投射的陰影都是很清晰的,不過也沒有明顯的鋸齒。

PCSS可以動态生成軟陰影,而且不需要額外處理。隻要引擎裡面有shadow map算法,更改成PCSS算法并不複雜。

當然,這個算法也是有一定問題的,在光源距離遮擋物很近的時候,我們看到的shadow會有嚴重的重影現象(這個問題我沒有深入調查,不過可能是用一些插值手段去除其走樣吧)。好在許多遊戲中,光源被很近的物體遮擋住的現象非常少,該算法應該還有很多用武之地的。

繼續閱讀