99国产精品欲av蜜臀,可以直接免费观看的AV网站,gogogo高清免费完整版,啊灬啊灬啊灬免费毛片

網易首頁 > 網易號 > 正文 申請入駐

RealtimeGI實戰篇(上)|稀疏體素與距離場搭建軟件光線追蹤

0
分享至


【USparkle專欄】如果你深懷絕技,愛“搞點研究”,樂于分享也博采眾長,我們期待你的加入,讓智慧的火花碰撞交織,讓知識的傳遞生生不息!

這是侑虎科技第1738篇文章,感謝作者AKG4e3供稿。歡迎轉發分享,未經作者授權請勿轉載。如果您有任何獨到的見解或者發現也歡迎聯系我們,一起探討。(QQ群:793972859)

作者主頁:

https://www.zhihu.com/people/long-ruo-li-21

開篇

我認為學習某樣東西最好的方式就是在使用中摸爬滾打帶著目標去邊學邊做,恰逢彼時騰訊在GDC 2023上發布了HSGI的演講,體素軟件光追+ReSTIR算法大放異彩,在那一刻想要RTX ON的心情達到了頂點,于是不知天高地厚地立下了要做一個軟件光追管線復刻一下HSGI的目標。

斗轉星移,四季更迭。在帕魯之余,筆者完成了自己定下的一個一個小目標,對UE引擎有了一些基礎的認識,也取得了一些微小的成果。思前想后決定趕在今年的尾巴做一個小小的總結,辭舊迎新結束這一年。

一、理論鋪墊

實時GI的求解,其實就是求解渲染方程的過程。回顧整個計算的偽代碼,小小的渲染方程竟藏著實時渲染的三座大山!(眾所周知三座大山有四座。)

第一座山:可見性求解。首先我們需要找到對當前像素有光照貢獻的所有可見點;

第二座山:材質的評估。對于每一個可見點,需要以某種手段評估其表面的材質以得到Base Color、Normal等材質屬性;

第三座山:光照計算。萬事俱備我們要根據可見點的材質,計算其收到的直接+間接光照,作為遞歸方程的返回值;

第四座山:降噪。我們只能遍歷有限的可見點,因此蒙特卡洛估計器會返回嘈雜的結果。


對于硬件光線追蹤管線來說,硬件提供了BVH遍歷功能來解決可見性查詢問題。此外硬件提供了Hit Shader,能在光線命中時執行一段用戶自定義的連連看Shader來評估材質以及光照。對于降噪問題NVIDA貼心的提供了如NRD等各種降噪SDK。

對于小米加步槍一窮二白的軟件光追來說,這三座大山都要我們自己一點點鏟平。因此本文的重點將圍繞前三座大山展開。在后續的文章中,我們將重點突破降噪這座大山。

二、核心思路省流速覽

2.1 場景表達

騰訊在GDC 2023上發表的HSGI演講提供了很棒的思路,筆者也沿用HSGI的思路,使用體素來作為GI場景的表達。這樣自然而然地解決了材質評估和光照評估兩座大山。

對于光線的每一個命中點,我們根據命中位置查詢體素,就能得到這一點的Base Color、Normal等材質屬性,我們稱之為Material Cache;有了材質信息我們為每個體素計算其收到的直接+間接光照,光照結果存儲回體素中,我們稱之為Radiance Cache。


存儲Base Color、Normal、Emissive和Radiance需要耗費巨量的內存,因此需要對其進行稀疏化處理。我們將整個體素分為若干個4x4x4的子塊,稱之為Voxel Block,這是體素內存分配的最小單位。只要一個Block內存在任意一枚體素,我們就為其在體素池子中分配完整的4x4x4個體素的空間。

與之對應需要有一個分辨率為“體素分辨率÷4”的頁表,指明當前Block在體素池子中的實際位置。于是體素尋址的過程需要先根據體素的位置確定體素所屬的Block,然后再訪問頁表拿到實際的地址偏移進行紋理采樣。


2.2 體素化

在HSGI原文中使用的是基于光柵化的體素化,這需要在CPU端遍歷所有的物體,挑選“與待更新的體素區域相交的物體”并發起Drawcall,此處筆者耍了一些花活,使用了一種不依賴光柵化的體素化方法,這樣整個體素化的流程能完全被GPU接管。

