余瀚游,茍成秋
(1.四川大學(xué)視覺(jué)合成圖形圖像技術(shù)國(guó)防重點(diǎn)學(xué)科實(shí)驗(yàn)室,成都 610065;2.四川大學(xué)計(jì)算機(jī)學(xué)院,成都 610065)
隨著計(jì)算機(jī)硬件計(jì)算能力的快速發(fā)展,工業(yè)界針對(duì)游戲領(lǐng)域的真實(shí)感和實(shí)時(shí)性要求越來(lái)越高。而影響游戲中真實(shí)感最重要的因素就是光照。良好的實(shí)時(shí)光照算法可以改善游戲畫(huà)面渲染效果和提高用戶(hù)體驗(yàn)。使用基于物理的光照算法[2]幾乎能呈現(xiàn)出現(xiàn)實(shí)生活中的光照效果,但是往往不能達(dá)到實(shí)時(shí)性的要求。現(xiàn)在的實(shí)時(shí)渲染[1]基本使用延遲光照(Deferred Lighting)[4-5]的算法來(lái)提高效率,但是延遲光照中不能處理透明物體的光照效果。本文采用光源鏈表的方式以統(tǒng)一地渲染三維場(chǎng)景中不同透明程度的幾何對(duì)象。
隨著光源數(shù)量和場(chǎng)景復(fù)雜度提高,前向渲染(Forward Shading)[9]算法并不能高效進(jìn)行光照計(jì)算。而延遲渲染算法通過(guò)解耦幾何計(jì)算和光照計(jì)算,可以大幅度提高渲染效率。但在延遲光照中,幾何緩沖區(qū)只能保存的是深度值最小片元(Fragment)的信息。如果在同一個(gè)像素位置同時(shí)存在透明片元和不透明片元,并且透明片元在前,那么幾何緩沖區(qū)不能同時(shí)保存多個(gè)片元信息,從而沒(méi)法同時(shí)渲染透明和不透明物體。普通做法不渲染透明物體或者額外的前向渲染透明物
延遲光照是屏幕空間渲染技術(shù),避免渲染被遮擋的片元。第一個(gè)渲染過(guò)程(Render Pass)中沒(méi)有對(duì)場(chǎng)景幾何體進(jìn)行光照計(jì)算,僅僅是保存幾何體表面信息到幾何緩沖區(qū)(G-Buffer),例如顏色,紋理,法線等。第二階段在圖像采樣位置,發(fā)現(xiàn)可見(jiàn)性表面后再進(jìn)行光照計(jì)算。不同于前向渲染方法,延遲渲染的光照計(jì)算是獨(dú)立于場(chǎng)景復(fù)雜度。前向渲染卻會(huì)根據(jù)場(chǎng)景中所有光源渲染每個(gè)幾何體,在最差的情況,可能帶來(lái)的效率O(M×N),其中M代表M個(gè)物體,N代表N個(gè)光源。而延遲渲染只需要O(M+N)時(shí)間效率。
體。光源鏈表的實(shí)時(shí)光照算法,具體思想是每個(gè)片元構(gòu)建光源鏈表,光源加入到當(dāng)前片元的鏈表中。接著,通過(guò)訪問(wèn)光源鏈表,如果片元的世界坐標(biāo)系的位置位于光源影響范圍內(nèi),從而計(jì)算當(dāng)前片元的光照效果。
雖然延遲光照可以很好渲染動(dòng)態(tài)多光源場(chǎng)景,但是它并不能渲染透明物體和粒子特效。延遲光照算法中,普通做法是不渲染透明物體或者增加額外的前向渲染過(guò)程。如果不渲染透明物體,那么場(chǎng)景看起來(lái)不真實(shí);額外的前向渲染會(huì)增加系統(tǒng)的復(fù)雜性和降低渲染效率。本文的光源鏈表(Light Linked List,LLL)[10]方法僅計(jì)算被每個(gè)光源影響的片元,不用區(qū)分透明物體和不透明物體,因此可以同時(shí)渲染透明和不透明幾何體。而且,任何沒(méi)被寫(xiě)深度緩沖區(qū)的幾何體也能訪問(wèn)光源資源,進(jìn)而進(jìn)行光照計(jì)算。LLL算法要求顯卡支持無(wú)序訪問(wèn)視圖(Unordered Access Views,UAV)和原子計(jì)算器(Atomic Counter)。
LLL本質(zhì)是GPU鏈表[6-8],每個(gè)鏈表元素需要保存光源最小最大深度值,光源索引和Next指針。保存這些信息需要使用三個(gè)UAV資源:
(1)LightFragmentLinkedBuffer:光源鏈表緩存。存放完整的光源鏈表元素信息,結(jié)構(gòu)體偽代碼定義如Algorithm2-1所示。
(2)LightBoundBuffer:光源深度范圍緩存。光源幾何體最大最小深度值需要兩次調(diào)用生成,因此要臨時(shí)保存光源深度值和索引,下次用來(lái)匹配填充完整的鏈表元素信息。
(3)LightStartOffsetBuffer:光源頭指針緩存。保存當(dāng)前屏幕像素光源鏈表的頭指針,需要使用原子計(jì)算器作為分配鏈表指針的工具。
Algorithm 2-1:光源鏈表結(jié)構(gòu)體struct SLightFragmentLinkedList{
uint m_LightIndex;
float m_LightMinDepth;
float m_LightMaxDepth;
uint m_Next;};
LLL算法步驟主要分為光源鏈表的構(gòu)建和訪問(wèn)。首先對(duì)所有光源覆蓋的片元構(gòu)建鏈表,因?yàn)閳?chǎng)景幾何體處于光源幾何體(Light Volume)內(nèi),會(huì)遮擋光源幾何體背面,所以需要關(guān)閉硬件深度測(cè)試。而要保存光源幾何體最小最大深度值,需要兩遍軟件深度測(cè)試,第一遍打開(kāi)背面裁剪,第二遍打開(kāi)前面裁剪,構(gòu)建的光源鏈表信息保存到LightFragmentLinkedBuffer。然后渲染透明和不透明物體,并且遍歷當(dāng)前片元的光源鏈表,如果幾何體的深度值處于最小最大深度值區(qū)間內(nèi),那么對(duì)幾何體進(jìn)行光照渲染。
渲染不透明幾何體,保存最小深度值片元的幾何信息。各個(gè)保存的幾何信息必須處于同一空間坐標(biāo)下,本文中保存的是世界坐標(biāo)系下的位置,材質(zhì)顏色,以及世界坐標(biāo)系下的法線。如果想降低GPU內(nèi)存使用率,可以把世界坐標(biāo)系下的位置紋理,改變?yōu)镹DC(Normalized Device Coordinates)空間下只有一個(gè)通道的深度紋理,并且深度值映射到[0,1]區(qū)間。
世界坐標(biāo)系位置信息需要三個(gè)浮點(diǎn)數(shù)通道紋理,而深度信息只需要一個(gè)浮點(diǎn)通道紋理。在后期的渲染階段,可以通過(guò)矩陣轉(zhuǎn)換,把深度信息還原為位置信息。因?yàn)樯疃染彌_區(qū)的值是非線性,所以需要轉(zhuǎn)換深度值到線性的深度表達(dá)。公式(1)中,M代表矩陣,P代表幾何體頂點(diǎn)坐標(biāo)。
三維場(chǎng)景頂點(diǎn)經(jīng)過(guò)投影變換到裁剪空間坐標(biāo)系,除以齊次坐標(biāo)系w分量歸一化到NDC坐標(biāo)。經(jīng)過(guò)轉(zhuǎn)換深度值變?yōu)楣剑?)所示。
相機(jī)空間的z值總是投影到近平面,不依靠X,Y坐標(biāo)的影響,造成M13=M23=M14=M24=0,并且在OpenGL的投影矩陣中M34=-1,M44=0,因此最終轉(zhuǎn)換的相機(jī)空間下的z值如公式(3)所示。
(1)軟件深度測(cè)試
在渲染過(guò)不透明幾何體后,深度緩沖區(qū)已經(jīng)寫(xiě)入不透明物體的深度值。接著渲染光源幾何體可能會(huì)有圖1中的三種情況:光源被場(chǎng)景遮擋、光源與場(chǎng)景幾何體相交、光源在場(chǎng)景幾何體之前。
第一種情況光源幾何體深度測(cè)試失敗,完全被遮擋意味著看不見(jiàn)光照效果,因此光源幾何體不用加入到光源鏈表。第三種情況時(shí)深度測(cè)試成功,容易保存光源最大最小深度值。但是第二種情況,因?yàn)楣庠吹谋趁姹粓?chǎng)景遮擋,造成背面深度測(cè)試失敗,所以不能取得背面的深度值。為了保證光源結(jié)合體的背面被像素著色器處理,需要關(guān)閉硬件深度測(cè)試,在片元著色器中進(jìn)行軟件深度測(cè)試。
(2)分配鏈表
圖1 光源和場(chǎng)景幾何體
圖2 光源鏈表結(jié)構(gòu)初始圖
如圖2所示,LightFragmentLinkedBuffer結(jié)構(gòu)存儲(chǔ)最大最小深度值,幾何體的最小最大深度值被硬件光柵化,卻是在不同的時(shí)間傳送到片元著色器。光源幾何體的最小深度值等于光源正面的深度值,最大深度值等于光源背面的深度值。
第一遍Pass打開(kāi)背面裁剪,僅允許光柵化光源幾何體正面。在OpenGL的片元著色器中可以通過(guò)gl_FrontFacing判斷是否當(dāng)前三角片元是否為正面。當(dāng)前片元為正面時(shí)執(zhí)行軟件深度測(cè)試。并且比較當(dāng)前光源結(jié)合體的深度值和深度緩沖器的深度值,如果深度測(cè)試失敗,那么提前返回,不必接著做后續(xù)計(jì)算。光源索引可通過(guò)OpenGL原子計(jì)算器執(zhí)行遞增操作,每個(gè)片元都會(huì)得到唯一的正整數(shù)值。LightStartOffsetBuffer使用頭插法來(lái)更新頭指針鏈表。而LightFragmentLinkedBuffer寫(xiě)入光源的索引,最小深度值,以及Next指針。因?yàn)楝F(xiàn)在沒(méi)法得到光源幾何體的背面深度值,所以暫時(shí)不寫(xiě)入最大深度值。
第二遍Pass打開(kāi)正面裁剪,硬件光柵化光源幾何體的背面。因?yàn)長(zhǎng)ightStartOffsetBuffer紋理大小和窗口一致,所以可以通過(guò)轉(zhuǎn)換的紋理坐標(biāo)取紋理值得到頭指針。根據(jù)頭指針的索引取出LightFragmentLinked-Buffer的數(shù)據(jù),如果當(dāng)前渲染的光源幾何體的索引和緩沖區(qū)數(shù)據(jù)的光源索引一致,那么更新最大深度值,并且提前結(jié)束鏈表循環(huán)。
(3)鏈表訪問(wèn)
前向渲染和延遲渲染訪問(wèn)光源鏈表都是一樣的方式,LightStartOffsetBuffer取出當(dāng)前片元鏈表的頭指針?biāo)饕H绻^指針?biāo)饕行?,那么表明?dāng)前片元存在鏈表數(shù)據(jù)。根據(jù)頭指針?biāo)饕〕鯨ightFragmentLinked-Buffer的數(shù)據(jù),包含最小最大深度值,進(jìn)行簡(jiǎn)單的深度測(cè)試。如果當(dāng)前場(chǎng)景幾何體的深度值在光源幾何體的深度值區(qū)間,表明會(huì)被光源幾何體所影響,進(jìn)而進(jìn)行光照計(jì)算。如果位于區(qū)間外,結(jié)束本次渲染繼續(xù)進(jìn)行鏈表遍歷。最后計(jì)算出當(dāng)前片元被光源鏈表中光源的光照值,再用 HDR(High-Dynamic Range)[3]把光照結(jié)果映射到計(jì)算機(jī)所表示的顏色區(qū)間。
本文算法的運(yùn)行環(huán)境為:Intel Xeon CPU E3-1230 V2@3.30GHz的處理器,8G內(nèi)存,顯卡為NVIDIA Ge-Force 670和Windows 10的操作系統(tǒng),編程環(huán)境為Visual Studio 2012。
圖3 光源鏈表無(wú)序訪問(wèn)視圖
圖4 延遲光照和LLL算法效果對(duì)比
(1)效果分析
如圖4(a)所示,在傳統(tǒng)延遲光照渲染光線中,程序無(wú)法處理透明物體天馬。但是在圖4(b)中,光源鏈表算法統(tǒng)一了不透明物體和透明的物體的光照過(guò)程,使用相同的鏈表緩存來(lái)計(jì)算光照,因此圖中天馬帶有平行光和點(diǎn)光源的光照效果。
(2)效率分析
表1 LLL算法和DS+FS效率對(duì)比(單位:FPS)
表1可以看出,光源鏈表算法在多光源場(chǎng)景中可以提高延遲光照的性能。在少量光源時(shí),因?yàn)榻⒐庠葱枰~外花費(fèi)時(shí)間,所以少量光源場(chǎng)景時(shí)處理透明物體性能提升不明顯。而在多光源場(chǎng)景或者場(chǎng)景中存在多個(gè)透明物體時(shí)光源鏈表算法可以更好提升性能。因?yàn)檠舆t渲染管線需要多一個(gè)前向渲染繪制過(guò)程,其次前向渲染是沒(méi)有解耦光源和物體,最后對(duì)延遲渲染引擎也是一個(gè)額外的負(fù)擔(dān)。
光源鏈表算法統(tǒng)一了透明和不透明物體,光源數(shù)據(jù)都在顯存中,無(wú)需從CPU端到GPU端帶寬的占用。而且光源鏈表解耦光源和物體,只需要針對(duì)光源幾何體內(nèi)部做深度測(cè)試,通過(guò)片元就進(jìn)行光照,進(jìn)而提高了性能。
針對(duì)于三維場(chǎng)景中帶有透明物體或粒子等特效時(shí),光源鏈表算法能幫助簡(jiǎn)化了光照渲染管線。而且光源鏈表算法能改善延遲渲染的性能。除此之外,光源鏈表算法的靈活性容易集成傳統(tǒng)光照算法,例如材質(zhì)是皮膚、頭發(fā)、布料、汽車(chē)噴漆等。未來(lái)的工作考慮設(shè)計(jì)緩存并發(fā)的光源鏈表結(jié)構(gòu)體來(lái)進(jìn)一步提高性能。
參考文獻(xiàn):
[1]Tomas Akenine-Moller,Tomas Moller,and Eric Haines.Real-Time Rendering.A.K.Peters,Ltd.,Natick,MA,USA,2nd Edition,2002.
[2]Matt Pharr and Greg Humphreys.Physically Based Rendering,Second Edition:From Theory To Implementation.Morgan Kaufmann Publishers Inc.,San Francisco,CA,USA,2nd Edition,2010.
[3]Greg Ward et al.High Dynamic Range Image Encodings,2006.
[4]KOONCE,R.2008.Deferred Shading in Tabula Rasa.In GPU Gems 3,429-457.
[5]Deering,M;Winner,S;Schediwy,B.;Duffy,C.and Hunt,N.The Triangle Processor and Normal Vector Shader:A VLSI System for High Performance Graphics.In:Proceedings of the 15th Annual Conference on Computer Graphics and Interactive Techniques(SIGGRAPH 88).Vol.22,Issue 4.New York:The ACM Press,1988:21-30.
[6]Holger Gruen and Nicolas Thibieroz.Order Independent Transparency and Indirect Illumination Using Dx11 Linked Lists.Presentation at the Advanced D3D Day Tutorial,Game Developers Conference,San Francisco,CA,March 9-13,2010
[7]Nicolas Thibieroz.Order-Independent Transparency Using Per-Pixel Linked Lists.GPU Pro,2:409-431,2011.
[8]Jason C.Yang,Justin Hensley,Holger Grün,and Nicolas Thibieroz.Real-Time Concurrent Linked List Construction on the GPU.In Proceedings of the 21st Eurographics Conference on Rendering,EGSR'10,pages 1297-1304,Aire-la-Ville,Switzerland,Switzerland,2010.Eurographics Association.
[9]Markus Billeter,Ola Olsson,Ulf Assarsson.Tiled Forward Shading.GPU Pro 4:Advanced Rendering Techniques,4:99,2013
[10]Abdul Bezrati.Real-Time Lighting Via Light Linked List.Presentation at SIGGRAPH2014,2014.