【原】實時渲染中經常使用的幾種Rendering Path

【原】實時渲染中經常使用的幾種Rendering Path

本文轉載請註明出處 —— polobymulberry-博客園html

本文爲個人圖形學大做業的論文部分,介紹了一些Rendering Path,比較簡單,若有錯誤,請你們指正。原文pdf:請點擊此處下載編程

1. rendering path的技術基礎


在介紹各類光照渲染方式以前,首先必須介紹一下現代的圖形渲染管線。這是下面提到的幾種Rendering Path的技術基礎。緩存

image

目前主流的遊戲和圖形渲染引擎,包括底層的API(如DirectX和OpenGL)都開始支持現代的圖形渲染管線。現代的渲染管線也稱爲可編程管線(Programmable Pipeline),簡單點說就是將之前固定管線寫死的部分(好比頂點的處理,像素顏色的處理等等)變成在GPU上能夠進行用戶自定義編程的部分,好處就是用戶能夠自由發揮的空間增大,缺點就是必須用戶本身實現不少功能。數據結構

下面簡單介紹下可編程管線的流程。以OpenGL繪製一個三角形舉例。首先用戶指定三個頂點傳給Vertex Shader。而後用戶能夠選擇是否進行Tessellation Shader(曲面細分可能會用到)和Geometry Shader(能夠在GPU上增刪幾何信息)。緊接着進行光柵化,再將光柵化後的結果傳給Fragment Shader進行pixel級別的處理。最後將處理的像素傳給FrameBuffer並顯示到屏幕上。框架

2. 幾種經常使用的Rendering Path


Rendering Path其實指的就是渲染場景中光照的方式。因爲場景中的光源可能不少,甚至是動態的光源。因此怎麼在速度和效果上達到一個最好的結果確實很困難。以當今的顯卡發展爲契機,人們才衍生出了這麼多的Rendering Path來處理各類光照。函數

2.1 Forward Rendering

image

Forward Rendering是絕大數引擎都含有的一種渲染方式。要使用Forward Rendering,通常在Vertex Shader或Fragment Shader階段對每一個頂點或每一個像素進行光照計算,而且是對每一個光源進行計算產生最終結果。下面是Forward Rendering的核心僞代碼[1]。工具

For each light:
    For each object affected by the light:
        framebuffer += object * light

好比在Unity3D 4.x引擎中,對於下圖中的圓圈(表示一個Geometry),進行Forward Rendering處理。post

image

將獲得下面的處理結果優化

image

也就是說,對於ABCD四個光源咱們在Fragment Shader中咱們對每一個pixel處理光照,對於DEFG光源咱們在Vertex Shader中對每一個vertex處理光照,而對於GH光源,咱們採用球調和(SH)函數進行處理。spa

Forward Rendering優缺點

很明顯,對於Forward Rendering,光源數量對計算複雜度影響巨大,因此比較適合戶外這種光源較少的場景(通常只有太陽光)。

可是對於多光源,咱們使用Forward Rendering的效率會極其低下。由於若是在vertex shader中計算光照,其複雜度將是 ,而若是在fragment shader中計算光照,其複雜度爲 。可見光源數目和複雜度是成線性增加的。

對此,咱們須要進行必要的優化。好比

  • 1.多在vertex shader中進行光照處理,由於有一個幾何體有10000個頂點,那麼對於n個光源,至少要在vertex shader中計算10000n次。而對於在fragment shader中進行處理,這種消耗會更多,由於對於一個普通的1024x768屏幕,將近有8百萬的像素要處理。因此若是頂點數小於像素個數的話,儘可能在vertex shader中進行光照。
  • 2.若是要在fragment shader中處理光照,咱們大可沒必要對每一個光源進行計算時,把全部像素都對該光源進行處理一次。由於每一個光源都有其本身的做用區域。好比點光源的做用區域是一個球體,而平行光的做用區域就是整個空間了。對於不在此光照做用區域的像素就不進行處理。可是這樣作的話,CPU端的負擔將加劇,由於要計算做用區域。
  • 3.對於某個幾何體,光源對其做用的程度是不一樣,因此有些做用程度特別小的光源能夠不進行考慮。典型的例子就是Unity中只考慮重要程度最大的4個光源。

2.2 Deferred Rendering

 

image