受到Lumen的啟發,我們為每個模型拍攝6個方向的Mesh Card,記錄物體的深度、Base Color、Normal等信息。對于每個體素,我們將其位置轉換到拍攝Mesh Card時的相機空間,像做Shadow Map一樣判斷體素深度和Mesh Card上記錄的深度是否足夠接近。如果兩個深度足夠接近我們認為該體素是有效的。


2.3 可見性查詢

對于可見性查詢這座大山,HSGI原文使用的是基于HDDA的光線步進,我這里使用的方案是無符號距離場。參考了Lumen生成Global DF的Mip Texture的策略,對于存在體素的格子我們標記其距離值為0作為初始值,然后進行距離場的傳播,每個體素需要遍歷自己周圍上下左右前后6個體素來更新自己的距離值。每幀進行一次距離的傳播,若干幀之后場景就會被距離場填滿。


2.4 核心思路小結

核心思路其實非常簡單,每個體素遍歷所有物體的所有Mesh Card,判斷體素是否命中Mesh Card的深度值。如果一個Cell里面存在體素,我們為其分配一個4x4x4大小的體素頁面,將Base Color、Normal等材質屬性寫入體素池子中。最后我們標記無符號距離場的值為0,然后執行距離場的傳播。

猶如把大象裝進冰箱里面,看似簡單的步驟需要依賴一系列的基礎設施。我們怎樣高效地篩選對體素有貢獻的物體?怎樣訪問每個物體的Mesh Card?又該如何為體素分配內存頁面?拿到了體素的材質屬性我們怎么點亮整個體素場景?我們接著往下走,一步一步實現這些小目標。

三、物體剔除與GPU Scene

場景中有成百上千的物體,而3D紋理中又有成百上千的體素,我們不可能暴力地用兩個for循環,每個體素遍歷所有Object。如果一個體素落在了Object的包圍盒外面,顯而易見其無法對體素產生貢獻,則我們可以跳過這個Object的檢查,這就需要引入Object剔除的策略。

3.1 剔除流程

和UE引擎中的距離場更新類似,筆者使用環繞相機的體素ClipMap來進行遠景的LOD表達。因此我們會對場景中的Object進行兩次剔除。第一次剔除會排除那些不在ClipMap內的Object,得到每個ClipMap層級可見的Object列表。


接著我們將體素細分為更小的更新區塊,我們稱之為Update Chunk,第二次剔除會針對每個Update Chunk構建一個獨立的Object列表(和Light Cluster的思路非常類似),有了更精細的剔除,每個體素只需找到自己所屬的Chunk并且遍歷與該Chunk相交的Object列表。


3.2 GPU Scene實現

對于剔除的操作我們也是在GPU上完成的,這就需要把全場景每個Object的包圍盒、位置等信息(稱之為Object Info)上傳到GPU Buffer中。我們在GPU上開辟一塊內存來存放Object Info,每幀增量地將CPU上有變化的Object Info同步到GPU Buffer上。


注:在UE引擎中這個功能叫做GPU Scene,出于練習的目的,以及要存儲額外的如Mesh Card等信息,筆者自己實現了一套簡易版本。下文中如果提到GPU Scene一般是代指我自己的丐版實現。

首先我們在CPU上實現了簡易的線性分配器,用Free List鏈表來管理Object Info的分配,CPU和GPU兩端的Object Info都共享一個數組下標索引,記作Object ID。每幀CPU端會將所有Dirty的Object Info上傳到緊湊的Upload Buffer,接著在Compute Shader中根據Object ID將Object Info放到GPU Buffer正確的下標位置。


因為在CPU端我們是使用Free List來分配GPU Buffer的下標,這種簡單的方式是不保證物體連續緊湊存放的。因此我們增加一個Pass將所有的Object Info中用于剔除的數據單獨提取到一個小結構體并緊湊排放在MiniObjectInfoBuffer中。這樣既可以減少剔除線程遍歷物體時的Divergence,也可以減少每次讀取Object Info的帶寬開銷。


3.3 物體剔除實現

以第一次剔除(針對ClipMap)為例,我們為每個Object分配一條線程,以N個物體(線程組大小)為一組進行剔除。我們總共需要派遣的線程組數目為“全場景物體數目÷N”。

