Unity性能優化之Draw Call

Unity(或者說基本所有圖形引擎)生成一幀畫面的處理過程大致可以這樣簡化描述:引擎首先經過簡單的可見性測試,確定攝像機可以看到的物體,然後把這些物體的頂點(包括本地位置、法線、UV等),索引(頂點如何組成三角形),變換(就是物體的位置、旋轉、縮放、以及攝像機位置等),相關光源,紋理,渲染方式(由材質/Shader決定)等數據準備好,然後通知圖形API——或者就簡單地看作是通知GPU——開始繪製,GPU基於這些數據,經過一系列運算,在屏幕上畫出成千上萬的三角形,最終構成一幅圖像。

在Unity中,每次引擎準備數據並通知GPU的過程稱爲一次Draw Call。這一過程是逐個物體進行的,對於每個物體,不只GPU的渲染,引擎重新設置材質/Shader也是一項非常耗時的操作。因此每幀的Draw Call次數是一項非常重要的性能指標,對於iOS來說應儘量控制在20次以內,這個值可以在編輯器的Statistic窗口看到。

Unity內置了Draw Call Batching技術,從名字就可以看出,它的主要目標就是在一次Draw Call中批量處理多個物體。只要物體的變換和材質相同,GPU就可以按完全相同的方式進行處理,即可以把它們放在一個Draw Call中。Draw Call Batching技術的核心就是在可見性測試之後,檢查所有要繪製的物體的材質,把相同材質的分爲一組(一個Batch),然後把它們組合成一個物體(統一變換),這樣就可以在一個Draw Call中處理多個物體了(實際上是組合後的一個物體)。

但Draw Call Batching存在一個缺陷,就是它需要把一個Batch中的所有物體組合到一起,相當於創建了一個與這些物體加起來一樣大的物體,與此同時就需要分配相應大小的內存。這不僅會消耗更多內存,還需要消耗CPU時間。特別是對於移動的物體,每一幀都得重新進行組合,這就需要進行一些權衡,否則得不償失。但對於靜止不動的物體來說,只需要進行一次組合,之後就可以一直使用,效率要高得多。

Unity提供了Dynamic Batching和Static Batching兩種方式。Dynamic Batching是完全自動進行的,不需要也無法進行任何干預,對於頂點數在300以內的可移動物體,只要使用相同的材質,就會組成Batch。Static Batching則需要把靜止的物體標記爲Static,然後無論大小,都會組成Batch。如前文所說,Static Batching顯然比Dynamic Batching要高效得多,於是,Static Batching功能是收費的……

要有效利用Draw Call Batching,首先是儘量減少場景中使用的材質數量,即儘量共享材質,對於僅紋理不同的材質可以把紋理組合到一張更大的紋理中(稱爲Texture Atlasing)。然後是把不會移動的物體標記爲Static。此外還可以通過CombineChildren腳本(Standard Assets/Scripts/Unity Scripts/CombineChildren)手動把物體組合在一起,但這個腳本會影響可見性測試,因爲組合在一起的物體始終會被看作一個物體,從而會增加GPU要處理的幾何體數量,因此要小心使用。

對於複雜的靜態場景,還可以考慮自行設計遮擋剔除算法,減少可見的物體數量同時也可以減少Draw Call。

總之,理解Draw Call和Draw Call Batching原理,根據場景特點設計相應的方案來儘量減少Draw Call次數纔是王道,其它方面亦然。

發佈了16 篇原創文章 · 獲贊 16 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章