Unity中的三種渲染路徑

畅知發表於2024-09-16

Unity中的渲染路徑

Unity的渲染路徑

在Unity裡,渲染路徑(Rendering Path)決定了光照是如何應用到Unity Shader中的。因此,我們只有為Shader正確地選擇和設定了需要的渲染路徑,該shader的光照計算才可以被正確執行。

unity中的渲染路徑:

  • Forward Rendering Path (向前渲染路徑)
  • Deferred Rendering Path (延遲渲染路徑) 【新的版本已替換老版本】
  • Vertex Lit Rendering Path (頂點渲染路徑)【Unity 5.X之後已被拋棄】

大多數情況下,一個專案只會使用一種渲染路徑。

Forward Rendering Path (向前渲染路徑)

前向渲染路徑是傳統的渲染方式,也是我們最常用的一種渲染路徑。

向前渲染路徑原理:

在進行一次完整的向前渲染過程中,我們需要渲染該物件的渲染圖元,並計算兩個緩衝區的資訊:顏色緩衝區和深度緩衝區。利用深度緩衝來確定一個片元是否是可見的,如果可見就更新顏色緩衝區中的顏色值。

Pass  {
	for  (each  primitive  in  this  model)  {
		for  (each  fragment  covered  by  this  primitive)  {
			if  (failed  in  depth  test)  {
				// 如果沒有透過深度測試,說明該片元是不可見的
				discard;
              }  else  {
				// 如果該片元可見
				// 就迚行光照計算
				float4  color  =  Shading(materialInfo,  pos,  normal,  lightDir,  viewDir);
				// 更新幀緩衝
				writeFrameBuffer(fragment,  color);
				}
		}
	}
}

對於每個逐畫素光源,我們都需要進行上面一次完整的渲染流程。

如果一個物體在多個逐畫素光源的影響區域內,那麼該物體就需要執行多個Pass,每個Pass計算一個逐畫素光源的光照結果,然後在幀緩衝中把這些光照結果混合起來得到最終的顏色值。

Unity中的向前渲染:

Unity中向前渲染路徑的3種處理光照的方式:

逐頂點處理、逐畫素處理和球諧函式(Spherical Harmonics,SH)處理。

而決定一個光源使用哪種處理模式取決於它的型別和渲染模式。

光照型別:指該光源是平行光還是其它型別光源

光源的渲染模式:是否是Important

在前向渲染中,當我們渲染一個物體時,Unity會根據場景中各個光源的設定以及這些光源對物體的影響程度(例如,距離該物體的遠近、光源強度等)對這些光源進行一個重要度排序。其中,一定數目的光源會按逐畫素的方式處理,然後最多有4個光源按逐頂點的方式處理,剩下的光源可以按SH方式處理。

  • 場景中最亮的平行光總是按逐畫素處理的。
  • 渲染模式被設定成Not Important的光源,會按逐頂點或者SH處理。
  • 渲染模式被設定成Important的光源,會按逐畫素處理。
  • 如果根據以上規則得到的逐畫素光源數量小於Quality Setting中的逐畫素光源數量(Pixel Light Count),會有更多的光源以逐畫素的方式進行渲染。

img

向前渲染中的兩種Pass ,在Pass中進行光照計算。

對於前向渲染來說,一個Unity Shader通常會定義一個Base Pass(Base Pass也可以定義多次,例如需要雙面渲染等情況)以及一個Additional Pass。

一個Base Pass僅會執行一次(定義了多個Base Pass的情況除外),而一個Additional Pass會根據影響該物體的其他逐畫素光源的數目被多次呼叫,即每個逐畫素光源會執行一次Additional Pass。

Vertex Lit Rendering Path (頂點渲染路徑)

頂點照明渲染路徑是對硬體配置要求最少、運算效能最高,但同時也是得到的效果最差的一種型別,它不支援那些逐畫素才能得到的效果,例如陰影、法線對映、高精度的高光反射等。實際上,它僅僅是前向渲染路徑的一個子集,也就是說,所有可以在頂點照明渲染路徑中實現的功能都可以在前向渲染路徑中完成。

如果選擇使用頂點照明渲染路徑,那麼Unity會只填充那些逐頂點相關的光源變數,意味著我們不可以使用一些逐畫素光照變數。

Unity中的頂點照明渲染:

頂點照明渲染路徑通常在一個Pass中就可以完成對物體的渲染。在這個Pass中,我們會計算我們關心的所有光源對該物體的照明,並且這個計算是按逐頂點處理的。這是Unity中最快速的渲染路徑,並且具有最廣泛的硬體支援(但是遊戲機上並不支援這種路徑)。

可訪問的內建變數和函式:

在Unity中,我們可以在一個頂點照明的Pass中最多訪問到8個逐頂點光源。

img

頂點照明渲染路徑中可以使用的內建變數

img

頂點照明渲染路徑中可以使用的內建函式

Deferred Rendering Path (延遲渲染路徑)

延遲渲染是一種更古老的渲染方法,但由於上述前向渲染可能造成的瓶頸問題,近幾年又流行起來。

除了前向渲染中使用的顏色緩衝和深度緩衝外,延遲渲染還會利用額外的緩衝區,這些緩衝區也被統稱為G緩衝(G-buffer),其中G是英文Geometry的縮寫。G緩衝區儲存了我們所關心的表面(通常指的是離攝像機最近的表面)的其他資訊,例如該表面的法線、位置、用於光照計算的材質屬性等。