首先通過Shared Memory記錄線程組內每個Object的剔除結果;接著由線程組內第一個線程統計與ClipMap相交的Object數目,通過Interlocked指令在剔除結果Buffer中申請空間;最后各個線程將包圍盒和Object ID寫入Buffer。


這是一個非常基礎且好用的GPU并行編程范式。后續的第二次物體剔除(針對Update Chunk)代碼也是沿用同樣的邏輯,同樣對每N個Object分配一個線程組執行“剔除-統計-分配-寫回”這幾步。筆者這里就不再重復展示,有需要的讀者可以訪問GitHub獲取完整的代碼。


因為與ClipMap相交的Object數量無法確定,所以第二次針對Update Chunk的剔除我們使用的是Indirect Dispatch,這是一個二維的Dispatch,X軸代表ClipMap內的所有 Object,Y軸代表每個待更新的區塊。


至此我們為每個待更新的區塊,構建了與之相交的物體列表,大大加速了體素遍歷Object的過程。不過為了執行體素化,我們還欠一味東風,那就是Mesh Card,接下來的小節將介紹其管理策略。

四、Mesh Card管理

一組Mesh Card提供了物體的幾何信息(深度圖)與材質信息的快照,也是本文中不依賴硬件光柵化的體素化算法的基石。和Lumen不同,在筆者的方案中Mesh Card不負責存儲Radiance,因此它與場景Object的實例并非一一對應關系。使用了相同Mesh和Material的多個Object是可以共享同一組Mesh Card,可以將其類比為硬件光追中的BLAS概念。因此我們需要單獨實現Mesh Card的分配器。


我們使用圖集的策略來管理Mesh Card,配套一個四叉樹分配器為每張Mesh Card在圖集上分配物理空間;對于每組Mesh Card我們需要記錄它們的數量、分辨率等信息;對于每個Mesh Card,我們要記錄拍攝時的變換矩陣以及其在圖集上的位置。和Object Info類似我們配套一個線性分配器即可。


和Object Info類似,所有的分配(圖集空間、Mesh Card Info)都發生在CPU端,然后通過Upload Buffer將分配的結果同步到GPU 端。我們使用引用計數來管理每個Surface Cache(一組Mesh Card的集合),在Primitive新增或者刪除時我們根據其用到的Mesh、Material算出一個Hash Key,增加或減少Key對應的Surface Cache的引用,在引用為0的邊界情況我們還會通過四叉樹分配器分配或釋放圖集空間。


物體實例在場景中可能具有不同的縮放,對于巨大的物體它需要更高分辨率的Mesh Card來保證精度。在物體加入場景時我們會為其默認分配最低分辨率,隨著時間的推移我們每幀會隨機檢查一小部分Surface Cache,遍歷所有引用它的Object計算引用者在世界空間中的最大尺寸,根據尺寸重新分配Mesh Card圖集并重新發起Mesh Card捕獲的Drawcall。


五、體素注入與頁面分配

有了剔除后的物體列表,以及每個物體捕獲的Mesh Card,我們終于可以開始進行體素化了!

5.1 體素注入

在筆者的實現中,將128x128x128的體素均勻劃分為了8x8x8個更新區塊(Update Chunk),也是上文提到的剔除和體素注入的最小單位。

當相機移動、場景中的Primitive移動時都要重新對相關聯的Chunk進行體素注入。前者只需按照移動方向將前方Chunk置臟,后者則需要同時記錄增加、刪除的Primitive的兩個包圍盒所影響的Chunk,因為我們需要先擦除舊體素再注入新體素。在每幀盤點出Dirty的Chunk之后我們通過Upload Buffer將Chunk上傳到GPU。


和2.2小結中描述的流程一致,我們為每個Update Chunk內的每個體素分配一個線程,遍歷該體素所屬的Update Chunk的Object List,對于每一個Object我們找到它對應的Surface Cache并遍歷所有Mesh Card,逐個檢查其深度圖是否與體素相交。


和HSGI一樣,我們這里也使用一個uint64來表示一個4x4x4的體素Block內的體素占用情況,我們稱之為Voxel Bit Occupy Map,這樣我們可以使用32x32x32分辨率的紋理來表達128x128x128分辨率的體素占用情況。


我們為每個4x4x4的體素Block分配一個4x4x4大小的線程組,通過Shared Memory 統計Block內體素的占位情況,然后由線程組內第一個線程負責將占位情況Pack成 uint64寫入Bit Occupy Map,這里我們用兩個uint32代替uint64以獲得更好的兼容性。


