1. 程式人生 > >unity3d渲染路徑整理

unity3d渲染路徑整理

方向光源是最不消耗GPU資源的。點光源的陰影較消耗GPU資源。聚光燈是較消耗GPU資源的。
Area light區域光源無法用於實時光照,只適用於光照貼圖烘培。
Cookie如果是平行光或聚光燈 那麼可以是2D的紋理遮罩貼圖,如果是點光源那麼cookie要是cubemap texture立方體紋理。

unity3d渲染路徑:

只有平行光在forward渲染模式下支援陰影,其它光源型別在player setting中設定Rendering path 為deferred模式下(4.x版本非移動平臺才支援)才能支援陰影。

1.vertex list rendered path:

硬體要求:Opengl es1.1以上
 就頂點光照顏色計算,顏色可進行插值,不支援畫素運算效果,如法線貼圖,陰影,Light cookies等。

2.forward rendered path: 

硬體要求:Opengl es2.0 shader modle2.0(DX9)以上
核心處理虛擬碼:
For each light: 
   For each object affected 
   by the light:        
	framebuffer += object * light
演算法複雜度:O(n^2)。
只有一個渲染目標(後臺顏色快取),支援有限的畫素級別光照(通常最亮的為important, 其它設定為not important),最多4個頂點光照,其它是SH近似光照計算。
假設有ABCD EFGH 由近到遠圍繞著物體。
也就是說,對於ABCD四個光源我們在Fragment Shader中我們對每個pixel處理光照,對於DEFG光源我們在Vertex Shader中對每個vertex處理光照,而對於GH光源,我們採用球調和(SH)函式進行處理。
渲染過程每個pass都是一個完整渲染drawcall:

Bass Pass: 

渲染一個畫素計算的方向光。以及所有頂點計算和SH方向光。之後每增加一個逐畫素計算的光都需要增加一個對應的pass.LightMap在此應用,在此步的方向光可以有陰影。

Additional Pass:

額外的畫素計算光,無陰影。也就是說Forward Lighting只支援一個有陰影的方向光。

SH: 

Spherical Harmonics,效率極高,不支援light cookies和法線貼圖,更新頻率慢,不支援鏡面反射。

缺點是:每增加一個燈光,就要增加相應的draw call渲染物體,當燈光數量很多場景很複雜時候CPUGPU計算壓力很大。
優點是:每個燈光渲染一次物體,物體每次通過多重取樣的光柵化,支援抗鋸齒;物體每次提交到後臺快取都是獨立的,可以進行blend 支援半透明物體的渲染,有限的燈光進行畫素級別光照支援法線貼圖,平行光陰影,light cookies等。

3.deferred rendered path:

硬體要求:Opengl es3.0 shader modle3.0(DX9c)以上
核心處理虛擬碼:
For each object:    
Render to multiple targets
For each light:     
Apply light as a 2D postprocess

演算法複雜度:O(n)

Deferred Rendering(延遲渲染)顧名思義,就是將光照處理這一步驟延遲一段時間再處理。具體做法就是將光照處理這一步放在已經三維物體生成二維圖片之後進行處理。也就是說將物空間的光照處理放到了像空間進行處理。要做到這一步,需要一個重要的輔助工具——G-Buffer。G-Buffer主要是用來儲存每個畫素對應的Position,Normal,Diffuse Color和其他Material parameters。根據這些資訊,我們就可以在像空間中對每個畫素進行光照處理。
DepthR32F
Normal + scatteringA2R10G10B10
Diffuse color + emissiveA8R8G8B8
Other material parametersA8R8G8B8
對於一個普通的1024x768的螢幕解析度,一個G-Buffer共得使用1024x768x128bit=20MB。如果要渲染更酷的特效,使用的G-Buffer大小將增加。存取G-Buffer耗費的頻寬也是一個不可忽視的缺陷。
儲存的G-buffers中有所有物體彙總的Z值(一個float 32位),材質Diffuse Color(可直接來自紋理),法線貼圖RGB和鏡面強度A(色澤),材質Specular Color(可直接來自紋理),紋理材質索引值(可以在shader中指定獲取)都是是唯一的快取物件;對每個燈光從光照入射角lightDir,視角方向viewDirection從shader中獲取,從不同的快取G-Buffer中獲取對應的紋理漫反射值,法線值,高光顏色值,進行光照的計算合成:

如漫反射顏色:

float3 lightDir = normalize(input.lightDir);
float3 diffuseReflection = attenuation * _LightColor0.rgb * resColor.rgb * max(0.0, dot(normalDir, lightDir));

 高光顏色:
計算鏡面高光需要viewDir也要轉換的切線空間中進行計算(deferred應該是在螢幕空間座標系中進行運算)。
 

specularReflection = attenuation * _LightColor0.rgb  * _SpecColor.rgb * 
pow( max(0.0, dot( reflect(-lightDirection, normalDirection),  viewDirection)), _Shininess);

最終光照顏色:
  
return float4(input.vertexLighting + ambientLighting + diffuseReflection + specularReflection, 1.0);

unity3d perferred渲染過程(其實是類似Light Pre-Pass形式)分為三個處理,組成完整的渲染drawcall:
Base Pass: 

繪製深度緩衝等裁剪空間的緩衝資訊。儲存在一張ARGB32 Render Texture中,RGB存該點法線,A存鏡面反射強度。如果深度能讀取為Texture的話,深度不會被顯式渲染。不能讀取的話,則使用著色器替換ShaderReplacement,即Camera.RenderWithShader。Base Pass的結果是,場景的物體附帶了深度緩衝,以及一張儲存法線和鏡面強度的Texture。
Lighting Pass: 
只支援Blinn-Phong光照模型,陰影也是在這一步計算。之前產生的緩衝在這一步用於計算光照。產生的光照緩衝同樣是一張ARGB32 Render Texture,RGB表漫反射光的顏色,A表單色鏡面光 。應該對光照資訊,可以使用blend混合。
Final Pass: 
將紋理顏色(來自外部檔案的紋理貼圖組合的大圖)與儲存的光照結果組合。LightMap在這一步被應用 注意:在Deferred Lighting的這一步完成後,才會到Forward Lighting。應該存在每個物體的z值和normal值可以很簡單的找到邊緣進行MSAA抗鋸齒操作。

缺點:

紋理合併為大圖,不真正支援反鋸齒(大圖邊界不清楚),不支援半透明(大圖在光照顏色前面合成,光照的alpha不能再參與混合)。如果是類似Light Pre-Pass形式應該可以支援部分抗鋸齒和半透明處理的。硬體至少是Shader Model 3.0 。延遲渲染在正交攝像機模式下也是不支援的,如果攝像機切換到了正交模式之後就會預設使用正向渲染。

優點:對複雜場景,很多光源情況下,有很好的渲染效能。


其它的deferred lighting渲染優化方式:

1).Light Pre-Pass

具體的做法是:

(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繪製的。這兩張圖在效果上不應該有太大區別。

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相比,減少了存取的頻寬。
 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耗費的時間沒有那麼多。Forward+的優勢還有很多,其實大多就是傳統Forward Rendering本身的優勢,所以Forward+更像一個集各種Rendering Path優勢於一體的Rendering Path。
整理自文章:
http://blog.csdn.net/onafioo/article/details/51882109
http://blog.csdn.net/lichaoguan/article/details/42554821
http://www.cnblogs.com/MrZivChu/p/RenderingPath.html