延遲渲染,及材質ID

轉自http://blog.csdn.net/pizi0475/article/details/7521394

技術背景

最近太懶了,打LOLRM這一塊都荒廢了下來,關於延遲渲染的RM工程其實個把月前寫好的,雜務所擾,一直沒有靜下心來整理,現在正值年關,終於可以繼續了,努力在接下來的幾周把接下來的Monkey計劃完成。

關於延遲渲染技術,在現階段的遊戲程序中正被越來越推廣使用,從PS3Xbox360的次時代,到暴雪的星際2,及最近效果完全征服我的戰地3,無一例外的使用了延遲渲染DeferredShadin(以下簡稱DSDeferredLightingDL技術暫不在這裏討論)

那麼傳說中的強大延遲渲染技術到底有何強大之處呢?!

其實,理論早在幾十年前就已經提出,實現也不難,真正的優勢,要從傳統的前向渲染(ForwardShadingFS)說起,下面引用一段介紹:

在TabulaRasa中,我們一開始的渲染引擎是基於最初的DX9而完成的傳統前向渲染技術(FS)的,使用了HLSL和D3DXEffect。我們的Effect使用了Pass裏的Annotation來描述這個Pass所支持的光照。而在CPU這邊,引擎可以算出來每個幾何體被那些光源所影響——這個信息連同那些在Pass的Annotation裏的信息一起,用於設置光源的參數、以及確定每個Pass該調用多少次。

這種前向着色有多種問題:

1,計算每個幾何體受那些光影響耗費了CPU的時間,更壞的是,這是個O(n*m)的操作。

2,Shader經常需要超過一次以上的Pass來渲染光照,渲染n個燈光,對於複雜的Shader,可能需要O(n)次運算。

3,增加新的光照模型和新的光源類型,可能需要改變所有Effect的源文件。

4,Shader很快就將達到或者超出SM2的指令限制。

在MMO裏,我們對遊戲環境很少會有過於苛求的要求。我們無法控制同屏可見的玩家數量、無法控制同屏會有多少特效和光源。由於傳統前向渲染缺乏對環境的控制,且對於光源的複雜度難於估量,因此我們選擇了延期着色。這可以讓我們的畫面更接近於當今頂尖的遊戲引擎,並且讓光照所耗費的資源獨立於場景的幾何複雜度。

延期着色提供了下面的好處:

1,光照所耗費的資源獨立於場景複雜度,這樣就不用再費盡心機去想着處理那些光源影響幾何體了。

2,不必要再爲幾何體的受光提供附加的Pass了,這樣就節省了DrawCall和狀態切換的數量。

3,在增加新的光源類型和光照模型時,材質的Shader不需要做出任何改變。

4,材質Shader不產生光照,這樣就節省了計算額外的幾何體的指令數。

         簡單的說,DS最大優勢便是在如今渲染模塊中PixelShader變得越來越複雜的情況下,能最大限度地節約硬件效能。

實現原理

延遲渲染管線可分爲倆個階段:Geometry,Lighting,當然如將GeometryBuffer中的豐富的信息僅僅用於光照點亮過程顯而易見不是俺們程序猿“雁過拔毛”的性格,所以通常各種Post-processing也會被被我們加入管線之中,這裏且不做深入。

鄙人很懶,相比碼字,更喜歡用代碼說話,所以這裏就雜糅一些別人的著說,後面再一一提名感謝,嘿嘿~~~

Geometry階段:將本幀所有的幾何信息(位置,法線,貼圖)光柵化到G-buffer

Lighting階段:以G-buffer作爲輸入(位置,法線)進行逐像素的光照計算,得到渲染結果。

DS整體渲染過程並不複雜,但問題往往出在細節,下面先一一列舉各個步驟。

G-buffer

Geometry階段將幾何信息渲染到MultiRenderTarget上(MRT),當前最多支持4MRT。並且驅動要求4MRT必須相同的bit寬度。RT對顯存佔用過大會增加帶寬,降低cache命中。而簡單格式的RT又會影響畫質。因此決定使用32bitRT(如A8R8G8B8R16G16F)或64bit寬度的RT(如A16R16G16B16F)。需要在畫質和性能間做出折衷。(開發時儘可能可以方便的配置)。中有一些性能比較。

