查看原文
其他

Cocos Creator ScrollView 性能优化

Cocos技术顾问组 COCOS 2022-06-10

9月份 Cocos 技术开发分享会第 2 期在深圳圆满举行,近期我们将对活动干货进行整理,陆续在公众号上发布,没能去到深圳现场的开发者可以关注一下!对于分享的议题有哪些疑惑也欢迎在文末给我们留言!



本文基于 Cocos Creator v2.1.2 

《Cocos Creator ScrollView 性能优化》

讲师:Cocos 技术顾问组


分享原因:

Cocos Creator 的 ScrollView 组件是游戏开发中常用的组件,在一些商城界面、排行榜界面、任务列表、背包系统等模块中经常会使用到它,但同时它的开销也非常大。当我们需要显示的条目比较多时,单纯简单地去使用的话,往往性能不大理想。


Cocos Creator 只实现了最基本的 ScrollView,相应的优化还需要我们根据项目的情况来进行针对性的优化。


常见问题:


当数据量比较大时,我们很容易碰到两个问题:


  • DrawCall 的数量比较高,渲染性能比较低

  • 整个 Scrollview 的节点数太多,导致隐藏或显示界面时的 onEnable 和 Disable 开销比较大


比如下面这个界面:


Demo 中的 ScrollView 1 场景


ScrollView 当中有 20 个 Cell,总共的 DrawCall 达到了 790,单个 Cell 大概有 50 个节点,总共就有差不多 1000 个节点,这时我们的开销会变得非常的大



常规优化方式推荐:


1、合并渲染批次,降低 DrawCall,提升渲染性能


有两个方法可以使用:


(1)使用自动图集或使用 TexturePacker 对碎图进行打包处理:

   

这样操作的话,可以让多个 Sprite 渲染的纹理都是同一张图集图片,合并这些 sprite 的渲染批次,就可以减少 DrawCall 以及 CPU 的运算开销。


这里我使用了 AutoAtlas 来实现,关于 AutoAtlas 的使用可以[参考文档]让我们来看下效果:



同样是 20 个 Cell,DrawCall 降低到了 556,相比较之前有了比较明显的降低。

        

优化到这个程度还不够,如果你是在 Google 的 Chrome 浏览器上进行调试的话,推荐你使用 spector.js 这个插件,通过这个插件你可以看到每个 DrawCall 对于纹理的处理情况。对于原生开发,则可以使用 XCode 中的 GPU analysis功能。

    

(2)开启 dynamicAtlas 功能


开启这个功能,在 main.js 中的 window.boot() 方法内加入下面的两行代码即可:


cc.macro.CLEANUP_IMAGE_CACHE = false;cc.dynamicAtlasManager.enabled = true;


开启之后,我们可以看到 DrawCall 大幅下降,部分 DrawCall 已经合并。


2、对于 Label 的处理。


Label 的处理跟前面的优化方案选择有关系:


(1)如果使用了自动图集或 TexturePacker 对碎图进行合并的话,可以选择 Label 使用 bmfont 字体,而不是使用系统字体,同时将 bmfont 使用到的纹理资也一起合并到图集资源中。



可以看到,DrawCall 又进一步地降低了,目前运行的效果是 330 个 DrawCall。



(2)如果前面使用的是 dynamicAtlas 的功能,那么可以选择 Label 使用系统字体,同时将 Label 的 CacheMode 属性更改为 BITMAP。



这个模式下会将 Label 的纹理当作一个 Sprite 纹理,并且参与到 dynamicAtlas 中去,这样就可以跟 Sprite 的纹理进行合批处理。


        

从这两个方案可以看出来,优化策略都是想办法对 DrawCall 进行合并批处理,只是使用 dynamicAtlas 更加地智能,同时也可以更好地适应复杂的节点结构。


但需要注意的是,dynamicAtlas 会有额外的 CPU 计算以及动态纹理的绘制开销,因此需要根据项目的情况去选择使用。


3、通过 Cell 的位置进行计算,让显示范围外节点的 opacity 为0,即不显示,减少  DrawCall 。


在可视范围外的节点,本身我们就不可见,所以就不需要它再进行绘制,平白增加 Drawcall。我们可以将这些可视范围外节点的 opacity 属性设置为 0,从而避免绘制,可以有效的降低 DrawCall。

update (dt) { var viewRect = cc.rect(- this.view.width / 2, - this.content.y - this.view.height, this.view.width, this.view.height); for (let i = 0; i < this.content.children.length; i++) { const node = this.content.children[i]; if (viewRect.intersects(node.getBoundingBox())) { node.opacity = 255; } else { node.opacity = 0; } } }


这里我将判断逻辑放在了 Update 函数中,你也可以将这段方法放到 ScrollView 的滑动回调中去,这样的话不用每帧都计算,只在需要的时候才会去进行计算,节约一些 CPU 的开销。