Deferred Rendering(延遲渲染)顧名思義,就是將光照處理這一步驟延遲一段時間再處理。具體作法就是將光照處理這一步放在已經三維物體生成二維圖片以後進行處理。也就是說將物空間的光照處理放到了像空間進行處理。要作到這一步,須要一個重要的輔助工具——G-Buffer。G-Buffer主要是用來存儲每一個像素對應的Position,Normal,Diffuse Color和其餘Material parameters。根據這些信息,咱們就能夠在像空間中對每一個像素進行光照處理[3]。下面是Deferred Rendering的核心僞代碼。

For each object: 
    Render to multiple targets 
For each light: 
    Apply light as a 2D postprocess

下面簡單舉個例子[1]。

首先咱們用存儲各類信息的紋理圖。好比下面這張Depth Buffer,主要是用來肯定該像素距離視點的遠近的。

image

圖. Depth Buffer

根據反射光的密度/強度分度圖來計算反射效果。

image

圖.Specular Intensity/Power

下圖表示法向數據,這個很關鍵。進行光照計算最重要的一組數據。

image

圖.Normal Buffer

下圖使用了Diffuse Color Buffer。

image

圖.Diffuse Color Buffer

這是使用Deferred Rendering最終的結果。

image

圖.Deferred Lighting Results

Deferred Rendering的最大的優點就是將光源的數目和場景中物體的數目在複雜度層面上徹底分開。也就是說場景中不論是一個三角形仍是一百萬個三角形,最後的複雜度不會隨光源數目變化而產生巨大變化。從上面的僞代碼能夠看出deferred rendering的複雜度爲 。

可是Deferred Rendering侷限性也是顯而易見。好比我在G-Buffer存儲如下數據

Depth

R32F

Normal + scattering

A2R10G10B10

Diffuse color + emissive

A8R8G8B8

Other material parameters

A8R8G8B8

這樣的話,對於一個普通的1024x768的屏幕分辨率。總共得使用1024x768x128bit=20MB,對於目前的動則上GB的顯卡內存,可能不算什麼。可是使用G-Buffer耗費的顯存仍是不少的。一方面,對於低端顯卡,這麼大的顯卡內存確實很耗費資源。另外一方面,若是要渲染更酷的特效,使用的G-Buffer大小將增長,而且其增長的幅度也是很可觀的。順帶說一句,存取G-Buffer耗費的帶寬也是一個不可忽視的缺陷。

對於Deferred Rendering的優化也是一個頗有挑戰的問題。下面簡單介紹幾種下降Deferred Rendering存取帶寬的方式。最簡單也是最容易想到的就是將存取的G-Buffer數據結構最小化,這也就衍生出了light pre-pass方法。另外一種方式是將多個光照組成一組,而後一塊兒處理,這種方法衍生了Tile-based deferred Rendering。

2.2.1 Light Pre-Pass

Light Pre-Pass最先是由Wolfgang Engel在他的博客[2]中提到的。具體的作法是

  • (1)只在G-Buffer中存儲Z值和Normal值。對比Deferred Render,少了Diffuse Color, Specular Color以及對應位置的材質索引值。
  • (2)在FS階段利用上面的G-Buffer計算出所必須的light properties,好比Normal*LightDir,LightColor,Specular等light properties。將這些計算出的光照進行alpha-blend並存入LightBuffer(就是用來存儲light properties的buffer)。
  • (3)最後將結果送到forward rendering渲染方式計算最後的光照效果。

相對於傳統的Deferred Render,使用Light Pre-Pass能夠對每一個不一樣的幾何體使用不一樣的shader進行渲染,因此每一個物體的material properties將有更多變化。這裏咱們能夠看出相對於傳統的Deferred Render,它的第二步(見僞代碼)是遍歷每一個光源,這樣就增長了光源設置的靈活性,而Light Pre-Pass第三步使用的實際上是forward rendering,因此能夠對每一個mesh設置其材質,這二者是相輔相成的,有利有弊。另外一個Light Pre-Pass的優勢是在使用MSAA上頗有利。雖然並非100%使用上了MSAA(除非使用DX10/11的特性),可是因爲使用了Z值和Normal值,就能夠很容易找到邊緣,並進行採樣。

下面這兩張圖,左邊是使用傳統Deferred Render繪製的,右邊是使用Light Pre-Pass繪製的。這兩張圖在效果上不該該有太大區別。

image image

2.2.2 Tile-Based Deferred Rendering

