(二)unity中的渲染優化技術——————(減少draw call數目 方法一:動態批處理)

批處理的實現原理就是爲了減少每一幀需要的draw call數目。爲了把一個對象渲染到屏幕上,CPU需要檢查哪些光源影響了該物體,綁定shader並設置它的參數,再把渲染命令發送給GPU。當場景中包含了大量對象時,這些操作就會非常耗時。一個極端的例子是,如果我們需要渲染一千個三角形,把他們按一千個單獨的網格進行渲染所花費的時間要遠遠大於渲染一個包含了一千個三角形的網格。在這兩種情況下,GPU的性能消耗其實並沒有多大的區別,但CPU的draw call數目就會成爲性能瓶頸。因此,批處理的思想很簡單,就是在每次調用draw call時儘可能多地處理多個物體。

那麼什麼樣的物體可以一起處理?答案是使用一個材質的物體。因爲對於使用一個材質的物體,她們之間的不同僅僅在於頂點數據的差別。我們可以把這些頂點數據合併在一起,在一起發送給GPU,就可以完成一次批處理。

unity中支持兩種批處理方式:一種是動態批處理,一種是靜態批處理。對於動態批處理來說,優點是一切處理都是unity自動完成的,不需要我們自己做任何操作,而且物體是可以移動的,缺點是限制很多,可能一不小心就破壞了這種機制,導致unity無法動態批處理一些使用了相同材質的物體。而對於靜態批處理來說,它的優點是自由度很高,限制很少;但缺點是可能會佔用更多的內存,而且經過靜態批處理後的所有物體都不可以再移動了(即便在腳本中嘗試改變物體的位置也是無效的)。

一、動態批處理

如果場景中有一些模型共享了同一個材質並滿足一些條件,unity就可以自動把它們進行批處理,從而只需要花費一個draw call就可以渲染所有的模型。動態批處理的基本原理是,每一幀把可以進行批處理的模型網格進行合併,合併後模型數據傳遞給GPU,然後使用同一個材質對其渲染。除了實現方便,動態批處理的另一個好處是:經過批處理的物體仍然可以移動,這是由於在處理每幀時Unity都會重新合併一次網格。

雖然unity的動態批處理不需要我們進行任何額外工作,但只有滿足條件的模型和材質纔可以被動態批處理。需要注意隨着unity版本的變化,這些條件也有一些改變,我們下面給出一些主要條件限制。

1.能夠進行動態批處理的網格的頂點屬性規模要小於900。例如shader中需要使用頂點位置、法線和紋理座標這3個頂點屬性,那麼想要讓模型能夠被動態批處理,它的頂點數目不能超過300。需要注意的是,這個數字在未來有可能會發生變化,因此不要依賴這個數據。

2.一般來說,所有對象都需要使用同一個縮放尺度(可以是(1,1,1)、(1,2,3),(1.5,1.4,1.3)等,但必須都一樣)。一個例外情況下,如果所有的物體都使用了不同的非同一縮放,那麼他們也是可以被動態批處理的。但在unity5中,這種對模型縮放的限制已經不存在了。

3.使用光照紋理(lightmap)的物體需要小心處理。這些物體需要額外的渲染參數,例如在光照紋理上的索引、偏移量和縮放信息等。因此爲了讓這些物體可以被動態批處理,我們需要保證他們指向光照紋理中的同一個位置。

4.多Pass的shader會中斷批處理,在前向渲染中,我們有時需要額外的Pass來爲模型添加更多的光照效果,但這樣一來模型就不會被動態批處理了。

下面看一個場景,裏面有3個立方體,他們使用了同一個材質,同時還包含了使用其他材質的一個球體。場景中還包含了一個平行光,關閉了陰影效果,以避免陰影計算對批處理數目的影響,這個場景的渲染統計數據如下圖:

可以看出要渲染這樣一個包含了4個物體的場景共需要3個批處理(untiy5中是2個,我用的是unity2018,我們發現有一個draw call進行了clear操作,具體作用目前還不清楚,先不用管他,我們以unity5爲參考),其中一個批處理用於繪製經過動態批處理合並後的3個立方體網格,另一個批處理用於繪製球體。我們可以從Save by batching看出批處理幫我們節省了2個draw call。

現在我們再向場景中添加一個點光源,並調整它的位置使他可以照亮這4個物體,由於場景中的物體都使用多個Pass的shader,因此點光源會對他們產生光照影響,如下圖:

 我們發現渲染一幀所需的批處理數目增大到了9(untiy5中是8個,我用的是unity2018,我們發現有一個draw call進行了clear操作,具體作用目前還不清楚,先不用管他,我們以unity5爲參考),而Save by batching的數目變成了0。這是因爲多個Pass的shader在需要應用多個光照的情況下,破壞了動態批處理的機制,導致unity不能對這些物體進行動態批處理。而由於平行光和點光源需要對4個物體分別產生影響,因此需要2X4個批處理操作。我們從FrameDebug查看,平行光產生影響的Pass是ForwardBase的渲染路徑,而點光源產生影響的Pass是ForwardAdd的渲染路徑。只有物體在點光源的影響範圍內,unity纔會調用額外Pass處理它。因此,如果場景中點光源的距離物體很遠,仍然會被動態批處理的。

動態批處理的限制條件比較多,例如很多時候我們的模型數據往往會超過900個頂點屬性限制,這種時候依賴動態批處理來減少draw call顯然已經不能滿足我們需求了,這時我們可以使用靜態批處理技術,下篇文章介紹。

 

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