前面幾篇陰影相關的:
https://www.cnblogs.com/crazii/p/5443534.html 這個是在做bh3 MMD角色自陰影時的筆記
https://www.cnblogs.com/crazii/p/7227269.html 這個是blade的CSM筆記和相關思考
這次在項目里對unity又做了新的改進, 整體思路還是沿用第二篇的方式:
1.使用足夠長/遠的視錐(view/projection)剔除場景 (渲染shadow map總是要剔除的,所以先用足夠遠的視錐,保證所有可見陰影的shadow caster都在)
2.根據剔除后的包圍盒,代替場景包圍盒,做凸包體相交
3.重新計算並設置渲染用的view/projection也就是說(shadow) scene culling和rendering用的view/projection是不一樣的,后者基於前者的culling結果重新計算。
記錄幾個要點:
1. shadowmap剔除以后的結果, 可以是一組世界空間的caster(的包圍盒), 變換到光空間, 再合並; 也可以是他們合並后的結果, 再變換到光空間. 建議使用前者, 因為合並后包圍盒已經變大, 再做空間變換,會導致包圍盒(AABB)變更大. blade為了偷懶使用了后者, 最近在unity的項目里里使用了前者.
2.一般CSM的cascade判斷,可以簡單的用場景相機的視距分割. unity使用的是球體. 最好的方式是用光視錐(Light Frustum OBB, xy without z), 幾個cascade的光視錐方向一樣. 比如4個cascade: shader里需要光空間UP,光空間RIGHT, 然后4個viewpoint和4個視錐的width, height. 按球體/距離划分很容分到質量更低的cascade, 但是前一級很可能有深度可以采樣. 極端的例子: 光接近平行地面的時候, 影子被拉很長, 相機近處的物體投影很遠, 如果按光視錐OBB, 近處物體的影子就只會采樣cascade0, 不會采樣更低的cascade. 另外, receiver的范圍可以忽略, 只考慮caster的范圍, 否則為了顯示拉長的陰影, 使用更大的陰影范圍, 陰影質量也會下降.
另外OBB檢測會多出4個dot指令和一組比較指令, 對於收益來說時可以接受的
比如下圖里shadow range只有10, sm利用率幾乎沾滿整個cascade 0. 實際投影距離卻很長,30多米, 質量也沒有降低:
3.基於第2點, OBB是完全契合shadowmap視錐的, 所以只要在OBB內的receiver,一定可以在對應的cascade采樣到陰影, 所以如果一個物體的陰影完全渲染在cascade0里時, 就可以不用再畫到cascade1里. 這個優化可以根據caster的個數來決定要不要做, 比如一個只有10個caster物體的手游, 可以考慮迭代檢測. 可能出現的結果是: cascade0里有2個object, cascade1里只有1個object, 又因為緊湊包圍盒, 所以cascade1的質量比cascade0還要高.
4.一直在說的重新計算緊湊包圍盒, 不僅在blade里做了實現和驗證, 在mmd視頻渲染里得到了驗證, 也在實際項目里也得到了驗證, 特別是有CSM時, cascade0(視點近處幾米內)的質量會有明顯提升, sm利用率變高, 陰影會占據大部分區域.
下面時圖示 (光視錐的視角):
5. 在考慮使用light space的投影體的bounding volume, 用stencil標記receiver的范圍(類似shadow volume的標記方式), 圈出來的部分才做陰影采樣, 這樣對於soft shadow和pcss可以有優化. 但是依賴於early stencil, 也要看游戲場景是否適用. 目前6s測試, 1.2ms=>0.6ms, 節省了0.6ms, 用unity tent7x7 softshadow, 4=>1.5ms 省了2.5ms, 60%左右, 目測和陰影站整個地面的比例有關, 符合優化的原理. 根據理論來推測, 對於地面陰影占據絕大多數的情況, 優化不明顯.