有了Bit Occupy Map我們可以將體素可視化出來。此處作為演示我還可視化了每個 Update Chunk (下圖藍色)以便觀察體素更新的過程。因為使用了環繞地址映射,超出范圍但是來不及更新的體素會被映射回前方。為了演示我特地將每幀允許體素注入的Chunk預算調的很低,實際運行時是不會出現來不及更新的Artifact的。


5.2 體素頁面分配

只有Bit Occupy Map我們能得到場景的幾何表達,這解決了可見性查詢的問題,本小節將解決如何查詢命中點的材質屬性。Mesh Card不僅記錄了物體的深度信息,還保存了物體的Base Color、Normal和Emissive等材質屬性。我們使用和5.1小節體素注入中提到的“深度相交測試”相同的UV訪問Mesh Card圖集,即可拿到物體的材質屬性。


不同Object實例在世界空間中World Normal各不相同,此外Mesh Card是不包含Radiance的,因此我們不能簡單地用Mesh Card來表達逐Object實例的Surface信息。對于在體素注入中產生的每一個體素我們都應該獨立地記錄其Surface信息。如果把Mesh Card類比為硬件光追中的BLAS,那么帶有物體材質信息和Radiance的體素則可以類比為TLAS。


和Bit Occupy這種高度壓縮的數據不同,材質屬性是無法壓縮的。每個體素都有其獨自的Base Color,因此我們選擇稀疏地分頁存儲材質屬性。我們開辟一塊固定大小的體素池子作為物理存儲,同時配套一個指向Pool內空閑體素頁面的Free List Buffer作為GPU上的線性分配器,此外還需要配套一個體素頁表來為已經分配出去的體素頁面建立“體素位置”到“物理存儲地址”的映射。


和體素注入一樣,體素頁面的分配也是以4x4x4的Voxel Block為單位(這也是體素頁面的大小),因此體素頁面分配的流程完全可以合并到體素注入中。在每個線程組的第一個線程執行完Voxel Bit Occupy Map的寫入之后,它還要負責為當前Block找到一個體素頁面。

首先我們根據體素所在的Block的位置訪問Page Table得到Page ID,如果當前Block存在體素而沒有分配頁面我們訪問Page Free List獲取一個空閑的Page,如果當前Block不存在體素卻占用了一個有效的Page,我們將其插入到Page Release List中等待釋放。最后的最后將Page ID寫回Page Table,并記錄在共享變量中方便組內其他線程訪問。


在第一個線程分配完成體素Page之后,線程組內其他體素注入線程就可以將體素注入的結果寫入Voxel Pool,首先訪問Shared變量獲取該體素所屬的Block對應的Page,并計算在Pool中的地址。然后從Mesh Card中拿到Base Color等材質屬性,寫入Page對應的物理存儲中。


在體素可視化以及后面的光線追蹤中,我們也是通過同樣的代碼,先訪問Page Table再訪問Voxel Pool,這里就不重復展示了,感興趣的讀者可以移步GitHub瀏覽。有了稀疏體素我們獲得了查詢任意位置的Material信息的能力,可視化一發看下效果。


六、距離場

完成了體素注入,我們獲得了一張1/4分辨率的Bit Occupy Map,其中的每一個像素都表達了4x4x4的Voxel Block中的體素占位情況。我們可以直接利用Bit Occupy Map進行光線追蹤,上文的可視化就是這么來的。


利用Bit Occupy Map加速的HDDA光線追蹤一次能跳過4個體素的距離,要想跳過更大的距離就要對其生成Mip。在筆者的實現中體素為128分辨率,為了保證Volume的循環尋址,最小一級Bit Occupy的Mip不能小于8(因為Update Chunk在xyz方向上各有8個),這導致Bit Occupy的Mip層級并不高。

經過性能的對比,最終筆者還是決定使用距離場的方案,因為距離場能快速跳過空白的區域。出于學習的目的,筆者的代碼中仍保留了Bit Occupy Map純體素追蹤的算法,通過控制臺變量r.RealtimeGI.UseDistanceField開關。

距離場是處處連續且有數值意義的,可是我們目前手頭上只有非0即1的體素,怎么把場景的幾何表達從體素轉換到距離場呢?這里筆者參考了Lumen中Global Distance Field的做法:首先注入初始的距離值,然后進行若干次距離場的傳播(類比于對體素做Bloom)就可以將距離場填充滿整個場景。


