大家好,我是曉衡!
上周我花了3天的時間,體驗測試了一款 Creator 3.x 性能優化工具:98K動態分層合批。
它能將 DrawCall
超過 1000+ 次的 2D 界面,實現運行時節點分層排序,利用引擎動態合圖 + 批量渲染能力,從底層將 DrawCall 優化到個數位。
測試案例是一個 2D 背包界面,我在 ScrollView 中動態創建了 500 個 item 元素。你可以看到,開啟合批優化后 DrawCall 從 1016 直接降到了 8,游戲幀率也從 5 幀直接拉滿到 60 幀。
這里是H5測試體驗鏈接,你也可以試一下:
98K動態分層合批
支持H5、小游戲、原生等多個平臺,而我的測試目標是,觀察對比在不同平臺環境上,使用 98K 優化前后的性能表現差異。
01 合批優化測試對比
先給出我的測試結果,一共測試了 7 個環境:
- Mac M1 Chrome 桌面瀏覽器
-
realme X50 Pro Android 原生
- realme X50 Pro Android 微信小游戲
- OPPO R11s Plus Android 原生
- OPPO R11s Plus Android 微信小游戲
- iPhone11 微信小游戲
- iPhone7 微信瀏覽器
以上測試環境數據,我整理了個表格,方便大家對比優化關后的效果:
如果你覺得看數據表還是很費勁的話,可以直接看曉衡這個結論:
- 開啟合批優化后,所有平臺都能跑到 60 幀,ScrollView列表滑動流暢;
- 除減少 DrawCall 外,還啟了渲染剔除,降低了渲染面數;
- 優化前后差異對比是:桌面 > 低端原生 > 低端小游戲 > 中高端原生&小游戲。
桌面瀏覽器上的優化性能最佳,這是我萬萬沒想到的,不論是 Mac 還是 Windows 系統,都是如此。未合批前僅僅只有 5 幀,在列表上滑動,非常卡頓,基本上無法使用。開啟合批后,直接拉滿到60幀,列表滑動流暢。
其次是在 iPhone 上,小游戲上的優化比瀏覽器要好,未合批前不到 30 幀,開啟合批后滿幀 60,列表滑動也更順滑。
然后是在 Android 手機上,中高機型未合批前就能達到 50 ~ 60 幀,優化后提升不到 10 幀的樣子,不看調試數值感覺不明顯。低端機型的優化效果不錯,有 20 ~ 30 幀的提升,硬件性能越低優化后的效果越好。
最后,我在多說一點,就是在 iPhone 和 Android 低配機型上,原生性能要低于H5和小游戲,優化效果會好。下面是我構建的 APK 安裝包,感興趣的伙伴可以來體驗一下:
- 鏈接: https://pan.baidu.com/s/12aEvOL9fQrpyB4Xs--OALg?pwd=4znt 提取碼: 4znt
測試數據和結論有了,我們再深入一點,98K動態分層合批的核心是對 DrawCall 的優化,初學游戲開發的小伙伴,可能會有疑問:
DrawCall 是什么?為什么減少 DrawCall 能提升游戲的性能?合批又是個什么鬼?
而有過游戲開發經驗,又愛思考的老鐵多半會問:
道具背包這類應用場景,一個 item 混合有復雜的圖片、文字,98K是如何避免 DrawCall 被打斷的?
下面我就來嘗試一下,能否將上面幾個問題說清楚,你可以更加清楚知道是否適合在自己的項目中使用98K合批優化。
02 理解Drawcall與合批
DrawCall 是什么?
- 簡單來講 CPU 準備好渲染數據,提交給 GPU 進行繪制的這個過程就是一次 DrawCall
為什么減少 DrawCall 能提升游戲的性能?
- GPU 渲染圖像的速度非常非常快;
- CPU 的內存\顯存讀寫、數據處理和渲染狀態切換,相比 GPU 非常非常慢;
- 大量的 DrawCall 會讓 CPU 忙到焦頭爛額,而 GPU 大部分時間都在摸魚
因此,盡可能一次性將更多的渲染數據提交給 GPU,減少 CPU 的工作時間,從而提升游戲性能。
什么是合批?
- 簡單來說,組織更多渲染數據提交給 GPU 的過程,稱之為“批量渲染”簡稱“合批”
- 但要實現合批的前提是:渲染數據必須一致
更多關于 DrawCall 優化的理解,可以閱讀陳皮皮的這篇文章:Cocos Creator 性能優化:DrawCall
舉個例子
比如像下面這樣的節點樹結構,就無法實現合批:
因為 item 節點下的 Sprite 與 Label 節點渲染類型不同,并相互間隔排列,引擎無法向 GPU 批量提交渲染數據。
因此渲染一個 item 需要 DrawCall 4次:Sprite → Label → Sprite → Label。
我們調整一下 item 下的節點順序,像下面這樣:
試試你能計算出上圖中的 DrawCall 值嗎?在 Creator 引擎中預覽運行游戲,在畫面左下角,你會看到 DrawCall 的值顯示為 3。
細心的你這時可能會問:為什么 DrawCall 是 3 而不是 2 呢?
不用懷疑,你計算的 DrawCall 為 2 是正確的,因為引擎這里會占用一次 DrawCcall,具體為什么,我們后面來說原因,你也可以思考一下!
03 98K是如何避免 DrawCall 被打斷?
要想避免 DrawCall 被打斷,首先要理解什么是 DrawCall 打斷!
通過上面的舉例,不知道你沒有點感覺了。我們再來看多個 item 節點樹 DrawCall 情況又會是怎么樣的呢?
在層級管理器中,我們再復制一顆 item 節點樹出來,見下圖所示:
從上圖可以看出,兩顆 item 節點樹時又出現:item1(Sprite → Label) → item2(Sprite → Label) 交替的情況,合批就這樣被打斷了。
聰明的我立馬會想到,將所有 item 下的節點合并不就好了,像下圖這樣:
效果是不是很好?6 個節點只有 2 次 DrawCall !就這樣干?
有經驗的你問題又來了,我們的邏輯代碼通常是以單個 item 為單位建立的對象,如果將類型節點點合并到一起,上層邏輯代碼豈不是要亂成一鍋粥?
優化的方法是知道了,但代價太大,不知道如何下手!
這個問題一直困擾我多年,一直沒找到可行的解決方案,直到遇到98K動態合批的開發者。
這里不得不說下 98K動態合批 的強悍,就在于它可以讓你無視 item 子節點順序和層級關系,只需要在上層容器節點上添加 BatchItems
組件,最大程度上保證合批不被中斷,實現該節點樹的渲染優化。
其代碼實現原理是:
- 攔截引擎渲染開始事件,對節點樹下的所有子節點按類型重新分層排序;
- 攔截引擎渲染結束事件,立即還原渲染前的節點樹排序,從而實現無入侵式的合批優化
-
BatchItem
組件唯一的 Culling 屬性是可選的,它會拿 Culling 屬性所指定的矩形區,與容器中 item 矩形做相交測試,將不在 Culling 區的元素從渲染隊列中剔除掉
05 應用場景
需要注意的是98K合批優化,僅適用于 2D UI 界面的優化,特別是具有大量重復結構的 item 場景如:背包系統、滑動列表、技能欄、聊天界面等,以下應用場景供大家參考。
背包系統
頻道列表
游戲排行榜
聊天界面
04 注意事項
我在使用 98K編寫前面那個背包測試工程時,踩到幾個坑有幾點需要注意:
item 下子節點名字不能重復需保持唯一性
多個同結構的 item 子節點名字需要保持一致
節點的 Layer 屬性需保持相同,建議統一為 UI_2D
-
需要手動開啟引擎的動態合圖和關閉清除圖片緩存開關
dynamicAtlasManager.enabled = true; macro.CLEANUP_IMAGE_CACHE = false;
充分使用引擎的動態合圖,將盡量多的圖片合并,需要增大項目設置中 BATCHER2D_MEM_INCREMENT 宏的參數值
06 結語
最后,我再小結一下 98K動態分層合批 的整體感受!
它是非常適用于像背包系統、滑動列表、聊天消息這類 2D UI 場景。
如果因游戲中因節點太多導致圖文分層原因,打斷合批造成 DrawCall 劇增影響性能和增加發熱問題,98K合批可以說是首選的優化工具。
當然,你也可以使用虛擬列表的技術并不用創建出所有的 item,但我的感受是98K更為簡單粗暴、立桿見影,能結合使用效果更定會更佳。
而從多個環境平臺的測試效果來看:
- 桌面瀏覽效果最佳,如果你是做 H5 頁游,那再適合不過
- 再次是 iPhone 瀏覽器、小游戲優化效果顯著
- 然后是中低端的 Android 也比較推薦
下面是 H5 | Android 測試鏈接,強烈建議你也來體驗一下,歡迎留言說說在你的設備上體驗感受。
H5測試鏈接:
- http://gameview.creator-star.cn/98K/batch-items/index.html
Android測試包下載
- 鏈接: https://pan.baidu.com/s/12aEvOL9fQrpyB4Xs--OALg?pwd=4znt 提取碼: 4znt
Cocos Store下載鏈接
- https://store.cocos.com/app/detail/4310
希望今天的分享能夠對大家有所幫助和啟發, 曉衡會繼續挖掘 Cocos Store 上的優秀作品分享給大家,歡迎關注!