游戏滚动列表的优化(降低drawcall从154降低到14,图片大小,界面逻辑)
前因:
领导对于商城按钮点击切换卡顿非常不满,趁这次商城修改,顺便研究一下优化方案。
观察:
打开cocoscreator show FPS按钮,可以看到一些端倪。
第一眼看到drawcall比较高:154,三角形的顶点也很高,切换桌布和壁纸时渲染时间也会变高。
解决:
第一步,关闭商城界面后的大厅界面。在仅仅只展示商城界面背景时,drawcall还是有50左右,并且三角形的数量还是非常高。
这就非常奇怪了,这个界面明明是全屏,drawcall和triangle怎么还是这么高?
然后又想到,原来是大厅的界面还在渲染着,ui界面是没有深度测试的,所有场景上的节点都会加入到drawcall中。
第1点:那么第一步要优化的就是这里了,对于全屏界面可以把其他场景和摄像机关闭,顺便把商城中同一静态合集中的图片放到临近的位置。
drawcall和三角形数量瞬间下降。
第2点:把相关图片缩放到合适的大小重新保存到一个新文件中,并加入静态图集。
查看到对于壁纸和桌布中的图片是根据大图直接缩小放置的。
渲染过程中缩放会进行插值计算,甚至是多次插值;并且图片的数据大小也会影响读取的速度;还有就是小图可以放到一个静态图集中,可以参与合批。
第3点:修改滚动列表节点逻辑。
最终要重新设计这个滚动列表了,滚动列表中加入的每个节点都是单独一体的,总是打断合批,导致drawcall很高,再仔细理解一下合批策略。
引用自:2D 渲染组件合批说明 · Cocos Creator
2D 渲染组件合批规则说明
合批条件说明
2D 渲染组件合批的规则是节点的 layer、使用的材质、渲染组件的 blendState 和 DepthStencilState 相同、贴图源以及贴图采样都相同才会进行合批。 下面我们就分别说明一下这些条件:
- 节点的 layer:由于 layer 会涉及到渲染与否,所以不同的 layer 之间不能进行合批
- 材质:材质相同是合批的必然要求,由于我们使用的材质实例化的机制,所以用户在设置了材质的 uniform 之后材质会进行实例化,实例化之后的材质是无法进行合批的,如果自定义材质进行了 uniform 设置之后导致此组件无法合批,之后 uniform 值使用完毕想要该组件参与合批,可将材质资源重新赋值给组件即可重新使组件参与合批(通过 CustomMaterial 接口赋值即可)
- BlendState 状态:对于部分 2D 渲染组件可以在面板上设置部分的 BlendState 值,这个值不同的话是无法进行合批的
- DepthStencilState 状态:这个值控制着组件的深度检测和模板缓冲,一般来说用户不需关心这个值的设置,这个值由引擎自动控制(用于 Mask 的效果实现)
- 贴图源和贴图采样:一般来说,这个条件是影响合批的最主要的条件,尤其对于精灵和文本来说,贴图很容易产生差别导致无法合批。引擎提供了部分方法来实现更好的合批,可参考后文。
合批方法说明
结合以上的合批条件说明,我们可以通过一些方法来实现更好的合批方法,需要额外说明的是,2D 渲染组件的渲染数据采集是一个基于节点树的渲染方式,而一些组件是会打断合批的,目前引擎的内置组件 Mask,Graphics,UIMeshRenderer 由于材质不同和数据组织方式的差异会无法与其他组件合批,而 TiledMap,Spine 和 DragonBones 这三个中间件组件遵循自己的内部合批机制,所以上述组件都无法合批,且会打断其他组件合批,需要用户进行分模块管理节点树布局,以达到更好的合批效果。
那能想到的办法就是分批子节点。
如果操作?
目前的树节点逻辑是:
导致drawcall很多的原因就是子节点间会打断drawcall,子节点越多,drawcall越多。
想要解决这个问题就要改变子节点的节点逻辑。
如图中,把同一图集中的节点放到同一个父节点中。这样就不会打断drawcall,即便是子节点越来越多drawcall也不会随子节点数量同比增长。
所以最终展示出来的drawcall界面就是14。
从154降低到14,这样是不是就是最终优化版本了?
第4点:不重新搭建界面。
drawcall已经很难大幅度优化了,得从别的地方下手,切换桌布和壁纸界面时,会把滚动列表中所有子节点清空,重新克隆新建,修改图片数据。这样在快速切换桌布和壁纸界面时会导致渲染时间变长,新的策略就是使用两个滚动列表,打开一个时就把另一个关闭。
最终的效果就是,在低端机型上来回切换壁纸和桌布FPS会降低到10以下,现在则能稳定保持在30以上。
如果觉得我说的还不错,感谢点赞~