光照計算

使用延遲渲染技術最大的好處就是可以渲染光照極爲複雜的場景。這裏場景中的光照可以分爲兩類。

影響整個場景的scenelight。如directionallight。渲染一個screenquad,逐像素光照計算,沒什麼好說的。

另一類是隻影響一部分區域的locallight。如點光源,聚光燈,以及特效等等。這些locallight隻影響到屏幕上的某些像素,當然不需要逐像素的進行光照計算。最簡單的方法是繪製這些光源的包圍體(點光源的包圍體是球,聚光燈的包圍體是圓錐),包圍體的大小要大於等於光源的衰減範圍。這些包圍體經過變換投影到屏幕上的對應區域,隨後在pixelshader中計算光照。

優化:

1.光源包圍體的視錐剔除,遮擋剔除。

2.光源包圍體投影后很小時剔除;若干個靠的比較近的小光源合併成一個較大的光源

3.光源包圍體的backfaceculling

4.屏幕空間中沒有被光源照到的,或者被更近的物體遮擋住的像素不需要光照計算,因此可以逐像素的深度剔除。

a.使用正確的stencillightvolume。類似shadowvolume的方案,將渲染lightvolume的正反兩面,得到正確的stencilmask,然後光照計算時使用stencilbuffer。這種方法可以得到正確的結果,但是需要渲染每盞燈時頻繁改變renderstate,可能會帶來一定性能上的損失。

b使用ztest,可以得到“一定程度上正確”的結果。

陰影

光照計算的同時計算陰影。使用傳統的shadowmap,預先生成一張陰影圖。考慮在編輯場景的時候指定那些重要的光源纔會產生陰影。在計算shadowmap時要針對光源的bindingvolume進行剔除。