距離場是稠密的,我們開辟和體素等大小(128)的,格式為R8的3D紋理,用0~1的范圍表達最多32個體素的距離。在體素注入的時候順便將對應格子的距離標記為0即可獲取距離場的“啟動資金”。


我們每幀還會進行一次距離場的傳播來填充空白區域的距離值,經過若干幀后距離場將會收斂。傳播的算法也很簡單,我們直接用鄰居的距離值+1,然后和本像素的值比大小。


一個基本收斂的距離場大概長這樣:


有了距離場我們就可以愉快地RTX ON了,首先將采樣點相對Volume的位置映射到0~1的UV空間,采樣對應UV的距離場并計算步進距離。值得注意的是距離場的距離并不代表實際空間中的距離值,因為我們的距離傳播算法在對角線時會產生誤差,因此需要開一下根號修正這個誤差。


值得注意的是,當我們命中一個體素時不一定代表這個位置真的有體素。因為我們是使用線性插值采樣器進行距離場采樣的,所以在光線追蹤器的視角上,距離場是“圓滑”的。這就導致命中點有可能在體素之外,所以在命中的時候我們要檢查命中點所在體素的鄰居體素,在它們之中找到最近且有填充的體素,以此來作為命中點。


來看一下在距離場視角下的體素場景:


七、體素光照

有了距離場和稀疏體素,我們解決了第一小節中提到的可見性查詢、材質評估兩座大山。最后一個問題則是怎么評估命中點的光照呢?

和材質屬性類似,我們可以保存每個體素其接收到的Radiance,這樣在我們光線命中體素的時候就可以像訪問Base Color、Normal那樣直接獲取到體素的光照信息。我們將帶有光照信息的體素稱為Radiance Cache,而本節的內容就是怎么根據體素的材質去計算其受到的Radiance。

在開始之前,我們要申請一塊雙份加大的Voxel Pool來額外存儲每個體素的Radiance,我們為每個體素存儲法線方向+法線反方向兩個方向的Radiance,這么做是為了保證厚度為1體素的墻壁,只有外面的一側是接受陽光的,避免發生漏光。在光線命中時,我們也要根據光線的方向,選取合適的體素面的Radiance


7.1 體素直接光照

每個體素我們都能拿到其世界空間的位置、Base Color、Normal等信息,那直接N dot L一發其實就可以得到每個體素的來自方向光的直接光照。我們的計算流程可以類比為離屏的延遲渲染,只是G-Buffer的數據是從Voxel Pool里面拿到的。

因為體素并不是緊密填充的,如果我們強行遍歷128^3的體素,那些沒有填充(值為0)的體素會在每個線程組內產生大量的Divergence,最終會導致性能的急劇下降。我們要預先找到那些有填充(值為1)的體素,將它們緊密排列在緊湊的Valid Voxel Buffer中,再對這個緊湊Buffer進行遍歷和計算。


我們為每一個Voxel Block (4x4x4 voxel) 分配一個線程,該線程從該Block對應的Bit Occupy Map中統計Block內有效的體素數目并寫入Shared Memory,由組內第一個線程在緊湊Valid Voxel Buffer中分配空間,最后將結果寫入Buffer中以備后續Pass使用。


緊接著是一次Indirect Dispatch遍歷了Valid Voxel Buffer,對于每個體素我們首先從緊湊Buffer中取出它的下標,根據下標計算地址并從Voxel Pool中讀取其材質信息。我們遍歷其正面、背面的法線,通過N dot L計算方向光的直接光照,最后將Radiance寫回Voxel Pool對應的位置。


對于方向光的Shadow,我們分兩種情況。如果體素落在視錐體內我們采樣CSM,否則我們朝方向光方向發射一條Shadow Ray進行可見性測試。我們還在進行測試的時候添加了一些法線方向的Bias以防止產生自遮擋現象。


在可視化體素的流程中,我們根據光線的方向采樣雙面的Voxel Radiance Pool就能看到每個體素受到方向光的Direct Lighting。


可視化看下效果:


