面对包含复杂图文的 2D UI 场景,如何才能避免合批被打断、DrawCall 剧增的情况?Cocos Store 张晓衡体验测试了一款 Cocos Creator 3.x 性能优化工具,有效解决该问题。
高性能轻量 3D 碰撞管理器「98K 物理-轻量碰撞系统」的作者「我叫98K」,本次带来了一款全新的性能优化工具「98K 动态分层合批」,能够通过动态分层合批和范围剔除,显著降低 DrawCall。
该工具适用于 2D UI 界面的优化,特别是具有大量重复结构的 item 场景,如背包系统、滑动列表、排行榜、技能栏、聊天界面等,解决因图文分层打断合批、造成 DrawCall 剧增而影响性能的问题。
我们来测试一下在 H5、小游戏、原生等不同平台上,工具使用前后的性能表现差异。测试案例是一个 2D 背包界面,我在 ScrollView
中动态创建了 500 个 item 元素。测试结果如下:
从测试结果来看,工具开启合批优化后,各个平台的 DrawCall 都从 1000+ 降至个位数,帧率都达到了 60 帧,ScrollView
列表滑动流畅;此外,开启渲染剔除算法也有效降低了渲染面数。
像道具背包这类应用场景,一个 item
混合有复杂的图片和文字,「98K 动态分层合批」是如何避免 DrawCall 被打断的?我们又该如何理解 DrawCall 与合批呢?
DrawCall 与合批
什么是 DrawCall 与合批?
DrawCall 是什么?
简单来讲 CPU 准备好渲染数据,提交给 GPU 进行绘制的这个过程就是一次 DrawCall。
为什么减少 DrawCall 能提升游戏性能?
首先,GPU 渲染图像的速度非常非常快;而 CPU 的内存/显存读写、数据处理和渲染状态切换,相比 GPU 非常非常慢。大量的 DrawCall 会让 CPU 忙到焦头烂额,而 GPU 大部分时间都在摸鱼。
因此,若一次性将更多渲染数据提交给 GPU,减少 CPU 的工作时间,就能提升游戏性能。
什么是合批?
简单来说,组织更多渲染数据提交给 GPU 的过程,称之为「批量渲染」,简称「合批」。
实现合批的前提是:渲染数据必须一致。
举个例子,像上图中的的节点树结构,就无法实现合批。因为 item 节点下的 Sprite 与 Label 节点渲染类型不同,并相互间隔排列,引擎无法向 GPU 批量提交渲染数据。此时,渲染一个 item
需要 4 次 DrawCall:Sprite
→ Label
→ Sprite
→ Label
。
我们调整一下 item
下的节点顺序,如上图。
此时,渲染一个 item
需要 2 次 DrawCall。而因为引擎会占用一次 DrawCall,所以在 Cocos Creator 中预览运行游戏,画面左下角 DrawCall 的值显示为 3。
更多关于 DrawCall 优化的理解,可以阅读陈皮皮的文章《Cocos Creator 性能优化:DrawCall》。
如何避免 DrawCall 被打断?
什么是 DrawCall 打断呢?
在了解了单一 item
的 DrawCall 情况后,我们再来看看多个 item
节点树的 DrawCall 情况。
如上图,在层级管理器中,我们再复制一棵 item
节点树出来。可以看出,两棵 item
节点树存在 item1
(Sprite
→ Label
) → item2
(Sprite
→ Label
) 交替的情况,合批就这样被打断了。
也许你会想到:既然如此,将所有 item
下的节点合并不就好了。如上图所示,6 个节点只需 2 次 DrawCall。
但这样做有一个很大的问题:我们的逻辑代码通常是以单个 item
为单位建立的对象,如果将类型节点点合并到一起,上层逻辑代码岂不是要乱成一锅粥?
而「98K 动态分层合批」的强悍,就在于它可以让你无视 item
子节点顺序和层级关系,只需要在上层容器节点上添加 BatchItems
组件,即可最大程度上保证合批不被中断,实现该节点树的渲染优化。
其代码实现原理是:
拦截引擎渲染开始事件,对节点树下的所有子节点按类型重新分层排序;
拦截引擎渲染结束事件,立即还原渲染前的节点树排序,从而实现无入侵式的合批优化;
BatchItem
组件唯一的Culling
属性是可选的,它会拿Culling
属性所指定的矩形区,与容器中item
矩形做相交测试,将不在Culling
区的元素从渲染队列中剔除掉。
使用方法
「98K 动态分层合批」支持 Cocos Creator 3.x,开箱即挂即用无需添加任何代码。
优化技巧
Label
文字开启缓存模式,推荐char
模式:
开启自动合图或自定义图集:
macro.CLEANUP_IMAGE_CACHE = false;
dynamicAtlasManager.enabled = true;
开启自动合图
开启自定义图集
开启范围剔除,减少不可视的计算。
设置 item
显示范围(cc.UITransform
):
设置剔除范围节点(cc.UITransform
):
使用注意
名字不能重复:
item
下节点名字不能重复,保持唯一性,用于分层合批的收集和排序。名字顺序不能冲突:
item
内节点名顺序不能和其他item
内节点名顺序冲突,保持前后出现的顺序。相互不能重叠:
item
相互之间不能重叠,分层合批会改变绘画顺序,相互重叠会产生item
间显示层的冲突,需要避免这种使用情况。
版本支持情况
原生支持情况:v3.5.x 以下支持全平台,v3.6.x 以上暂不支持原生。
低版本使用方法:原默认工程是 v3.5.2,在 v3.5.2 以下版本使用时,请将
BatchItems.ts
复制到低版本工程上使用。
资源链接
插件下载:
https://store.cocos.com/app/detail/4310
H5 版测试链接:
http://gameview.creator-star.cn/98K/batch-items/index.html
📢 福利时间!转发本文并在评论区留言,2月6日(下周一),我们将从评论区中随机抽选3名小伙伴,送出「98K 动态分层合批」免费兑换码1个!
往期精彩