延遲渲染的原理:

延遲渲染主要包含了兩個Pass。

在第一個Pass中,我們不進行任何光照計算,而是僅僅計算哪些片元是可見的,這主要是透過深度緩衝技術來實現,當發現一個片元是可見的,我們就把它的相關資訊儲存到G緩衝區中。

然後,在第二個Pass中,我們利用G緩衝區的各個片元資訊,例如表面法線、視角方向、漫反射係數等,進行真正的光照計算。

        Pass  1  {
            // 第一個Pass不迚行真正的光照計算
            // 僅僅把光照計算需要的資訊儲存到G緩衝中

            for  (each  primitive  in  this  model)  {

              for  (each  fragment  covered  by  this  primitive)  {
                  if  (failed  in  depth  test)  {
                    // 如果沒有透過深度測試,說明該片元是不可見的
                    discard;
                  }  else  {
                    // 如果該片元可見
                    // 就把需要的資訊儲存到G緩衝中
                    writeGBuffer(materialInfo,  pos,  normal,  lightDir,  viewDir);
                  }
              }
          }
        }

        Pass  2  {
          // 利用G緩衝中的資訊迚行真正的光照計算

          for  (each  pixel  in  the  screen)  {
              if  (the  pixel  is  valid)  {
                  // 如果該畫素是有效的
                  // 讀取它對應的G緩衝中的資訊
                  readGBuffer(pixel,  materialInfo,  pos,  normal,  lightDir,  viewDir);

                  // 根據讀取到的資訊迚行光照計算
                  float4  color  =  Shading(materialInfo,  pos,  normal,  lightDir,  viewDir);
                  // 更新幀緩衝
                  writeFrameBuffer(pixel,  color);
              }
          }
        }

延遲渲染使用的Pass數目通常就是兩個,這跟場景中包含的光源數目是沒有關係的。

換句話說,延遲渲染的效率不依賴於場景的複雜度,而是和我們使用的螢幕空間的大小有關。

這是因為,我們需要的資訊都儲存在緩衝區中,而這些緩衝區可以理解成是一張張2D影像,我們的計算實際上就是在這些影像空間中進行的。

Unity中的延遲渲染:

Unity有兩種延遲渲染路徑,一種是遺留的延遲渲染路徑,即Unity 5之前使用的延遲渲染路徑,而另一種是Unity5.x中使用的延遲渲染路徑。如果遊戲中使用了大量的實時光照,那麼我們可能希望選擇延遲渲染路徑,但這種路徑需要一定的硬體支援。

對於延遲渲染路徑來說,它最適合在場景中光源數目很多、如果使用前向渲染會造成效能瓶頸的情況下使用。而且,延遲渲染路徑中的每個光源都可以按逐畫素的方式處理。

延遲渲染的缺點:

  • 不支援真正的抗鋸齒(anti-aliasing)功能。
  • 不能處理半透明物體。
  • 對顯示卡有一定要求。如果要使用延遲渲染的話,顯示卡必須支援MRT(Multiple Render Targets)、Shader Mode 3.0及以上、深度渲染紋理以及雙面的模板緩衝。

Unity要求我們提供兩個Pass。

(1)第一個Pass用於渲染G緩衝。在這個Pass中,我們會把物體的漫反射顏色、高光反射顏色、平滑度、法線、自發光和深度等資訊渲染到螢幕空間的G緩衝區中。對於每個物體來說,這個Pass僅會執行一次。

2)第二個Pass用於計算真正的光照模型。這個Pass會使用上一個Pass中渲染的資料來計算最終的光照顏色,再儲存到幀緩衝中。

預設的G緩衝區(注意,不同Unity版本的渲染紋理儲存內容會有所不同)包含了以下幾個渲染紋理(Render Texture, RT)。

  • RT0:格式是ARGB32, RGB通道用於儲存漫反射顏色,A通道沒有被使用。
  • RT1:格式是ARGB32, RGB通道用於儲存高光反射顏色,A通道用於儲存高光反射的指數部分。
  • RT2:格式是ARGB2101010, RGB通道用於儲存法線,A通道沒有被使用。
  • RT3:格式是ARGB32(非HDR)或ARGBHalf(HDR),用於儲存自發光+lightmap+反射探針(reflection probes)。

深度緩衝和模板緩衝。

當在第二個Pass中計算光照時,預設情況下僅可以使用Unity內建的Standard光照模型,如果我們想要使用其他的光照模型,就需要替換掉原有的Internal-DeferredShading.shader檔案。

可訪問的內建變數和函式:

img

這些變數都可以在UnityDeferred Library.cginc檔案中找到它們的宣告。

選擇哪種渲染路徑?

Unity的官方文件(http://docs.unity3d.com/Manual/RenderingPaths.html)中給出了4種渲染路徑(前向渲染路徑、延遲渲染路徑、遺留的延遲渲染路徑和頂點照明渲染路徑)的詳細比較,包括它們的特性比較(是否支援逐畫素光照、半透明物體、實時陰影等)、效能比較以及平臺支援。

總體來說,我們需要根據遊戲釋出的目標平臺來選擇渲染路徑。如果當前顯示卡不支援所選渲染路徑,那麼Unity會自動使用比其低一級的渲染路徑。

相關文章