Shadow Map


如何能夠高效的產生更接近真實的陰影一直是視頻游戲的一個很有挑戰的工作,本文介紹目前所為人熟知的兩種陰影技術之一的ShadowMap(陰影圖)技術。
    ShadowMap技術的概念應該說是最早應用在視頻游戲中的陰影實現技術,有着非常高效和快速的特點,在實現陰影的同時只需要相對很小的計算負擔。
    ShadowMap繪制陰影主要是通過一張額外的陰影貼圖來實現的,在早期的3D游戲中人物等動態運動的物體通常不繪制陰影,而場景內遮蔽關系相對確定的靜態物體的陰影通常是在建立模型之初便已繪制到場景的貼圖之中,這是利用ShadowMap來實現陰影概念的最初形成,而現在我們說到的 ShadowMap只是在游戲繪制時將陰影動態的繪制到一張陰影貼圖上,再利用計算好的陰影貼圖來繪制場景而已,整個計算只需要將場景繪制兩邊,而不需要像ShadowVolume一樣額外生成新的模型,所以Shadow可以保持很好的性能表現而與場景的復雜度並無太大關系。
    ShadowMap的概念很好理解,整個繪制過程分為兩個階段,首先以燈光為視角對場景進行繪制,繪制的結果是將場景內物體相對光源的深度信息寫入一張陰影圖中(Shadow Map),而不是RGB顏色。第二遍繪制場景時逐像素對比相對光源的深度值與陰影圖中的深度,當深度大於陰影圖中的深度時,說明該像素位於陰影中,進行相應的陰影混合。因為ShadowMap這種技術的特點,所以非常適合實現錐光源(spot light)下的陰影。對於在點光源(point light)下的利用ShadowMap生成陰影,有一種方法是利用Cubemap,這樣六張陰影圖可以實現全景點光源的ShadowMap。
    生成Shadow Map
    以DirectX中Sample為例,用於生成Shadow Map的Texture是格式為D3DFMT_R32F的RenderTarget,32位的浮點數可以保證深度信息的精度。
    第一遍的繪制中,設置視角變換和投影矩陣為光源的視角變換和投影矩陣(假設一個相機從光源向外),在Vertex Shader中照常進行頂點空間坐標(這樣深度測試會自動得到每個像素最接近光源的點),額外的貼圖坐標輸出為坐標的z和w坐標。
    Depth.xy = oPos.zw;
    在Pixel Shader中最終輸出的深度:
    Color = Depth.x / Depth.y;        // Depth is z / w
    這個值就是反映場景中在光源照射下的深度信息,值域位於0,1區間,位於近平面時為0,原平面時為1。
    渲染場景
    第二遍渲染場景,在Vertex Shader中除了完成坐標轉換和貼圖坐標轉換外,需要額外傳遞幾個參數,觀察視角下的空間坐標、法線向量以及轉換到光源投影空間下的坐標。前兩個用於光照計算,后一個用於陰影深度判斷。
    最后的陰影混合在Pixel Shader中完成,在這里依次判斷每個像素是否位於光照影響之下,只需用到該頂點的光向量與光源朝向向量點積的結果與光源照射范圍二分之一弧度值的 cos值相比較(通過夾角大小來判斷)
    如果位於光源照射下,則計算該像素在深度圖中的uv坐標,采樣,然后比較深度值,判斷是否位於陰影之內:
    //換算UV坐標
    float2 ShadowTexC = 0.5 * vPosLight.xy / vPosLight.w + float2( 0.5, 0.5 );
    ShadowTexC.y = 1.0f – ShadowTexC.y;
    //采樣並判斷深度
    LightAmount = (tex2D( g_samShadow, ShadowTexC ) < vPosLight.z / vPosLight.w)? 0.0f: 1.0f;
    最后根據陰影信息混合顏色即可。
    Shadow Map的最大優點是高效率和快速,同樣也會存在很多局限性,比如不適合點光源,並且在生成的陰影邊緣鋸齒化很嚴重。當然,我們也可以通過多次采樣混合陰影邊緣或者多次渲染進行高斯模糊來提高效果。


免責聲明!

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



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