前言
在游戲開發中,DrawCall 作為一個非常重要的性能指標,直接影響游戲的整體性能表現。
無論是 Cocos Creator、Unity、Unreal 還是其他游戲引擎,只要說到游戲性能優化,DrawCall 都是絕對少不了的一項。
本文將會介紹什么是 DrawCall,為什么要減少 DrawCall 以及在 Cocos Creator 項目中如何減少 DrawCall 來提升游戲性能。
什么是 DrawCall
DrawCall就是CPU調用圖形庫(比如DirectX或OpenGL)的圖形繪制接口,來命令GPU進行渲染的操作。
DrawCall 是如何影響性能的呢?
先舉個栗子:
http形式從服務器拉取1024個大小1kb的文件和單個大小為1M的文件,哪個耗時更短?
答:肯定是拉取單個1M的更快。
原因就是每個請求之前,http 都需要做許多的準備工作來保證文件能夠正常傳輸。而正是這些額外工作,造成了很多時間和性能開銷。
而每一次繪制CPU都要調用DrawCall,而在調動DrawCall前,CPU還要進行很多準備工作:檢測渲染狀態、提交渲染所需要的數據、提交渲染所需要的狀態。
而GPU本身具有很強大的計算能力,可以很快就處理完渲染任務。一般來說,繪制 100 個三角形和繪制 1000 個三角形所消耗的時間沒差多少。
但是,當 DrawCall 過多,CPU就會很多額外開銷用于準備工作,CPU本身負載,而這時GPU可能閑置了。
**也就是說,正是因為每次渲染前,CPU 都需要做一系列準備工作,而 CPU 的每一次內存顯存讀寫、數據處理和渲染狀態切換都會帶來一定的性能和時間消耗,積少成多,而 GPU 大部分時間都在摸魚。
所以才造成了我們認知中的,DrawCall 數量過多導致了卡頓 **
如何減少 DrawCall
如上所說,我們可以通過一次多給 CPU 分配點工作,讓一次渲染的內容多一些,減少分配次數,來達到我們的目的。
話是這么說,可是我們應該怎么實際操作呢?往下看
針對圖片資源
靜態合圖
就是講碎圖整合成一張大圖,即我們常說的 打圖集。
但是圖集也不是隨便打的,并不是一張大圖容納越多的碎圖越好。這里面也是有一定的門道的。
盡量將處于同一界面(UI)下的相鄰且渲染狀態相同的碎圖打包成圖集
對于Creator來說,在游戲運行時引擎是按照節點層級順序從上往下由淺到深進行渲染的,理論上 每渲染一張圖像(文本最終也是圖像)都需要一次 DrawCall。
渲染狀態是指:紋理狀態(預乘、循環模式和過濾模式)或 Material(材質)、Blend(混合模式)等等,所以使用自定義 Shader 也會打斷合批
所以 相鄰且渲染狀態相同 是關鍵點。
tip: 不建議任何圖片資源的尺寸超過2048*2048,否則可能會出現加載相關的問題。
下面介紹2種打圖集的方式
自動圖集資源(Auto Atlas)
利用 Cocos Creator 內置的自動圖集資源來將碎圖打包成圖集。
在項目構建時,編輯器會將所有自動圖集資源所在文件夾下的所有符合要求的圖像分別根據配置打包成一個或多個圖集。
自動圖集資源使用起來很靈活,編輯器在打包圖集時會自動遞歸子目錄,若子目錄下也有自動圖集資源(即 .pac 文件)則會跳過該目錄,所以我們可以對同一目錄下的不同部分的碎圖配置不同的參數。
關于自動圖集的幾點建議
合理控制圖集最大尺寸,避免單個圖像加載時間過長。尺寸太大的圖像沒有必要打進圖集(如背景圖)。善用九宮格(Sliced)可以節省很多空間(這一點需要美術大佬配合)。間距保持默認的 2 并保持勾選擴邊選項,避免圖像裁剪錯誤和出現黑邊的情況。勾選不包含未被引用資源選項,自動排除沒有用到的圖像以節省空間(該選項預覽時無效)。開發時預覽圖集,根據結果進行調整,以達到最好的優化效果。
TexturePacker
使用 TexturePacker 打包圖集時需要注意配置「形狀填充(Shape Padding,對應 Auto Atlas 中的間距)」,避免某張圖像出現相鄰圖像的像素的情況。
對比一下
Auto Atlas
- Cocos Creator 內置,方便
- 功能不多但是該有的都有
- 項目構建時才生成圖集,開發時任意修改無壓力
- 圖集尺寸在生成時自適應,節省空間
- 支持自動紋理壓縮
TexturePacker
- 第三方軟件需自行安裝,不夠方便
- 收費功能很多很專業但是基本用不著,免費功能也夠用
- 先生成圖集再使用,更換圖像又要重新生成圖集
- 尺寸固定需要自己設置
- 不支持自動紋理壓縮 動態合圖
Creator 官方說明:
Cocos Creator 提供了在項目構建時的靜態合圖方法 —— 「自動合圖」(Auto Atlas)。但是當項目日益壯大的時候貼圖會變得非常多,很難將貼圖打包到一張大貼圖中,這時靜態合圖就比較難以滿足降低 DrawCall 的需求。
所以 Cocos Creator 在 v2.0 中加入了 「動態合圖」(Dynamic Atlas)的功能,它能在項目運行時動態的將貼圖合并到一張大貼圖中。當渲染一張貼圖的時候,動態合圖系統會自動檢測這張貼圖是否已經被合并到了圖集(圖片集合)中,如果沒有,并且此貼圖又符合動態合圖的條件,就會將此貼圖合并到圖集中。
動態合圖官方文檔:
https://docs.cocos.com/creator/manual/zh/advanced-topics/dynamic-atlas.html
動態圖集有2個限制:
- 動態圖集尺寸最大是 2048 * 2048
-
碎圖的尺寸默認不能超過 512,可通過 API 進行修改:
cc.dynamicAtlasManager.maxFrameSize = 512
tips: 啟用動態合圖會增大內存消耗,不同平臺占用內存不一致。小游戲和原生平臺默認禁止動態合圖。可以通過 api 自行開啟:cc.macro.CLEANUP_IMAGE_CACHE = false; cc.dynamicAtlasManager.enabled = true;
還需要保證紋理的 Premulyiply Alpha(預乘)、Wrap Mode(循環模式) 和 Filter Mode(過濾模式) 等信息與動態圖集一致才能夠動態合批。
另外,靜態圖集也能參與動態合圖,只要滿足動態合圖的要求即可。
tip1: 自動圖集資源(Auto Atlas)需要在其屬性檢查器面板中開啟 Texture 欄下的 Packable 選項,該選項默認是禁用的。
tip2: 精靈(Sprite)也是需要開啟 Packable 選項才能動態合圖。該選項默認是開啟的。
tip3: 如果要使用了 shader ,那么需要禁用該精靈的 Packable 選項。
針對 Label
位圖字體(BMFont)
在 Creator 中使用系統字體或 TTF 字體的 Label 會打斷渲染合批,特別是 Label 和 Sprite 層疊交錯的情況,每一個 Label 都會打斷合批增加一個 DrawCall。
因此建議使用 BMFont 來代替 TTF 或系統字體,并且將 BMFont 與 UI 碎圖打包到同一圖集中(或「開啟動態合圖」),可以免除大部分文本導致的 DrawCall增加。
文本緩存模式(Cache Mode)
Creator 2.0.9 版本在 Label 組件上增加了 Cache Mode 選項,來解決系統字體和 TTF 字體帶來的性能問題。
CacheMode有三種選項:
- NONE(默認) 每一個 Label 都會生成為一張單獨的位圖,且不會參與動態合圖,所以每一個 Label 都會打斷渲染合批
- BITMAP 開啟 BITMAP 模式后,文本同樣會生成為一張位圖,但是只要符合動態合圖要求就可以參與動態合圖,和周圍的精靈合并 DrawCall 。一定要注意 BITMAP 模式只適用于不頻繁更改的文本,否則內存會爆炸。
- CHAR 開啟 CHAR 模式后,引擎會將該 Label 中出現的所有字符緩存到一張全局共享的位圖中,相當于是生成了一個 BMFont 。適用于文本頻繁更改的情況,對性能和內存最友好。tip: 該模式 只能用于字體樣式和字號固定,并且不會頻繁出現巨量未使用過的字符 的 Label。因為共享位圖的最大尺寸為 2048*2048,占滿了之后就沒辦法再渲染新的字符,需要切換場景才會清除共享位圖。
總結:對于大量頻繁更改的文本,使用 CHAR 模式帶來的性能提升是非常明顯的。
同時 CHAR 模式的局限也很明顯,一般用于場景中出現大量數字文本,類似于經驗值增加、血量減少之類的特效的情況
必經之路–調整UI層級順序
原則:
分離圖像節點和文本節點文本使用 BMFont 或 Cache Mode 選項,盡量出現避免文本打斷渲染合批的情況FBI WARNING: 一個 Mask 組件及其控制的渲染節點,需要至少三次 Draw call。第一次開啟模板測試并調用一次 Draw call,刷新模板緩沖。第二次繪制對需要通過模板測試的區域進行設置。第三次再進行實際的子節點內容繪制,繪制結束再關閉模板測試。因此 使用 Mask 組件就無法與其他相鄰節點進行批次處理 ,但是 Mask 組件內部的連續節點在滿足合并規則的情況下還是會進行合批。
總結
改變渲染狀態會打斷渲染合批,例如改變紋理狀態(預乘、循環模式和過濾模式)或改變 Material(材質)、Blend(混合模式)等等,所以使用自定義 Shader 也會打斷合批。圖集默認不參與動態合圖,手動開啟自動圖集資源的 Packable 選項后如果最終圖集符合動態合圖要求也可以參與動態合圖。紋理開啟 Packable 選項參與動態合圖后無法使用自定義 Shader,因為動態合圖會修改原始貼圖的 UV 坐標。使用 Cache Mode 的 BITMAP 模式需要注意內存情況,CHAR 模式需要注意文本內容不宜過多。在 ***Cocos Creator 2.0.7 之前的版本***中,改變節點的顏色或透明度、Sprite 組件使用九宮格(Sliced)都會打斷渲染合批
以上就是詳解CocosCreator優化之DrawCall的詳細內容,更多關于CocosCreator優化DrawCall的資料請關注服務器之家其它相關文章!
原文鏈接:https://blog.csdn.net/sinat_28338727/article/details/107886463