前言
在游戲開發(fā)中照棋,Draw call 作為一個非常重要的性能指標(biāo)猜拾,直接影響游戲的整體性能表現(xiàn)绍昂。Draw call 就是 CPU 調(diào)用圖形 API,比如 OpenGL拼岳,命令 GPU 進(jìn)行圖形繪制枝誊。一次 Draw call 就代表一次圖形繪制命令,由于 Draw call 帶來的 CPU 及 GPU 的渲染狀態(tài)切換消耗裂问,往往需要通過批次合并來降低 Draw call 的調(diào)用次數(shù)。批次合并的本質(zhì)就是在一幀的渲染過程中牛柒,保證連續(xù)節(jié)點(diǎn)的渲染狀態(tài)一致堪簿,將盡可能多的節(jié)點(diǎn)數(shù)據(jù)合并一次性提交,從而減少繪圖指令的調(diào)用次數(shù)皮壁,降低圖形 API 調(diào)用帶來的性能消耗椭更,同時也可以避免 GPU 進(jìn)行頻繁的渲染狀態(tài)切換。渲染狀態(tài)就包括:紋理狀態(tài)蛾魄,Blend 模式虑瀑,Stencil 狀態(tài),Depth Test 狀態(tài)等等
為了保證節(jié)點(diǎn)使用的紋理圖片資源一致滴须,引擎提供兩種合圖方式:靜態(tài)合圖和動態(tài)合圖舌狗。
靜態(tài)合圖
靜態(tài)合圖即為編輯器提供的自動圖集功能,以及其他第三方圖集打包工具如:TexturePacker 等扔水。在資源層面進(jìn)行散圖合并痛侍,保證UI節(jié)點(diǎn)使用的都是同一張貼圖,因?yàn)橥粡垐D集的紋理狀態(tài)都是一致的魔市,所以能夠達(dá)到渲染批次合并對紋理狀態(tài)的要求主届。
對于 Label 組件,為了保證所有的 Label 節(jié)點(diǎn)使用相同的紋理待德,通常會使用 BMFont 將要使用的 UI 文字提前進(jìn)行打包君丁,并使用引擎的自動圖集與散圖一起合并進(jìn)一張大的紋理,即可與其他相鄰的 Sprite 節(jié)點(diǎn)進(jìn)行批次合并将宪。自動圖集的創(chuàng)建與設(shè)置可以參考?自動圖集資源绘闷,然后新建一個自動圖集資源配置橡庞,把所有你希望進(jìn)行合圖的 UI 圖片,BMFont 和藝術(shù)數(shù)字都拖到自動圖集資源所在的目錄即可簸喂。BMFont 的文本制作可以通過 BMFont 字體制作工具毙死,將常用的美術(shù)字或者文本制作生成一張字體圖片及其字體映射文件。然后直接拖入編輯器中即可使用喻鳄。
動態(tài)合圖
靜態(tài)合圖的局限性還常常體現(xiàn)在動態(tài)文本的渲染過程扼倘,如 Label 組件在使用系統(tǒng)文本時,文本貼圖是依據(jù)文本內(nèi)容通過 Canvas 繪制動態(tài)生成除呵,不能提前進(jìn)行圖集打包再菊。所以,除了靜態(tài)合圖颜曾,引擎也提供了動態(tài)合圖的功能纠拔。
在運(yùn)行時,引擎通過將散圖添加到動態(tài)圖集中泛豪,來保證節(jié)點(diǎn)使用的紋理一致稠诲。由于動態(tài)圖集使用的是默認(rèn)紋理狀態(tài),所以只有當(dāng)散圖的紋理狀態(tài)與動態(tài)圖集的狀態(tài)一致诡曙,才可參與到引擎的動態(tài)合圖中臀叙。
Label 組件目前提供三種 Cache Mode:NONE、BITMAP价卤、CHAR劝萤。
NONE 模式即 Label 的整個文本內(nèi)容會進(jìn)行一次繪制,并進(jìn)行提交慎璧,但是并不參與動態(tài)合圖床嫌。
BITMAP 模式即 Label 的整個文本內(nèi)容會進(jìn)行一次繪制,并加入到動態(tài)圖集中胸私,以便進(jìn)行批次合并厌处。
CHAR 模式即 Label 會將文本內(nèi)容進(jìn)行拆分,然后對單個字符進(jìn)行繪制岁疼,并將字符緩存到一張單獨(dú)的字符圖集中嘱蛋。下次遇到相同字符不再重新繪制。
目前引擎的動態(tài)圖集主要有兩種:
一種是為散圖及使用 BITMAP 模式的文本提供的動態(tài)圖集五续,最大數(shù)量為?5?張洒敏,尺寸為?2048 * 2048。
另外一種是為使用 CHAR 模式的文本提供的字符圖集疙驾,單個場景只有?1?張凶伙,尺寸為?2048 * 2048
這兩種動態(tài)圖集在切換場景時會進(jìn)行清理釋放。由于動態(tài)圖集空間有限它碎,因此需要最佳化的利用:
對于一些?不常變化的靜態(tài)文本函荣,例如 UI 界面的標(biāo)題显押,屬性欄的固定文本,如果使用系統(tǒng)文本傻挂,可以設(shè)置為?BITMAP?模式乘碑,緩存到動態(tài)圖集中,這樣連續(xù)的 UI 節(jié)點(diǎn)即可進(jìn)行動態(tài)合批金拒。由于圖片一般會打包為靜態(tài)圖集兽肤,而為了最大限度的把界面中的 Label 進(jìn)行合批,可以將界面中的這些靜態(tài)文本節(jié)點(diǎn)層級放在最上層绪抛,并保證這些 Label 節(jié)點(diǎn)連續(xù)即可避免 Label 節(jié)點(diǎn)打斷批次资铡,同時合并連續(xù)的 Label 節(jié)點(diǎn)降低 Draw call。
對于一些?頻繁變化的文本幢码,例如游戲中常用的倒計(jì)時笤休,如果使用 BITMAP 模式,會導(dǎo)致大量的數(shù)值文本占用動態(tài)圖集空間症副,但是其使用的字符數(shù)量有限店雅,只有數(shù)字?0 - 9?這 10 個字符。為了避免頻繁繪制贞铣,可設(shè)置為?CHAR?模式闹啦,進(jìn)行字符緩存,將單個字符文本添加到字符圖集中咕娄。這樣緩存一次之后亥揖,后續(xù)所有的數(shù)字組合都可以從已緩存的字符中獲取珊擂,提高性能圣勒。如果連續(xù)的 Label 節(jié)點(diǎn)使用的都是 CHAR 模式,因?yàn)樗鼈兪褂玫氖峭粡堊址麍D集摧扇,所以也可以保證這些節(jié)點(diǎn)能夠進(jìn)行批次合并圣贸。
注意事項(xiàng)
1、由于 Creator 的自動圖集功能是在項(xiàng)目導(dǎo)出的時候進(jìn)行的扛稽,所以應(yīng)該在發(fā)布后的項(xiàng)目中進(jìn)行合批測試吁峻。
2、在導(dǎo)入 BMFont 的資源的時候在张,需要把?.fnt?和相應(yīng)的?png?圖片放在同一個目錄下面用含。
3、LabelAtlas 底層渲染采用的跟 BMFont 一樣的機(jī)制帮匾,所以也可以和 BMFont 及其它 UI 元素一起合圖來實(shí)現(xiàn)批次渲染啄骇。
4、微信小游戲平臺由于 Image 的內(nèi)存占用原因瘟斜,默認(rèn)禁用了動態(tài)圖集功能缸夹,如果對內(nèi)存占用要求不高的游戲痪寻,可以自行通過?cc.dynamicAtlasManager.enabled = true?打開該功能,并且設(shè)置?cc.macro.CLEANUP_IMAGE_CACHE = false?禁止清理 Image 緩存虽惭。具體可參考啟用橡类、禁用動態(tài)合圖。
5芽唇、默認(rèn) Spine 的合批是關(guān)閉的顾画,需要勾選enableBatch選項(xiàng)開啟,Spine 必須是同個 Spine 資源創(chuàng)建的對象披摄,且每個 Spine 只有一種混合模式亲雪、一張貼圖,才能進(jìn)行批次合并疚膊,Dragonbones 同理义辕。
6、單次 Draw call 的 Buffer 數(shù)據(jù)有限寓盗,當(dāng)數(shù)據(jù)超過 Buffer 長度限制時灌砖,會重新申請新的 Buffer,不同的 Buffer 也會是不同的批次傀蚌。