Unity - 關於對圖集DrawCall的分析及優化

現在的遊戲跑起來會有接近130-170個左右的DrawCall,遊戲運行起來明顯感覺到卡,而經過一天的優化,DrawCall成功縮減到30-70個,這個效果是非常顯著的,並且這個優化並沒有通過將現有的資源打包圖集來實現,圖集都是原有的圖集,如果從全局的角度對圖集再進行一次優化,那麼DrawCall還可以再減少十幾個

本次優化的重點包括:層級關係和特效

對於U3D,我是一個菜鳥,對於U3D的一些東西是一知半解,例如DrawCall,我得到的是一些並不完全正確的信息,例如將N個紋理打包成一個圖集,這個圖集就只會產生一個DrawCall,如果不打成圖集,那麼就會有N個DrawCall,這個觀點在很多人的認識裏都是正確的,因爲可以通過簡單的操作來驗證,但嚴格來說,這個觀點是錯誤的,因爲它還受層級關係影響!

渲染順序

U3D的渲染是有順序的,U3D的渲染順序是由我們控制的,控制好U3D的渲染順序,你才能控制好DrawCall

一個DrawCall,表示U3D使用這個材質/紋理,來進行一次渲染,那麼這次渲染假設有3個對象,那麼當3個對象都使用這一個材質/紋理的時候,就會產生一次DrawCall,可以理解爲一次將紋理輸送到屏幕上的過程,(實際上引擎大多會使用如雙緩衝,緩存這類的手段來優化這個過程,但在這裏我們只需要這樣子認識就可以了),假設3個對象使用不同的材質/紋理,那麼無疑會產生3個DrawCall

接下來我們的3個對象使用2個材質,A和B使用材質1,C使用材質2,這時候來看,應該是有2個DrawCall,或者3個DrawCall。應該是2個DrawCall啊,爲什麼會有3個DrawCall???而且是有時候2個,有時候3個。我們按照上面的DrawCall分析流程來分析一下:

1.渲染A,使用材質1
2.渲染B,使用材質1
3.渲染C,使用材質2

在這種情況下是2個DrawCall,在下面這種情況下,則是3個DrawCall

1.渲染A,使用材質1
2.渲染C,使用材質2
3.渲染B,使用材質1

因爲我們沒有控制好渲染順序(或者說沒有去特意控制),所以導致了額外的DrawCall,因爲A和B不是一次性渲染完的,而是被C打斷了,所以導致材質1被分爲兩次渲染

那麼是什麼在控制這個渲染順序呢?首先在多個相機的情況下,U3D會根據相機的深度順序進行渲染,在每個相機中,它會根據你距離相機的距離,由遠到近進行渲染,在UI相機中,還會根據你UI對象的深度進行渲染

那麼我們要做的就是,對要渲染的對象進行一次規劃,正確地排列好它們,規則是,按照Z軸或者深度,對空間進行劃分,然後確定好每個對象的Z軸和深度,讓使用同一個材質的東西,儘量保持在這個空間內,不要讓其他材質的對象進入這個空間,否則就會打斷這個空間的渲染順序

在這個基礎上,更細的規則有:

  • 場景中的東西,我們使用Z軸來進行空間的劃分,例如背景層,特效層1,人物層,特效層2
  • NGUI中的東西,我們統一使用Depth來進行空間的劃分
  • 人物模型,當人物模型只是用一個材質,DrawCall只有1,但是用了2個以上的材質,DrawCall就會暴增(或許對材質的RenderQueue進行規劃也可以使DrawCall只有2個,但這個要拆分好才行),3D人物處於複雜3D場景中的時候,我們的空間規則難免被破壞,這只能在設計的時候儘量去避免這種情況了
  • 使用了多個材質的特效,在動畫的過程中,往往會引起DrawCall的波動,在視覺效果可以接受的範圍內,可以將特效也進行空間劃分,假設這個特效是2D顯示,那麼可以使用Z軸來劃分空間

打包圖集

每個材質/紋理的渲染一定是會產生DrawCall的,這個DrawCall只能通過打包圖集來進行優化

製作圖集一般遵循幾個規則:

  • 從功能角度進行劃分,例如UI可以劃分爲公共部分,以及每個具體的界面,功能上,顯示上密切相關的圖片打包到一起
  • 不要一股腦把所有東西打包到一個圖集裏,特別是那些不可能同時出現的東西,它們就不應該在一個圖集裏,這樣的圖集意義不大,減少不了DrawCall,並且一個你不需要顯示的圖片,會一直佔用你的內存,這讓我非常不爽
  • 注意控制圖集的大小,不要讓圖集太大,一個超級大圖集的DrawCall消耗或許頂的上十幾個小圖集的消耗

字符圖集,在使用BMFont或者其他工具生成圖片字的時候,我們往往是直接導入一大串文字,然後直接生成圖片,但實際上這上面的操作也有優化空間,例如BMFont生成的圖片大小,是可以設置的,有兩個規則,一個規則是導出的圖片儘量小,另一個是導出的圖片儘量少,默認的大小應該是512x512,假設你生成的圖片256x256就可以容納,那麼多做一個操作你可以節省這麼多空間,另外當你輸入多幾個字,就導致增加一張圖片時,例如1024變成2048,那麼你可以考慮使用3張512的圖片,這樣也會節省空間

經過精心劃分的圖集在加上精心規劃的渲染順序,DrawCall會有一個質的優化

特效清理

U3D提供了非常便捷的方法讓我們很輕易地使用美術給過來的特效,懶惰的U3D程序猿會直接放入U3D,甚至不去看這是個什麼特效,我們的特效一般都是一瞬間的事情,例如技能特效,或者其他什麼特效,那麼特效播放完,這個特效我們就看不到了,但假設這個特效在播放結束的時候,沒有將自身的Active屬性設置爲false,那麼它就會繼續佔用你的DrawCall,消耗你設備的計算能力,所以程序需要保證當一個特效播放完之後,能夠被消耗,或者設置爲非激活的狀態,可以使用一些公共方法來完成特效播放完之後的清理工作(自己實現2個靜態函數,一個播放完銷燬,一個播放完設置未激活)

完成DrawCall的優化之後,接下來就是內存的優化了,(內存優化手記 待續)

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