這里還有一個小技巧,對于128^3x4的ClipMap來說,我們每幀計算全部體素的Radiance開銷還是太大了。我們會選擇2x2x2的棋盤格的模式去分幀更新體素的radiance,這樣每幀的開銷就只有全量更新的1/8,下圖展示了光照劇變時Voxel來不及更新的情況。


7.2 體素間接光照

細心的讀者肯定發現了,在上面的小節我們只計算了體素的直接光照,因此沒有光源的地方是死黑的。其實現在的體素已經準備進行后續的Final Gather流程了,只不過我們得到的是一次反彈的結果。如果我們為每個體素計算間接光照,我們就得到了無限反彈的結果。

我們使用基于Probe的方案來計算每個體素受到的間接光照。對于每一個Block(4x4x4 Voxel)我們放置一個Probe并均勻的Trace射線,從Voxel Radiance Pool中獲取命中點的光照,最后投影為球諧向量存儲到一張3D紋理中,用來在下一幀的Voxel Lighting Pass為體素提供間接光。


和Direct Lighting的計算類似,我們要先有一個Pass挑選出非空的Voxel Block,在其中擺放Probe并將Probe的索引Pack到緊湊的Buffer以決定我們要Dispatch多少組線程。


值得注意的是Probe的放置條件。我們不能只在當前Block是存在體素時才放置Probe,我們也要考慮相鄰Block的體素占位情況。當相鄰的Block非空時,當前的Block也要擺放一個Probe,這樣做是確保物體的雙面都能受到間接光照。


生成Probe的代碼和篩選有效體素的Pass類似,先判斷當前Block是否要擺放Probe,然后每組第一個線程統計、申請空間,最后各個線程將生成的Probe ID寫入緊湊Buffer。我們同樣使用了2x2x2的棋盤格策略進行分幀渲染,每幀只產生1/8的Probe。


Probe擺放的位置不能存在體素,因此需要進行Probe Relocation,我們的策略是遍歷代表當前Block體素占位情況的uint64,找到距離中心最近且為空的體素,在這個空的地方放置Probe就不會出現自相交的情況。因此我們需要一張額外的3D紋理來存儲Probe Offset,每個Texel代表一個Probe。

可視化一發Probe看看,可以發現Probe是緊緊圍繞物體擺放的,空的地方不會生成Probe,因為有Relocation機制,有體素的地方也不會有Probe。


上面的圖其實是帶了間接光的體素,我們這就開始進行Probe Gather!這是一個Indirect Dispatch,我們根據上面選出的有效Probe的數目來決定要發射多少線程組,每個Probe對應一個線程組。

我們為每個Probe分配64個線程并發射64(或者128,取決于控制臺變量)條射線,命中了體素則從Voxel Pool中取得Radiance,否則采樣Skylight,將Radiance投影成SH系數存儲到Shared Memory,最后進行Reduction并將結果存儲到3D紋理。


回頭修改Voxel Lighting Pass,我們根據體素的Index找到其所在的Block,因為Probe和Block是一一對應的,我們用Block Index采樣上一幀算好的Probe SH的3D紋理即可獲得當前體素的間接光照結果。代碼也非常簡單,采樣2x2x2的Probe,根據采樣點的法線、位置等信息決定接納或者排除probe,最后手動進行三線性插值。


萬事俱備!現在我們的體素是帶了直接光+間接光的體素,光線Hit到一個點能夠直接獲取到Incoming Radiance。此時光看體素的顏色,整個GI已經初現端倪。



八、性能

我們用EPIC商店的免費場景Modular Asian Medieval City為例,該場景包含了8000個Primitive,其中進入體素場景GPU Scene的Primitive數量為7500。

筆者的電腦為3060 Laptop(掙韭者),使用的體素精度為最小ClipMap層級0.2m,每幀允許的Update Chunk為64個,此外為了開發方便控制臺變量默認開啟r.Shaders.Optimize=0,沒有試過Cook后的情況。

UE引擎編輯器以4檔位進行不間斷相機移動以觸發體素更新,體素注入部分會產生0.1~0.2ms的開銷(圖1)剩下0.5ms為距離場傳播的開銷(圖2)。


對于體素光照部分,因為我們使用棋盤格的分幀更新策略,幀耗時會根據體素布局有跳變,平均在1.2ms。我們選取一個峰值幀進行查看,主要開銷在為每一層級的體素計算直接光、以及Probe Gather計算間接光上面。


