U3D DrawCall優化手記


在最近,使用U3D開發的游戲核心部分功能即將完成,中間由於各種歷史原因,導致項目存在比較大的問題,這些問題在最后,恐怕只能通過一次徹底的重構來解決

現在的游戲跑起來會有接近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的優化之后,接下來就是內存的優化了,(內存優化手記 待續)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM