在團結(jié)引擎 1.4.0 版本中,我們發(fā)布了重磅功能:虛擬陰影貼圖(Virtual Shadow Maps,VSM),全面升級開發(fā)體驗,為開發(fā)者提供更加逼真的光影效果。
虛擬陰影貼圖介紹
虛擬陰影貼圖(Virtual Shadow Maps,VSM)是一種GPU驅(qū)動的實時陰影渲染技術(shù),它能夠為高面數(shù)模型與大型場景提供超高分辨率的陰影。隨著虛擬幾何體(Virtual Geometry,VG)的推出,常規(guī)的陰影渲染技術(shù),如級聯(lián)陰影貼圖(CSM),已經(jīng)不能滿足高面數(shù)模型對于陰影質(zhì)量的要求,而虛擬陰影貼圖則能夠通過其超高的分辨率(16k x 16k)很好地對這一類模型和場景進行適配。
但是在復雜光源場景下,顯存很難容納下如此高分辨率的陰影貼圖,因此,與虛擬紋理(Virtual Texture)類似,虛擬陰影貼圖采用了分塊管理和按需加載的方法來優(yōu)化內(nèi)存占用和渲染性能。即使在一種非理想復雜場景中,需要渲染的陰影也只是攝像機當前所能觀察到的,虛擬陰影貼圖便利用了這一點來優(yōu)化內(nèi)存分配。
虛擬陰影貼圖會預分配一張固定大小的物理紋理(16384 x 4096)來存儲陰影深度,并將其劃分為 128 x 128 的物理頁(Page)。針對投射陰影的光源,虛擬陰影貼圖會為其提供若干虛擬的 16k x 16k 的超高分辨率紋理,并將這些虛擬紋理分為同樣 128 x 128 的虛擬頁。從深度緩沖還原出像素的世界空間位置,再將像素投射到光源的視口下,系統(tǒng)可以獲取到當前幀所需要的頁。虛擬陰影貼圖只會渲染這些需要的虛擬頁,并將陰影深度寫入物理頁。
局部光
局部光通過 16k x 16k 的虛擬陰影貼圖以及它的 Mipmap 機制,保證陰影渲染的質(zhì)量與效率。 目前,我們支持了聚光源與點光源兩種局部光。
?聚光源: 使用單張 16k x 16k 的陰影貼圖進行陰影渲染。
?點光源: 通過六張 16k x 16k 的陰影貼圖組成立方體貼圖(Cube Map)。
平行光
相較于局部光,平行光通常要覆蓋場景中更大的范圍,因而對于陰影貼圖的分辨率要求更高。為了滿足這一要求,平行光會使用到多張 16k x 16k 的裁剪圖(Clipmap)來進行陰影的渲染。每張裁剪圖對應一個陰影渲染的層級,裁剪圖的覆蓋范圍以攝像機為圓心,2^(層級 + 1)厘米為半徑。因此層級每提升一級,裁剪圖的覆蓋半徑提升一倍,而分辨率不變。默認的裁剪圖層級(Clipmap Level)為 6 - 22 級,最高可覆蓋半徑為 84 千米的面積,相較于傳統(tǒng)的陰影渲染技術(shù)取得了極大幅度的提升。
用戶可通過 Project Settings > Quality > HDRP 中 Virtual Shadow Map 模塊的Clipmap Min Level和Clipmap Max Level選項,靈活調(diào)整裁剪圖層級的范圍。
縮小覆蓋的層級數(shù)量能夠以陰影渲染質(zhì)量為代價換取虛擬陰影貼圖的整體開銷降低,用戶可根據(jù)具體的使用場景進行選擇。 如果當前工程對于近處陰影的質(zhì)量要求不高,則可以提升裁剪圖的最低有效層級; 如果當前工程所用的場景范圍不大,則可以降低裁剪圖的最高有效層級。
效果和性能對比
相比于傳統(tǒng)的陰影渲染技術(shù),虛擬陰影貼圖依靠其超高的分辨率,合理的頁分配與管理,能夠在大型場景或高精度模型的陰影渲染中取得更好的陰影效果,同時保證運行效率。
效果對比
下面的兩組圖片對比了 Tuanjie Editor 中級聯(lián)陰影貼圖(CSM)和虛擬陰影貼圖(VSM)的效果差異。對于級聯(lián)陰影貼圖,我們將 Resolution 選項設(shè)置為High,并將 Angular Diameter Scale for Softness 設(shè)置為0來渲染硬陰影。在 Volume 中,級聯(lián)陰影貼圖的 Max Distance 被設(shè)置為400。
CSM
VSM
可以看到的是得益于分辨率的提升,VSM 能夠取得更好的陰影質(zhì)量。
CSM
(Max Distance = 400)
VSM
除了陰影質(zhì)量的提升外,虛擬陰影貼圖還能在保證陰影質(zhì)量的基礎(chǔ)上覆蓋更大的范圍。在如上圖所示的陰影渲染中,整條街的長度遠遠超過了級聯(lián)陰影貼圖(CSM)400 米的 Max Distance,因而藍框所示區(qū)域就缺少了陰影的渲染。同時,在紅框所示區(qū)域中,CSM 所渲染的陰影出現(xiàn)了鋸齒,而 VSM 仍能夠呈現(xiàn)高精度的陰影。雖然將 Max Distance 提升到 1200 米后,級聯(lián)陰影能夠覆蓋整個區(qū)域(如下圖),但是顯而易見的是,街道上的硬陰影十分模糊,渲染質(zhì)量大幅下降,遠遠不及 VSM 所取得的效果。
CSM (Max Distance = 1200)
性能對比
我們 將在兩個場景中對比 VSM 和 CSM 的性能差異,第一個場景為 3200m * 1000m,包含大約40萬個 Game Object 的大型場景,而第二個場景則為包含大量復雜高精度模型的小型場景。
在這兩個場景當中,我們將分別比較在開啟 VSM; 同時開啟 CSM 和 VG; 開啟 CSM 的同時關(guān)閉 VG 的情況下,所表現(xiàn)出來的陰影渲染性能差異。 因為目前 VSM 只支持渲染硬陰影,所以在測試時 CSM 也同樣只渲染了硬陰影。
大型場景
1、開啟 VSM 后
- GPU 時間:總計 2.33ms。
- CPU 時間:初始化消耗0.327ms,執(zhí)行消耗0.094ms,總計0.421ms。
2、同時開啟 CSM 和 VG 后(CSM 的 Max Distance 為 2000 米)
- GPU 時間:總計 22.5ms。
- CPU 時間:初始化消耗0.243ms,執(zhí)行消耗2.737ms(RenderShadowMaps 消耗2.73ms,剩余過程消耗0.007ms),總計2.98ms。
3、同時開啟 CSM 和 VG 后(CSM 的 Max Distance 為 400 米)
- GPU 時間:總計 18.16ms。
- CPU 時間:初始化消耗0.288ms,執(zhí)行消耗0.446ms(RenderShadowMaps 消耗0.44ms,剩余過程消耗0.006ms),總計0.734ms。
4、開啟 CSM 的同時關(guān)閉 VG(CSM 的 Max Distance 為 2000 米)
- GPU 時間:總計 69.17ms。
- CPU 時間:初始化消耗0.055ms,執(zhí)行消耗28.05ms,總計28.105ms。
5、開啟 CSM 的同時關(guān)閉 VG(CSM 的 Max Distance 為 400 米)
- GPU 時間:總計 18.46ms。
- CPU 時間:初始化消耗 0.04ms,執(zhí)行消耗 5.23ms,總計 5.27ms。
性能總結(jié)與分析
我們?yōu)?CSM 選擇了兩個 Max Distance,2000米 與 400米。當 Max Distance 為 2000 米時,CSM 大致能覆蓋到攝像機視野中最遠的距離,但是此時 CSM 的性能大幅下降,因此我們也測試了在常見的 Max Distance 為 400 米的情況下,CSM 的性能表現(xiàn),但是從圖中可以看出,此距離下視野中出現(xiàn)了明顯的陰影缺失。
從表中可以看出,VSM 的性能是最為優(yōu)越的,且顯著優(yōu)于其他幾種方案,耗時約為表現(xiàn)第二的 CSM+VG(400m) 方案的一半。同時,在采用 CSM 的方案中,我們也能看到開啟 VG 后能夠極大提升 CSM 的性能表現(xiàn),因此我們推薦大家同時開啟 VSM 和 VG以取得最好的效果。
高精度模型場景
場景大小 70m*90m,包含了數(shù)百個面數(shù)為 300 萬的高模,整個場景面數(shù)在 10 億數(shù)量級,可以用于驗證當畫面近處包含大量高模時,VSM 的效果和性能表現(xiàn)。
1、開啟 VSM 后
- GPU 時間:共計 2.44MS
- CPU 時間:共計 0.633MS
2、同時開啟 CSM 和 VG 后(CSM 的 Max Distance 為 400 米)
- GPU 時間:共計 4.95MS
- CPU 時間:共計 0.465MS
3、開啟 CSM 的同時關(guān)閉 VG(CSM 的 Max Distance 為 400 米)
- GPU 時間:共計 382.55MS
- CPU 時間:共計 0.448MS
性能總結(jié)與分析
從渲染圖中可以看出,VSM 渲染出的硬陰影細節(jié)更為豐富,例如能夠渲染出雕像手指投射出的陰影,而 CSM 則無法做到這一點。而從性能上看,在渲染小場景中的高精度模型陰影時,雖然 VSM 的 CPU 耗時略微高于 CSM(我們還將持續(xù)優(yōu)化這部分開銷),但是 GPU 耗時大大降低了。
如何開啟虛擬陰影貼圖
打開工程的Project Settings,在Quality > HDRP中找到 Virtual Shadow Map 模塊,通過開關(guān) “Globally Enabled” 來開啟或關(guān)閉 VSM。
開啟后,虛擬陰影貼圖將替代工程中原先所有的陰影貼圖方案,如平行光所使用的級聯(lián)陰影貼圖。您幾乎不需要對現(xiàn)有的工程做任何調(diào)整,便能夠一鍵將場景中的所有陰影渲染方案替換為虛擬陰影貼圖。
目前若要開啟虛擬陰影貼圖,則需要同步開啟 Project Settings 中虛擬幾何體(Virtual Geometry)的全局開關(guān)。但是,虛擬陰影貼圖并非只能作用于 VG 物體。即使 Renderer 沒有開啟虛擬幾何體,虛擬陰影貼圖仍能夠為這些 Renderers 生成高質(zhì)量陰影。
VSM全局開關(guān)
VG全局開關(guān)
技術(shù)細節(jié)
虛擬陰影貼圖的陰影渲染主要涉及到如下圖所示的四個流程:
1. 從 GBuffer 提取當前幀所需要的虛擬頁號
2. 為這些虛擬頁分配實際的物理頁
3. 光柵化得到當前幀的深度值
4. 采樣深度圖渲染陰影
標記當前幀所需頁
因為虛擬陰影貼圖超高的分辨率,實際顯存容納不下這么大的紋理。 因此 16k x 16k 的陰影貼圖為虛擬紋理,且分割為了基本單位是 128 x 128 個紋素(texel)的虛擬頁。 根據(jù)當前幀需要哪些物體在光源視角下的深度值,我們標記這些深度值對應的虛擬頁為當前幀所需的頁,并在之后的流程中建立起虛擬頁和物理頁的映射關(guān)系,從而真正給這些虛擬頁分配物理顯存。
那么應該如何去確定當前幀需要哪些物體的深度信息呢? 獲取深度信息的最終目的是渲染屏幕中對應像素的陰影,因此,所需的物體即為出現(xiàn)在像素對應的虛擬頁中的物體。 我們可以從 GBuffer 中通過像素找到對應虛擬頁所需的相應信息,如頂點位置和法線。 VSM 在 GBuffer 的 Pass 之后插入了一個 Pass VSMClearAndExtractPagesFromGBuffer,用于從 GBuffer 中提取信息。 這個 Pass 會遍歷 GBuffer 的每一個紋素,從中獲取頂點的位置信息并映射到以光源為視角的屏幕空間中,找到對應的虛擬頁,這些虛擬頁便是當前幀所需的頁。
管理頁分配
現(xiàn)在我們知道了如何確定當前幀所需的頁,從原理可以看出每一幀所需的頁都有所不同,所以每一幀我們都需要重新建立起所需的虛擬頁和物理頁之間的映射關(guān)系,并保證當前幀所需的頁都能被映射到物理頁,否則我們便丟失了一些渲染陰影要求的深度信息。
光柵化生成陰影貼圖
因為 16k x 16k 的陰影貼圖為虛擬紋理,所以在光柵化時我們并不會將當前紋素的深度值作為 Fragment Shader 的輸出,而是寫入到對應的物理頁中。 在 Vertex Shader 中,將當前頂點進行坐標變換,變換為以光源為視角的裁剪空間坐標。 在 Fragment Shader 中,根據(jù)當前頂點的坐標確定所屬的虛擬頁,再向映射的物理頁的對應位置寫入深度值。
采樣生成陰影
類似于光柵化的過程,我們將屏幕中當前像素點對應的頂點位置進行坐標變換,切換到以光源為視角,從而確定當前像素對應的虛擬頁。 通過頁的映射關(guān)系,獲取到物理頁中存儲的深度值,并與當前像素在光源視角下的深度值做比較,若當前像素更靠近光源,則 Shadow Factor 為 1,否則為 0。 Shadow Factor 作為采樣的結(jié)果參與 LightLoop 相關(guān)的計算,從而得到陰影。
性能優(yōu)化
上述過程包含了虛擬陰影貼圖渲染陰影的基本流程,整個過程涉及大量的計算以及內(nèi)存讀寫,為了對性能進行優(yōu)化,我們使用了如下的幾個加速算法。
GPUCulling
類似于虛擬幾何體,我們將虛擬陰影貼圖的剔除(Culling)流程放到了 GPU 端實現(xiàn)。除了常規(guī)的以光源為視角的視錐體剔除(Frustum Culling)和遮擋剔除(Occlusion Culling)之外(對于開啟了虛擬幾何體的物體,還有額外的 LOD Culling),剔除流程中還判斷了當前物體所在的虛擬頁是否被標記,若未被標記,則當前物體被剔除。這么做是因為被標記的頁是當前幀渲染陰影所需頁,即使我們寫入了未被標記頁的深度值,在之后的陰影深度采樣流程中也不會用到這些頁,這部分算力就被浪費了。
深度緩存
從上述流程可以看出虛擬陰影貼圖每一幀需要更新的數(shù)據(jù)量非常龐大,如果我們每一幀都對這些數(shù)據(jù)進行全量更新的話,是一筆極大的開銷,會顯著降低幀率。因此我們需要盡可能地避免一些不必要的數(shù)據(jù)處理和更新。
在大多數(shù)情況下,場景中的物體保持了和上一幀相同的狀態(tài),因而它們的深度信息是不變的。對于這些物體,我們將它們的深度信息進行緩存保留,從而跳過上述流程中的一部分,直到這些物體出現(xiàn)了變化導致緩存失效。導致緩存失效的常見情況有:物體的移動,物體的出現(xiàn)與消失,攝像機的切換。在接下來的 Rendering Debugger 中 Cached Pages 可視化功能展示里,我們通過一個視頻演示了深度緩存的保留與更新機制。
在引入緩存機制后,上述流程中的一部分細節(jié)隨之發(fā)生變化,具體如下。
在未開啟緩存之前,對于管理頁分配,我們只需要簡單地按順序遍歷所有需要的虛擬頁和所有的物理頁,并將它們一一建立起映射關(guān)系。但是在開啟緩存后,并非所有的物理頁都是可以被覆寫的,因為其中一些頁存儲了上一幀有效的深度緩存信息,這些深度需要被這一幀復用。為了避免這些物理頁被覆寫,我們需要將這些物理頁重新映射到當前幀對應的虛擬頁。具體操作為在給所有虛擬頁分配物理頁之前,我們先判斷系統(tǒng)中是否保留了當前虛擬頁的有效深度緩存信息,如果有,那么我們根據(jù)上一幀的映射關(guān)系,找到對應的物理頁,并與這一幀的虛擬頁建立起映射關(guān)系,同時跳過這一幀的物理頁分配。
在進行 Culling 時,若系統(tǒng)判斷當前 cluster 或 instance 對應的虛擬頁為緩存頁,那么便會被剔除。這么做是因為我們已知這些物體的深度在這一幀并沒有發(fā)生變化,因而我們也就不需要 Culling 之后的光柵化流程來更新這些物體的深度值,從而節(jié)省一部分計算量。
用戶可通過 Project Settings 中 Virtual Shadow Map 模塊的Cache Enabled控制緩存的開關(guān)。同時,用戶可以通過Directional Light Cache Disabled開關(guān)單獨控制平行光的緩存。當場景中存在晝夜切換時,平行光的照射角度不斷變化,導致緩存頻繁失效,在這種情況下,緩存帶來的收益可能低于其計算成本,因此可以考慮關(guān)閉緩存提高效率。
Single Page VSM
我們通過對局部光的陰影精度進行調(diào)整來進一步優(yōu)化虛擬陰影貼圖的性能表現(xiàn)。對于距離攝像機較遠的局部光,高精度的陰影貼圖并不會帶來顯著的陰影效果提升,因此,我們針對這一部分局部光進行了優(yōu)化,使得它們的陰影精度降低為128 x 128,即一個頁的大小。
用戶可通過 Project Settings 中 Virtual Shadow Map 模塊的Distant Light Mode控制這一選項。當選項為OFF時,所有局部光都將使用高精度的陰影貼圖;當選項為ON時,攝像機遠處的局部光將使用低精度的陰影貼圖;當選項為ALWAYS時,所有的局部光,無論遠近,都將使用低精度的陰影貼圖。
Rendering Debugger 相關(guān)可視化功能
開啟虛擬陰影貼圖后,用戶可通過 GDRP 欄目下的VirtualShadowMap Visualization選項來控制虛擬陰影貼圖相關(guān)的可視化。通過該功能,用戶可以確認虛擬陰影貼圖是否如自己預期般工作。在接下來我們將以平行光為例,展示各種不同的可視化效果。
ClipmapLevelOrMipLevel
渲染屏幕中每個位置的陰影精度層級,平行光對應 ClipmapLevel,局部光則對應 MipLevel。每一種不同的顏色都代表了一個陰影精度層級。在如下圖所示的平行光陰影精度層級可視化中,根據(jù)與攝像機的距離,屏幕中的每個位置都被可視化了不同的精度層級,越靠近攝像機則陰影精度越高,層級越低。
正常渲染
ClipmapLevel
Request Pages
渲染屏幕中每個位置對應的虛擬頁,每一種相鄰的不同顏色塊都代表了一張?zhí)摂M頁??梢钥吹降氖牵嚯x攝像機越近,虛擬頁越密集,每個虛擬頁覆蓋的區(qū)域越小,而密度的邊界線則于上一欄中的 ClipmapLevel 對應。這是因為 ClipmapLevel 越低,則陰影精度越高,所以需要更多的虛擬頁去覆蓋相同大小的區(qū)域。圖中的每一個不同顏色的方塊都代表了一張 128 x 128 的虛擬頁,在 ClipmapLevel 變換的邊緣處虛擬頁可能存在不完整的情況,這是因為兩個層級間不同的虛擬頁發(fā)生了切換。
正常渲染
Request Pages
Cached Pages
渲染屏幕中每個位置對應的虛擬頁的緩存情況。若虛擬頁為綠色,則代表當前頁完全使用了緩存的深度信息;若虛擬頁為藍色,則代表當前頁的靜態(tài)物體部分使用了緩存的深度信息,而動態(tài)物體則沒有使用緩存;若虛擬頁為紅色,則代表當前頁內(nèi)的所有物體都沒有使用緩存信息。區(qū)分物體是否為靜態(tài)物體則是依據(jù) Inspector 窗口中 Mesh Renderer 組件的 Static Shadow Caster 選項是否開啟,若開啟則為靜態(tài)物體,否則為動態(tài)物體。
視頻展示了開啟 Cached Pages 可視化之后的效果。在第一幀時系統(tǒng)中沒有有效的緩存,因此所有物體在逐步由紅轉(zhuǎn)變?yōu)榫G。當鏡頭被移動時,不同 Clipmap 層級的邊界處出現(xiàn)了新的虛擬頁,這一部分新頁是沒有緩存信息的,因此層級交界處出現(xiàn)了紅色。隨著鏡頭轉(zhuǎn)換,畫面中出現(xiàn)了一輛在移動的汽車,這輛汽車所覆蓋的虛擬頁被標記為了藍色,這是因為汽車作為動態(tài)物體在移動,使得虛擬頁的動態(tài)緩存失效了。隨著鏡頭接近汽車,汽車所覆蓋的虛擬頁發(fā)生了變化,具體表現(xiàn)為從高 Clipmap 層級的虛擬頁變換為低 Clipmap 層級的虛擬頁,因而緩存失效的虛擬頁也隨之變化。
ShadowFactor
渲染屏幕中每個位置對應的陰影系數(shù),因為目前虛擬陰影貼圖只支持硬陰影,所以在目前 ShadowFactor 的可視化中只有 0 和 1 兩種值存在。值為 0 代表當前位置存在陰影,值為 1 代表當前位置不存在陰影。
正常渲染
Shadow Factor
兼容性
目前虛擬陰影貼圖處于試驗性版本,仍在積極開發(fā)當中,因此使用上存在一定局限性。當前虛擬陰影貼圖只能在團結(jié)引擎 1.4.0 版本的 HDRP 管線中使用,適配的材質(zhì)包括Lit.shader,LayeredLit.shader 以及 Shader Graph,支持的平臺包括Windows(DX11, DX12, Vulkan)和Linux(Vulkan)。
同時,目前虛擬陰影貼圖只支持渲染硬陰影。在所有光源類型中,平行光(Directional),點光源(Point)和聚光燈(Spot)能夠通過虛擬陰影貼圖渲染陰影,而面光源(Area)的適配工作仍在進行中。
Unity 官方微信
第一時間了解Unity引擎動向,學習進階開發(fā)技能
每一個“點贊”、“在看”,都是我們前進的動力
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺“網(wǎng)易號”用戶上傳并發(fā)布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.