TBDR主要思想就是將屏幕分紅一個個小塊tile。而後根據這些Depth求得每一個tile的bounding box。對每一個tile的bounding box和light進行求交,這樣就獲得了對該tile有做用的light的序列。最後根據獲得的序列計算所在tile的光照效果。[4][5]

對比Deferred Render,以前是對每一個光源求取其做用區域light volume,而後決定其做用的的pixel,也就是說每一個光源要求取一次。而使用TBDR,只要遍歷每一個pixel,讓其所屬tile與光線求交,來計算做用其上的light,並利用G-Buffer進行Shading。一方面這樣作減小了所需考慮的光源個數,另外一方面與傳統的Deferred Rendering相比,減小了存取的帶寬。

2.3 Forward+

Forward+ == Forward + Light Culling[6]。Forward+很相似Tiled-based Deferred Rendering。其具體作法就是先對輸入的場景進行z-prepass,也就是說關閉寫入color,只向z-buffer寫入z值。注意此步驟是Forward+必須的,而其餘渲染方式是可選的。接下來來的步驟和TBDR很相似,都是劃分tiles,並計算bounding box。只不過TBDR是在G-Buffer中完成這一步驟的,而Forward+是根據Z-Buffer。最後一步其實使用的是forward方式,即在FS階段對每一個pixel根據其所在tile的light序列計算光照效果。而TBDR使用的是基於G-Buffer的deferred rendering。

實際上,forward+比deferred運行的更快。咱們能夠看出因爲Forward+只要寫深度緩存就能夠,而Deferred Render除了深度緩存,還要寫入法向緩存。而在Light Culling步驟,Forward+只須要計算出哪些light對該tile有影響便可。而Deferred Render還在這一部分把光照處理給作了。而這一部分,Forward+是放在Shading階段作的。因此Shading階段Forward+耗費更多時間。可是對目前硬件來講,Shading耗費的時間沒有那麼多。

image

Forward+的優點還有不少,其實大多就是傳統Forward Rendering自己的優點,因此Forward+更像一個集各類Rendering Path優點於一體的Rendering Path。

image

3. 總結


首先咱們列出Rendering Equation,而後對比Forward Rendering,Deferred Rendering和Forward+ Rendering[6]。

3.1 Rendering Equation

其中點 處有一入射光,其光強爲 ,入射角度爲 。根據函數 和 來計算出射角爲 處的出射光強度。最後在輔以出射光的相對於視點可見性 。注意此處的 爲場景中總共有 個光源。

image

3.2 Forward Renderng

因爲Forward自己對多光源支持力度不高,因此此處對於每一個點 的處理再也不考慮全部的 個光源,僅僅考慮少許的或者說通過挑選的 個光源。能夠看出這樣的光照效果並不完美。另外,每一個光線的 是計算不了的。

image

3.3 Deferred Rendering

因爲Deferred Rendering使用了light culling,因此不用遍歷場景中的全部光源,只需遍歷通過light culling後的 個光源便可。而且Deferred Rendering將計算BxDF的部分單獨分出來了。

image

3.4 Forward+ Rendering

能夠看出Forward+和Forward最大區別就是光源的挑選上有了很到改進。

image

參考文獻

[1] Shawn Hargreaves. (2004) 「Deferred Shading」. [Online] Available:

http://hall.org.ua/halls/wizzard/books/articles-cg/DeferredShading.pdf (April 15,2015)

[2] Wolfgang Engel. (March 16, 2008) 「Light Pre-Pass Renderer」. [Online] Available:

http://diaryofagraphicsprogrammer.blogspot.com/2008/03/light-pre-pass-renderer.html(April 14,2015)

[3] Klint J. Deferred Rendering in Leadwerks Engine[J]. Copyright Leadwerks Corporation, 2008.

[4] 龔敏敏.(April 22, 2012) 「Forward框架的逆襲:解析Forward+渲染」. [Online] Available:

http://www.cnblogs.com/gongminmin/archive/2012/04/22/2464982.html(April 13,2015)

[5] Lauritzen A. Deferred rendering for current and future rendering pipelines[J]. SIGGRAPH Course: Beyond Programmable Shading, 2010: 1-34.

[6] Harada T, McKee J, Yang J C. Forward+: Bringing deferred lighting to the next level[J]. 2012.

相關文章
相關標籤/搜索