方向光和聚光燈可以使用基本的shadowmap投影(正交投影,透視投影)。點光源會複雜一些,需要使用cubicshadowmap。(考慮unwrappingmethod[14]

半透明

由於在延遲渲染的過程中只計算離屏幕距離最近的那個像素的光照,因此無法處理半透明物體的光照。

方案1

延遲渲染的過程中只處理不透明的物體,將所有半透明的物體放在渲染過程的最後,使用傳統的forwardshading渲染。

方案2

Geometry階段將半透明的物體和背景逐像素的交織起來,將透明度放在一個單獨的通道中。按一般的方法計算光照。隨後在composition階段再根據透明度將透明物體和背景逐像素的混合起來。

優點:

光照一致性。半透明的物體也參加延遲渲染,可以接受多光源的光照。

簡單並且健壯。不需要單獨區分不透明物體和半透明物體,不需要單獨的半透明渲染管道。

速度快。只增加了710ps指令,兩張貼圖,只有約2%的性能損失。

缺點:

模糊。在半透明的物體上會有一點模糊,原因是在交織的過程中會有一定信息損失。

邊緣鋸齒。反交織的過程中半透明物體的邊緣會產生一些鋸齒。

只能有一層半透明。

多種材質

在延遲光照的過程中支持多種材質需要如下方案:

G-buffer階段輸出材質的IDG-buffer的一個通道中,隨後在lighting階段根據材質ID使用不同的光照函數計算光照。這種方案在sm3.0中使用動態分支的前提下可以很好的工作。

反鋸齒

Dx9API不支持反鋸齒的MRT(需要在後處理上自行解決AntiAlias)Dx10支持。

一種方案是使用超採樣,先渲染到大的RT上,再downsample到正常的大小,得到沒有鋸齒的結果。延遲渲染的效率跟分辨率有很大關係,因此這種方法會極大的降低性能,基本不可取。

另一種方案是使用“intelligentblur”,只模糊物體邊緣的像素:

根據相鄰像素的深度和法線提取物體邊界,然後對提取出的邊界進行模糊。模糊時要避免不正確的泄露。如後面物體的顏色泄露到前面的物體上。總體而言實現會較爲複雜。

另一種方案:pre-lighting

一種pre-zrenderingdeferredrendering的結合。G-buffer階段只保存depthnormal,然後計算光照信息到lightingbuffer,格式如下

LightColor.r*N.L*Att
LightColor.g*N.L*Att
LightColor.b*N.L*Att
R.V^n*N.L*Att

最後使用傳統的forwardshading再將整個場景渲染一遍,期間查詢lightingbuffer

與普通的deferredshading相比:

優點:

佔用帶寬小,第一遍渲染只輸出normaldepth是自動獲得的。可以用在較老的硬件平臺上,不需要MRT支持。對現有forwardshading管道改動較小,比較容易實現。

缺點:

整個場景需要渲染兩遍,相當於在pre-zforwardshading中間加了一個lightingstage

Resistance2,《GTAIV》,《MidnightClubLosAngeles》使用了這種技術。CryEngine3中也使用了這種方案。

RT選擇分配

MRT中必須的信息:position(depth),normal,diffuse(texture)

可能需要的信息:specular,power,emissive,ao,materialid這些信息需要在這4RT上用合理格式,合理的組織。這裏還可以就存儲空間和shader的複雜性做折衷。如只保存depth,然後在光照時計算position。以及用球面座標保存法線。以目前的資料得出的結論是應該儘可能地pack數據,減少內存佔用,多出來的若干條shader指令不會明顯影響性能。

         RT的預置,分配是需要針對實際使用而設計的,如何最大化地發揮每一個bit的作用,是一門需要不斷實踐的技術活。

clip_image002[4]

KillZone中的MRTf分佈管理

附上DX9SDK中對MRT的說明

MultipleRenderTargets(Direct3D9)

MultipleRenderTargets(MRT)referstotheabilitytorendertomultiplesurfaces(seeIDirect3D9Surface)withasingledrawcall.Thesesurfacescanbecreatedindependentlyofeachother.RendertargetscanbesetusingIDirect3DDevice9::SetRenderTarget.

Multiplerendertargetshavethefollowingrestrictions:

  • Allrendertargetsurfacesusedtogethermusthavethesamebitdepthbutcanbeofdifferentformats,unlesstheD3DPMISCCAPS_MRTINDEPENDENTBITDEPTHScapisset.
  • Allsurfacesofamultiplerendertargetshouldhavethesamewidthandheight.
  • Someimplementationscannotperformpost-pixelshaderoperationsonmultiplerendertargets,including:nodithering,alphatest,nofogging,noblendingormasking,exceptthez-testandstenciltest.Devicesthatcansupportpost-pixelshaderoperationssetthecapbittoD3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING.

WhentheD3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDINGcapisset,youmustfirstconsulttheIDirect3D9::CheckDeviceFormatwiththeUSAGE_QUERY_POSTPIXELSHADER_BLENDINGresultforthespecificsurfaceformat.Iffalse,nopost-pixelshaderblendingoperationswillbeavailableforthatspecificsurfaceformat.Iftrue,thedeviceisexpectedtoapplythesamestatetoallsimultaneousrendertargetsasfollows:

    • Alphablend:ThecolorvalueinoCiisblendedwiththeithrendertarget.
    • Alphatest:ComparisonwillhappenwithoC0.Ifthecomparisonfails,thepixeltestisterminatedforallrendertargets.
    • Fog:Rendertarget0willgetfogged.Otherrendertargetsareundefined.Implementationscanchoosetofogthemallusingthesamestate.
    • Dithering:Undefined.
  • Noantialiasingissupported.
  • Someoftheimplementationsdonotapplytheoutputwritemask(D3DRS_COLORWRITEENABLE).Thosethatcan,haveindependentcolorwritemasks.Thisisexpressedusinganewcapabilitybit.Thenumberofindependentcolorwritemasksavailablewillbeequaltothemaximumnumberofelementsthedeviceiscapableof.

RenderMonkey實踐

RenderMonkey中內置了一個簡單的DS範例工程,如下圖

clip_image004[3]

clip_image006[3]

可見,DS分成兩個Pss,分別實現了GeometryLighting過程。

 

clip_image008[3]

VetexShader中,輸出了世界變換座標,視角變換空間座標,及世界變換空間中的法向量。

clip_image010[3]

這裏的PixelShader中由於是簡單例子,只使用了兩個RT,分別輸出世界座標到RT0,輸出法向量到RT1

具體渲染過程可以由下清晰可見,有興趣地可以拿起筆算一下WorldPos,看一下紅黃藍綠黑白的分佈~

clip_image012[3]

 

ID材質標記

前面提到過MaterialID,這裏也對其做一個實現,順便深入下實際使用中的DS技術。

clip_image014[3]

在新的工程中,Geometry階段使用了兩個Pass,利用標記不同的Alpha值來來實現DS中兩中材質的渲染,當然,實際使用中,Alpha通道通常會被佔用,來存儲EmittColorSepcStrength等參數,這時候可以使用StencilBuffer來做標記~

在兩個Pass中標記材質直接使用了指定Alpha值,在Compostion中判斷值,但Float值是存在精度問題的,這裏借鑑了DriectX中工具函數的一個做法,加入一個Epsilon值,實現一個約等於的Equal函數,在DX10後,會有Int,就好多了~

clip_image016[3]

clip_image018[3]

         實現效果見下圖,在Composition中實現了純色,法線貼圖兩種材質~

clip_image020[3]

AntiAlias

關於抗鋸齒的問題,在KlayGE上看到一篇,拿來以饗讀者

Deferred Shading發明的一天起,anti-alias的問題就一直困擾着所有Deferred的方法。雖然很多無良的遊戲廠商直接在Deferred Rendering的遊戲裏不支持AA,但確實AA對提升畫面質量很有幫助。

Edge AA

Deferred的框架裏,很自然會想到用Edge AA來處理AA。其過程不外乎:

  1. 邊緣檢測,得到每個像素像邊緣的程度
  2. shader里根據像邊緣的程度來控制採樣座標

這本身並不是個複雜的過程,尤其是第二步,非常直截了當了,所以這裏集中討論的是如何進行邊緣檢測。

GPU Gems 2“Deferred Shading in STALKER”一文提供了一種邊緣檢測的方法,通過把周圍像素的法線差和深度差的和來判斷邊緣,由e_barrier這個參數來定義閾值和比例,而這個參數和分辨率有關。GPU Gems 3“Deferred Shading in Tabula Rasa”改進了這個過程,只判斷法線差和深度差最大和最小的兩組。由於只是局部的相對量而已,這樣就做到了和分辨率無關的邊緣檢測。KlayGE目前用的也是這種方法,得到的邊緣如下:

clip_image021[3]

Edge

另一個可能用於邊緣檢測的方法是,前面提到了如何恢復出每個pixelview space position,每個pixel取得周圍4pixel的位置之後,就可以直接cross得出一個normal,姑且稱爲screen space normal。如果一個像素是連續的,那麼這個normal就會很接近於G-Buffer中保存的normal,否則它們的方向就會差別很大。下圖爲G- Buffer中的normal

clip_image022[3]

Normal in G-Buffer

這是screen space計算出的normal

clip_image023[3]

Normal in screen space

把這兩個normal做一次dot,小於某個閾值的就認爲是邊緣,得到:

clip_image024[3]

Screen space normal based edge

利用硬件MSAA作邊緣檢測

前面提到的邊緣檢測結果雖然不錯,但其實都是是參數相關的。能否就用硬件的MSAA來做邊緣檢測呢?在Shader model 3.0以上的GPUvertex attribute插值的時候可以選擇centroid這個modifier。開啓了centroidattribute,會選擇覆蓋到的sample中心來插值,而不是像素中心。所以,同一個屬性,如果即有centroid又有不帶centroid的版本都傳給pixel shader,在pixel shader裏面判斷兩者不一致,就表示這個pixel在邊緣上。這樣的話,邊緣的情況就和硬件MSAA完全一致了。但其實MSAA會過渡判斷邊緣,所有三角形的邊緣都會被認出來,即便只是物體內部的。所以謹慎使用。

能不能就用MSAA

前面討論了那麼多都是基於EdgeAA。在Deferred Lighting框架下,難道就不能直接用MSAA?可以!這也是Deferred LightingDeferred Shading優秀的方面之一。Deferred Shading不能直接MSAA的本質原因是在G-Buffer之後,物體幾何信息全部拋棄了。相比Deferred Lighting,在shading pass,物體會被再次渲染一遍,這個時候還是有幾何信息的,如果在shading pass打開了MSAA,就可以像Forward shading那樣利用硬件MSAA了。唯一不同的是,光照來自於lighting passtexture,而不是從光源計算。就算硬件MSAA,也只是每個pixel執行一次pixel shader,在按照覆蓋情況寫入sample的,所以在這裏視覺上幾乎和Forward shading一樣。

實際使用DS

到目前爲止,這裏都是很淺顯的理論探究,自己做了一個簡單地實現,同時渲染幾十盞燈光都可以輕易地保持高FPS,這在傳統的FS體系中是難以想象的,so,感受到DS技術的吸引力了吧?!

clip_image026[3]

閉門造車是難以前進的,多借鑑下成功的實際項目纔是王道,載錄若干如下,其它更多詳見最後的附錄:

clip_image028[3]

Cryengine渲染引擎剖析》

 

clip_image030[3]

<星際爭霸2>引擎技術解析》

載錄引用地址

延遲渲染技術文獻摘錄

http://blog.csdn.net/Garuda/article/details/5273106

TabulaRasa中的延遲着色技術

http://blog.csdn.net/noslopforever/article/details/3951273

《延遲渲染-KlayGE

http://www.klayge.org/wiki/

其它相關內容

工欲善其事必先利其器,除了必要的實踐,在原理上上做足功課亦是非常重要,下面將相關的文章引用列如下:

[1]DeferredShadingDemo

http://www.puzzledhero.com/projects/pages/deferred_shading_demo.htm

[2]Deferredshading2dx10                             

http://www.humus.name/index.php?page=3D&ID=81

[3]gpugems2Chapter9.DeferredShadinginS.T.A.L.K.E.R.

http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter09.html

[4]Hargreaves,Shawn,andMarkHarris.2004."DeferredShading."Presentation.

http://download.nvidia.com/developer/presentations/2004/6800_Leagues/6800_Leagues_Deferred_Shading.pdf

[5]Chapter19.DeferredShadinginTabulaRasa

http://http.developer.nvidia.com/GPUGems3/gpugems3_ch19.html

[6]DeferredShadingTutorial.

http://fabio.policarpo.nom.br/docs/Deferred_Shading_Tutorial_SBGAMES2005.pdf.

[7]Deferredrenderingtransparency

Shaderx7

[8]DesigningaRendererformultiplelights:ThelightPre-PassRenderer

Shaderx7

[9]LightPre-PassDeferredLighting:LatestDevelopmentWolfgangEngel

http://www.bungie.net/images/Inside/publications/siggraph/Engel/LightPrePass.ppt

[10]deferred-shading-aa-alpha-blending-demo

http://null-ptr.blogspot.com/2009/01/deferred-shading-aa-alpha-blending-demo.html

[11]overcomingdeferredshadingdrawbacks

shaderx5

[12]Reconstructingpixel3Dpositionfromdepth

http://www.gamedev.net/community/forums/topic.asp?topic_id=474166

[13]StoringNormalsUsingSphericalCoordinates

http://mynameismjp.wordpress.com/2009/06/17/storing-normals-using-spherical-coordinates/

[14]Efficientomnidirectionalshadowmaps

Shaderx3

[15]DeferredShadingShawnHargreaves

http://www.talula.demon.co.uk/DeferredShading.pdf

[17]Pre-lightinginResistance2MarkLee

http://cmpmedia.vo.llnwd.net/o1/vault/gdc09/slides/gdc09_insomniac_prelighting.pdf

[18]DeferredRenderinginKillzone2

http://www.guerrilla-games.com/publications/dr_kz2_rsx_dev07.pdf

[19]DeferredShadingShines.DeferredLighting?NotSoMuch.

http://gameangst.com/?p=141

[20]WikiDeferredshading

http://en.wikipedia.org/wiki/Deferred_shading

工程下載

/Files/hmxp8/DeferredShading_V1.1.rar

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章