注:這里clip0的開銷非常小是因為一個優化,最低層級的ClipMap不進行Probe Gather,而是復用上一層clip1的Probe Irradiance,這個優化在室外場景非常好用,但是室內場景容易漏光。

九、階段性總結

到這里,歷經艱難險阻。我們攻克了軟件光追的三座大山,成功把大象裝進冰箱。一起來看看我們都干了什么:


  • 為了體素注入,我們實現了一套Mesh Card的生成和管理系統

  • 為了高效地剔除Object,我們實現了一套簡易的GPU Scene

  • 為了存儲體素的材質信息和Radiance,我們實現了一套簡易的體素分頁內存管理系統

  • 為了可見性查詢,我們實現了距離場和體素HDDA兩種軟件光線追蹤算法

  • 為了計算體素的直接光和間接光,我們實現了簡易的離屏Deferred Shading,以及類似DDGI的Probe Gather系統

到這里我們的GI之旅其實才進行到一半。在后面的文章中我們將重點介紹如何對屏幕像素進行Final Gather、如何使用各種奇技淫巧來降噪。


十、代碼倉庫

https://github.com/AKGWSB/UnrealEngine/tree/4.27-akgi

引擎部分的代碼位:

Engine\Source\Runtime\Renderer\Private\RealtimeGI

著色器部分位于:

Engine\Shaders\Private\RealtimeGI

十一、參考與引用

HSGI: Cross-Platform Hierarchical Surfel Global Illumination

https://www.gdcvault.com/play/1029169/LIGHTSPEED-STUDIOS-Developer-Summit-HSGI

Radiance Caching for Real-Time Global Illumination

https://www.youtube.com/watch?v=2GYXuM10riw

游戲引擎隨筆 0x29:UE5 Lumen 源碼解析系列

https://zhuanlan.zhihu.com/p/499713106

最強分析 |一文理解Lumen及全局光照的實現機制

https://zhuanlan.zhihu.com/p/643337359

UE5 Lumen實現分析

https://zhuanlan.zhihu.com/p/378119803

UE5.1 Lumen Indirect Diffuse Lighting技術分析

https://zhuanlan.zhihu.com/p/69

文末,再次感謝 AKG4e3 的分享, 作者主頁: https://www.zhihu.com/people/long-ruo-li-21, 如果您有任何獨到的見解或者發現也歡迎聯系我們,一起探討。(QQ群: 793972859 )。

近期精彩回顧

特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。

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.

相關推薦
熱點推薦
黃曉明機場“整活”!16厘米鞋跟配詭異發際線,網友笑不活了

黃曉明機場“整活”!16厘米鞋跟配詭異發際線,網友笑不活了

玫瑰講娛
2025-06-16 19:44:51
美制戰機損失最大的一天,德黑蘭大批客機爆炸:伊朗空軍被摧毀了

美制戰機損失最大的一天,德黑蘭大批客機爆炸:伊朗空軍被摧毀了

帥先工場
2025-06-17 15:59:21
我爸出軌秘書已經45年,我媽不哭不鬧,在他70歲生日這天絕地反擊

我爸出軌秘書已經45年,我媽不哭不鬧,在他70歲生日這天絕地反擊

詭譎怪談
2025-05-02 15:13:52
S媽時隔27天再發文,稱與大S過去捐款不計其數,懇求網友停止網暴

S媽時隔27天再發文,稱與大S過去捐款不計其數,懇求網友停止網暴

鑫鑫說說
2025-06-18 11:03:14
如果這事還有人洗白,那真是極端的扭曲!

如果這事還有人洗白,那真是極端的扭曲!

胖胖說他不胖
2025-06-17 17:25:29
伊朗稱襲擊摩薩德總部 現場畫面曝光

伊朗稱襲擊摩薩德總部 現場畫面曝光

看看新聞Knews
2025-06-17 20:42:12
從古至今,賺錢最快的路子就一個,從未改變

從古至今,賺錢最快的路子就一個,從未改變

德魯克博雅管理
2025-05-29 17:03:46
第一批韭菜開始站崗

第一批韭菜開始站崗

懶貓的豐收日
2025-06-18 18:35:28
56歲高曉松與高中女友相約聚會,曬二人戀愛時合影,被嘲像兩代人

56歲高曉松與高中女友相約聚會,曬二人戀愛時合影,被嘲像兩代人

娛圈小愚
2025-06-18 08:53:07
全市場:羅馬官網短短幾小時被擠癱瘓,暫停季票銷售

全市場:羅馬官網短短幾小時被擠癱瘓,暫停季票銷售

懂球帝
2025-06-18 00:07:22
伊朗發生大規模網絡中斷 互聯網服務將切換至國家內部網絡

伊朗發生大規模網絡中斷 互聯網服務將切換至國家內部網絡

財聯社
2025-06-18 00:11:18
伊朗要變天了

伊朗要變天了

戰爭研究所
2025-06-13 23:40:34
以色列青年粗暴阻止亞洲工人進入防空洞:避難所專供以色列人用!

以色列青年粗暴阻止亞洲工人進入防空洞:避難所專供以色列人用!

阿龍聊軍事
2025-06-18 10:29:40
中紀委劃紅線!機關事業單位職工下班后,不能去這8類場所!

中紀委劃紅線!機關事業單位職工下班后,不能去這8類場所!

金哥說新能源車
2025-06-11 13:29:08
蘇超“太湖三可愛”成了交通一卡通卡面?官方:是真的

蘇超“太湖三可愛”成了交通一卡通卡面?官方:是真的

現代快報
2025-06-18 15:34:07
福建一姑娘把“荔枝核”泡水里,兩周長成“粉盆栽”,太治愈了

福建一姑娘把“荔枝核”泡水里,兩周長成“粉盆栽”,太治愈了

美家指南
2025-06-09 11:08:50
不要修特異功能:我身邊有神通的人沒有一個好下場

不要修特異功能:我身邊有神通的人沒有一個好下場

老僧奇譚
2025-06-17 11:23:09
李嘉誠說:“只有窮人,才會癡迷技術,只有笨人,才會先把事做好

李嘉誠說:“只有窮人,才會癡迷技術,只有笨人,才會先把事做好

伊人河畔
2025-06-08 11:05:34
國足敲定臨時主帥,久爾杰維奇將帶隊征戰東亞杯

國足敲定臨時主帥,久爾杰維奇將帶隊征戰東亞杯

齊魯壹點
2025-06-18 11:12:15
王虹北大講課座無虛席!韋東奕聽課表情惹爭議,網友評價太扎心!

王虹北大講課座無虛席!韋東奕聽課表情惹爭議,網友評價太扎心!

古希臘掌管松餅的神
2025-06-17 20:00:39
2025-06-18 19:24:49
侑虎科技UWA incentive-icons
侑虎科技UWA
游戲/VR性能優化平臺
1455文章數 984關注度
往期回顧 全部

科技要聞

別叫我互聯網公司,京東的野心藏不住了

頭條要聞

俄方稱朝鮮決定向俄羅斯追加派兵6000人 中方回應

頭條要聞

俄方稱朝鮮決定向俄羅斯追加派兵6000人 中方回應

體育要聞

高僧下山了!文班結束少林寺10日修行

娛樂要聞

前老板舉報李雪琴欠190萬轉移公司財產

財經要聞

潘功勝李云澤吳清發聲 資本市場關鍵信號

汽車要聞

燈光技術升級還有插混版本 全新奧迪Q3預計明年國產

態度原創

旅游
本地
時尚
公開課
軍事航空

旅游要聞

熱聞|清明假期將至,熱門目的地有哪些?

本地新聞

黎錦匠人鄭春榮:經緯千年 我在海島織黎錦

鞋子選錯胖10斤?下半身胖可入這幾雙顯瘦神鞋

公開課

李玫瑾:為什么性格比能力更重要?

軍事要聞

特朗普呼吁伊朗無條件投降

無障礙瀏覽 進入關懷版 主站蜘蛛池模板: 富锦市| 清远市| 瑞金市| 永嘉县| 宜州市| 广汉市| 岳西县| 库车县| 三亚市| 海南省| 大邑县| 望奎县| 灵山县| 米脂县| 闸北区| 双桥区| 杭锦旗| 中西区| 南康市| 凌云县| 许昌市| 宝鸡市| 句容市| 和政县| 荆州市| 久治县| 江川县| 东至县| 鄂托克前旗| 宁阳县| 宁远县| 大庆市| 新津县| 萨嘎县| 偃师市| 天等县| 淳化县| 双柏县| 中牟县| 吴旗县| 逊克县|