最终效果可以看到,在启用 dynamicAtlas 的方案上,DrawCall 可以降低到 68,相比较最原始的 790 个 DrawCall,效果显著。



4、资源处理,减少 Mask 组件数量


通过对资源的处理,减少 Cell 中使用 Mask 组件的数量,尽量不使用 Mask 组件。


由于 Mask 组件需要在 stencil 和 content 前后都添加修改 gl 状态的 render command,因此使用 Mask 会打断我们的 DrawCall 批处理。


对于一些特殊的显示,例如圆角的 icon 等,如果条件允许,尽量不要使用 Mask 组件来进行处理,而是通过对资源进行处理达到同样的效果。


目前 Mask 组件、Spine 组件、DragonBone 组件都会打断批处理,在节点结构上我们要避免被打断的情况发生。



在这个 demo 当中,每一个 icon 都有一个使用了 Mask 组件的子节点,我们去除它,效果如下:



最终就只有 18 个 DrawCall,基本上是极限地 DrawCall 优化了。毕竟 ScrollView 本身就有一个 Mask 组件,这个组件我们无法避免,必须要使用。


5、复用 Cell 节点,减少节点数


对 Cell节点进行复用,减少节点数,这一块改动比较大。前面都是对 DrawCall 的优化,但实际的节点数量还是很多。当显示或隐藏这个界面时,大量的节点会带来大量的 enable 和 disable 的开销。


因此我们通过复用节点,根据滑动情况实时更新 Cell 位置以及显示内容的方式,减少节点的数量。具体操作可以参考[Cocos Creator 官方示例]中的 ListView 示例。


原理如下:



具体代码可以参考 demo 工程中的 ScrollView 3 场景的实现,最终效果如下:



20 个 Cell 的 ScrollView,实际上只是 7 个 Cell 节点在不停的复用显示,从而表现出来的。与之前的效果以及 DrawCall 相同,但实际使用的节点数大大降低,大约有 300 个节点,相比较之前的 1000 个节点大幅降低。


6、分帧加载节点与节点快照


由于背包模块的需求,往往首次需要同步加载并显示多个 Cell 节点,所以往往会造成加载卡顿、加载崩溃等问题,针对这个问题,我们提出了分帧加载节点与 renderTexture 节点快照组合而成的优化方案。


分帧加载方案,主要利用的是 ES6 特性中的异步加载方案:Generator(协程)。下面是节选自本次分享会 PPT 中的对协程执行流程的讲解:



协程能够有效地暂停当前语句并将转移它的执行权,等待执行权返回。这个过程可以一直重复,直到语句执行完毕。分帧加载方案就是利用协程的这一点特性,在每次语句循环执行时,将加载代码的执行权转移给下一帧去执行,从而达到分帧加载的效果。


节点快照方案的原理是:首先放置一个 Cell 参考节点,放置在可渲染但是不可见的区域(可通过多摄像机实现)。之后每当需要新增一个 Cell 节点,都让 Cell 参考节点去做相应变换,变换结束后利用 Camera 和 RenderTexture 将渲染结果[截图]下来,再交由 Content 中新增的 简易 Cell 节点渲染出来即可。


未优化前,500 个 Cell 节点 DrawCall 达到 2514 个,总节点数达到节点总数 3048 个。



优化后的效果如下:


优化完之后,加载完成时 DrawCall 稳定为 18 个,节点总数 548 个,效果显著。


以上就是一些常用的 ScrollView 性能优化手段,欢迎大家在 Cocos 论坛上一起讨论更有价值的游戏优化方案。


参考文档


查看截图方案

https://docs.cocos.com/creator/manual/zh/render/camera.html#%E6%88%AA%E5%9B%BE


Auto-atlas Asset:

https://docs.cocos2d-x.org/creator/2.1/manual/en/asset-workflow/auto-atlas.html


UI 渲染批次合并指南:

https://docs.cocos.com/creator/manual/zh/advanced-topics/ui-auto-batch.html


背包模块优化方案地址:

https://github.com/Jno1995/ScrollViewTest



演讲视频



搭配 PPT 观看更棒哦,在公众号内输入【性能优化】可获取演讲 PPT。




极限开发《TheCode》和《Shoot the F》创作笔记

Cocos Creator 2.1.3 正式发布

Cocos 荣耀讲师征集计划

微信创意小游戏橙皮书发布

用 Cocos Creator 制作平台跳跃游戏

Cocos技术派|3D小游戏《快上车》技术分享

Cocos海外开发者专访:遗憾的是没早点开始做游戏

我的小游戏开发之路|腾讯TGideas周桂华(花叔)

Gameloft 如何打造 Facebook 小游戏玩转越南市场

Cocos Creator 零基础入门教程 | 免费

Cocos 引擎 UI 全新升级:进一步提升编辑器体验



我就知道你“在看”▼

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存