蔣莉珍
(桂林航天工業(yè)學(xué)院, 廣西 桂林541001)
用射線跟蹤生成的圖像質(zhì)量比用光柵化高很多[1],一個典型的例子就是近年來動畫中大多數(shù)的特技效果都用路徑跟蹤來完成的。 但是使用射線跟蹤是有挑戰(zhàn)性的實時應(yīng)用程序,例如在游戲中的應(yīng)用。首先像包括包圍卷層次(BVH)構(gòu)造、BVH 遍歷、和射線/原始交叉測試等射線跟蹤算法的步驟的代價是非常高昂的。 其次在射線跟蹤技術(shù)中采用隨機抽樣也非常困難,因為通常需要數(shù)百到數(shù)千的樣本,以產(chǎn)生一個收斂的圖像,這遠遠超出了現(xiàn)代實時渲染技術(shù)的預(yù)算的計算范圍,現(xiàn)代實時渲染技術(shù)只能按幾個數(shù)量級來進行計算,并且,直到最近,實時圖形api 還沒有光線跟蹤支持使光線追蹤集成在當(dāng)前的游戲中很難被利用。 隨著在DirectX 12 和Vulkan 中射線跟蹤支持的宣布徹底的改變了此前的狀況。 本文主要采用了DirectX 射線追蹤(DXR)并將其集成到UE4 中,這使得可以重用現(xiàn)有的材質(zhì)著色器代碼。
將光線跟蹤框架集成到大型應(yīng)用程序如虛幻引擎中是非常困難的,對于ue4 來說已經(jīng)算是非常大的構(gòu)架更改了[2]。 將光線追蹤集成到UE4 主要為了實現(xiàn)的目標(biāo)如下:
(1)性能。 這是UE4 的一個關(guān)鍵方面,通過此方面來判斷光線跟蹤功能是否可以符合用戶的期望。 通過使用現(xiàn)有的基于光柵化的技術(shù)計算g 緩沖區(qū),然后通過對比可以幫助我們更好進行的判斷,在進行計算時最重要的是射線是用來計算特定的通道,如反射或面積光的陰影。
(2)兼容性。 射線跟蹤通過的輸出與現(xiàn)有的UE4 的著色和后處理管道必須是兼容的。
(3)光的陰影一致。 UE4 使用的陰影模型必須準(zhǔn)確使用光線追蹤來產(chǎn)生一致的陰影效果。 具體來說時需要嚴格遵循相同的數(shù)學(xué)規(guī)則在現(xiàn)有的著色器代碼中對UE4 提供的各種遮陽模型做BRDF 評估,重要性抽樣,和BRDF 概率分布函數(shù)。
(4)最小化中斷。 現(xiàn)有的UE4 用戶必須找到易于理解和擴展的集成,因此,這些集成必須遵循UE設(shè)計范例。
(5)多平臺支持。 最初在UE4 中實時光線跟蹤是完全基于DXR,如果需要UE4 的多平臺特性支持必須設(shè)計新系統(tǒng),這樣在以后進行平臺移動時就不必過多的關(guān)注重構(gòu)技術(shù)了。
整合分為兩個階段。 第一個階段是原型階段,本文利用了“反射”(《星球大戰(zhàn)》的部分)和“光速”(保時捷)演示探討了光線跟蹤技術(shù)在計算機輔助設(shè)計中的應(yīng)用。 以此來幫助我們獲取到了有關(guān)性能、API、集成延遲著色管道渲染硬件接口中需要的更改(RHI)、一個從每個硬件的細節(jié)中抽象出用戶的薄層平臺、著色器API 的變化、可擴展性等等集成中最具挑戰(zhàn)性的方面的結(jié)論。
在找到第一階段出現(xiàn)的大多數(shù)問題的答案后,進入第二階段。 這包括對UE4 高級版本的重大重寫渲染系統(tǒng),除了提供了一個更好的實時光線追蹤的集成,也提升了整體性能提高了著色器API 的可擴展性等等各方面的好處[3]。
下面簡述一下在高層次上將射線跟蹤集成到基于柵格的實時系統(tǒng)中渲染引擎的幾個步驟:(1)注冊將被ray 跟蹤的幾何圖形這樣保證了當(dāng)圖形改變時可以加速結(jié)構(gòu)可以建立或更新。 (2)創(chuàng)建命中著色器,使任何時候的射線擊中一塊幾何圖形,都可以像在基于柵格化的渲染計算它的材料參數(shù)。 (3)創(chuàng)建光線生成著色器,跟蹤陰影反射等各種用途的光線情況。
要理解第一步,首先要理解由DirectX 射線跟蹤API 公開的兩級加速結(jié)構(gòu)(AS)。 在DXR 中兩種類型的加速結(jié)構(gòu)形成了一個兩級層次結(jié)構(gòu):頂級加速結(jié)構(gòu)(TLAS)和底層加速結(jié)構(gòu)(BLAS)[4]。 如圖1 所示,TLAS 構(gòu)建在一組實例之上,并且每個實例都有一個有自己的變換矩陣和指向BLAS 的指針。 每個BLAS 都建立在一組幾何原語之上,幾何原語可以是三角形,也可以是AABBS,這些其中AABBS 被用來封裝自定義幾何圖形,由于沿著射線可以找到AABBS 所以這些幾何圖形將使用自定義交叉著色器在加速結(jié)構(gòu)遍歷過程中進行交叉。 TLAS 通常為動態(tài)場景重建每個幀,每個TLAS 為每個獨特的幾何圖形至少構(gòu)建一次[5]。 如果幾何圖形是靜態(tài)的,則在初始構(gòu)建之后不需要額外的BLAS 構(gòu)建操作。不過對于動態(tài)幾何,BLAS 將需要更新或完全重建。當(dāng)輸入原語的數(shù)量發(fā)生變化時,需要重新構(gòu)建完整的BLAS 比如三角形或AABBS 需要添加或刪除。對于BVH(這是NVIDIA RTX 實現(xiàn)所使用的)來說BLAS 更新需要一個refit 操作,其中樹中的所有AABBS 都從葉子更新到根,但樹結(jié)構(gòu)保持不變。
圖1 加速結(jié)構(gòu)的兩級層次結(jié)構(gòu)Fig. 1 A two-level hierarchy of accelerated structures
在實驗UE4 實現(xiàn)中,擴展渲染硬件接口(RHI)的抽象靈感來自于NVIDIAOptiX API,但略有不同把整個的抽象做了相應(yīng)的簡化。 這個抽象由3 種對象 類 型 組 成: rtScene, rtObject, 和 rtGeometry。rtScene 是由多個有效的rtObjects 組成的實例,每個實例都指向一個rtGeometry。 rtScene 封裝了一個TLAS,而rtGeometry 封裝了多個BLAS。 rtGeometry和任何指向給定rtGeometry 的rtObject 都可以由多個部分組成,所有這些都屬于同一個UE4 原始對象(靜態(tài)網(wǎng)格或骨架網(wǎng)格)并且共享相同的索引和頂點緩沖區(qū),但是他們可以使用不同的(材質(zhì))點擊著色器。 rtGeometry 本身沒有與之關(guān)聯(lián)的著色器,因此我們可以在rtObject 部分設(shè)置著色器及其參數(shù)。
引擎材質(zhì)著色系統(tǒng)和RHI 也被擴展到支持DXR 中新的射線跟蹤著色器類型,在實驗中主要的著色階段為射線生成、最近命中、任意命中、交叉、錯過。 與這些著色器階段的射線跟蹤管道如圖2 所示。 除了最近命中和任何命中的著色器,本文還擴展了引擎支持使用現(xiàn)有的頂點著色器(VS)和像素著色器(PS)。 利用了一個擴展開源微軟DirectX 的實用工具編譯器來提供一種從預(yù)編譯的VS 和PS的DXIL 表示生成最近命中和任意命中著色器的機制。 此實用程序?qū)S 代碼、輸入組裝階段的輸入布局(包括頂點和索引緩沖區(qū)格式和步長)和PS 代碼作為輸入。 給定這個輸入,它可以生成執(zhí)行索引緩沖區(qū)提取、頂點屬性提取、格式化的最優(yōu)代碼,接下來是VS 求值(對于三角形中的三個頂點),然后使用擊中時的重心坐標(biāo)插值VS 輸出,其結(jié)果作為輸入提供給PS。 該實用程序還能夠生成一個最小的任意點擊著色器來執(zhí)行alpha 測試。 這使得引擎中的渲染代碼可以繼續(xù)使用頂點和像素著色器,就好像它們將 被用來采用光柵化G-buffer 設(shè)置著色器參數(shù)一樣。
圖2 射線跟蹤管道Fig. 2 Ray tracing pipeline
在這個實驗性的RHI 抽象下的實現(xiàn)有兩個額外的職責(zé):編譯射線跟蹤著色器(到特定于gpu 的表示)以及管理著色器綁定表,管理著色器綁定表指向需要用于每個幾何圖形塊的著色器代碼和著色器參數(shù)。
在引入RTX 和DirectX 射線跟蹤之前,圖形api(用于柵格化和計算)中現(xiàn)有的管道抽象只需要提供少量的著色器(1 到5 個)來創(chuàng)建所謂的管道狀態(tài)對象(PSO),該對象它封裝了用于輸入著色器的已編譯的特定于機器的代碼。 這些圖形api 允許在需要時并行創(chuàng)建許多管道狀態(tài)對象,每個對象用于不同的材質(zhì)或渲染管道。 然而,射線跟蹤管道在很大程度上改變了這一點。 射線跟蹤管道狀態(tài)對象(RTPSO)必須與所有可能需要在給定場景中執(zhí)行的著色器一起創(chuàng)建,比如當(dāng)一個射線命中任何對象時,不管什么樣子的對象系統(tǒng)都可以執(zhí)行與之相關(guān)聯(lián)的著色器代碼。 在當(dāng)今游戲的復(fù)雜內(nèi)容中,這很容易就意味著成千上萬著色器。 編譯數(shù)以千計的射線跟蹤著色器成機器碼如果順序進行,一個RTPSO可能非常耗時。 幸運的是,這兩個DirectX 射線跟蹤和所有其他由RTX expose 啟用的NVIDIA 射線跟蹤api 能夠編譯利用當(dāng)今cpu 的多核在并行多射線跟蹤著色機的機器碼。 在實驗中UE4 實現(xiàn)時,可以通過簡單地調(diào)度單獨的任務(wù)來使用這個功能,它們各自編譯一個射線跟蹤著色器或命中組,形成DXR 所謂的集合。 在每一幀,如果沒有其他著色器編譯任務(wù)已經(jīng)在執(zhí)行,檢查是否存在那種需求但不能用的著色器。 如果找到任何這樣的著色器,我們就開始新一輪的著色器編譯任務(wù)。 我們還檢查了每一幀之前是否有著色器編譯任務(wù)已經(jīng)完成。 如果完成了創(chuàng)建了一個新的RTPSO,替換了之前的RTPSO。 在任何時候,一個RTPSO 都用于一個幀中的所有DispatchRays()調(diào)用。 任何舊的RTPSO 如果不在幀框架中使用時都會被新的RTPSO 所取代。 當(dāng)構(gòu)建TLAS 時,當(dāng)前RTPSO 中尚未提供所需著色器的對象會被刪除(跳過)。
這個表是一個由多個記錄組成的內(nèi)存緩沖區(qū),每個記錄都包含一個不透明的著色器標(biāo)識符和一些著色器參數(shù),它們相當(dāng)于DirectX 12 調(diào)用的根表(用于圖形管道繪制或計算管道調(diào)度)。
由于第一個實驗實現(xiàn)的目的是得到每一幀更新場景中每個對象的著色器參數(shù),所以著色器綁定表管理很簡單,就像命令緩沖區(qū)一樣。 著色器綁定表被分配為一個n 緩沖的線性內(nèi)存緩沖區(qū),大小由場景中的對象數(shù)量決定。 在每個框架中,我們利用可見的GPU 以及可以分配緩沖區(qū)的CPU 來編寫整個著色器綁定表,然后我們將GPU 副本從這個緩沖區(qū)加入到GPU 本地副本的隊列中。
最近引入的用于光線跟蹤加速的專用硬件和圖形api 中添加的光線跟蹤進行創(chuàng)新,并嘗試一種混合呈現(xiàn)的新方法,將柵格化和光線跟蹤相結(jié)合。 雖然沒有進行在商業(yè)級游戲引擎虛幻引擎4 中集成光線追蹤的工程實踐。 不過這種創(chuàng)新的重建過濾器,用于渲染隨機效果,如光滑的反射、柔和的陰影、環(huán)境遮擋和漫射間接照明,每個像素只有一條路徑,使這些昂貴的效果在實時中應(yīng)用成為可能。 而且已經(jīng)成功地使用混合渲染創(chuàng)建了兩個電影質(zhì)量的演示雖然演示的片段過于短促。