在Unity中實現屏幕空間陰影(1)


接着上篇文章,我們實現了SSR效果。

其中的在屏幕空間進行光線追蹤的方法是通用的。借此我們再實現一種屏幕空間的效果,即屏幕空間陰影。

文中的圖片來自Catlike coding
http://catlikecoding.com/unity/tutorials/rendering/part-7/

完成的工程: https://github.com/yangrc1234/ScreenSpaceShadow

原生陰影

首先我們要了解一下原生的陰影是怎么實現的,這里我們只討論Directional Light。

首先,我們將Directional Light視作一個相機,對整個場景進行繪制。我們只需要其中的深度信息。(如果你嘗試過自己寫一個可以產生陰影的Shader,應該知道這個繪制是通過調用ShadowCaster類型的pass來實現的)

通過這樣渲染的一張ShadowMap,在我們渲染主相機的畫面時,對每一個像素,我們獲得它的世界坐標,然后將該世界坐標轉換到Directional Light的坐標系下,采樣對應的ShadowMap中的點。如果我們采樣出來的深度,大於該坐標的深度,我們認為該點沒有被阻擋。否則認為該點處於陰影中。

這就是ShadowMap方法的簡單描述。在Unity的Directional Light流程中,采用的是Cascade ShadowMap,此時會有若干個不同分辨率的ShadowMap被生成,分別對應與相機距離不同的區域,這樣可以做到相機較近的區域,分辨率較高,陰影質量更好;較遠的區域分辨率較低,質量一般(但是遠了你也看不出來)。


Cascade ShadowMap示例

不同於其他類型的光源,在主相機渲染時,我們求一個點的光照度,並不是直接去轉換坐標系然后采樣ShadowMap。在Directional Light流程中,在主相機渲染之前,Unity會將Cascade ShadowMap轉化為一張屏幕空間的陰影貼圖(Screen Space Mask,當然該過程也需要轉換坐標系去比較深度等等)。然后在主相機渲染時直接取采樣這張屏幕空間陰影貼圖獲得光照度。


屏幕空間的陰影貼圖示例

我們待會兒會通過操作這張屏幕空間陰影來實現我們的效果。

這種陰影實現毫無疑問是目前的主流方法。但是它也有不少問題,比如Shadow Acne現象。我們之前說到,判斷一個點是否在陰影中,是通過深度比較進行的。但是我們要判斷一個像素是否在陰影中時,因為深度貼圖的精度問題,可能會出現被周圍的差異極小的像素遮擋的情況。

屏幕空間陰影

屏幕空間陰影基於屏幕空間光線追蹤實現陰影效果。

最大的好處就是讓不參與ShadowMap繪制的物體也可以投出陰影。

而且作為一個屏幕效果,其效率與場景復雜度無關。

在繪制大量的小型物體時,這一優勢是很明顯的。

下圖是一個效果關閉開啟的對比。圖中的草是Unity的Terrain系統繪制的,默認不開啟陰影。可以看到開啟屏幕空間陰影后畫面提升明顯。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM