版本:2.4.3

参考:

Cocos Creator 性能优化:DrawCall(全面!)

【乐府】突破动态合图-你真的把动态合图用对了吗?

cocos文档-动态合图 

 

主要是看论坛水友陈皮皮的文章《Cocos Creator 性能优化:DrawCall》,实际测试下drawcall。

 

一 动态合图测试

二 AABB+ABAB测试

三 自动合图测试(Auto Atlas)

四  系统字体文本测试 

五 BMFont文本测试

六 遇到问题

 

一 动态合图测试

开始动态合图,代码需要写在项目脚本中的最外层,不要在start或onLoad中禁用,确保在项目加载过程中即时生效。否则如果在部分贴图缓存已经释放的情况下才启用动态图集,可能会导致报错。 

const {ccclass, property} = cc._decorator;

//是否在将贴图上传至 GPU 之后删除原始图片缓存,删除之后图片将无法进行 动态合图。 
//web平台不需要开启,因为web平台Image占用内存小。
//小游戏平台默认开启,避免内存占用过高。
cc.macro.CLEANUP_IMAGE_CACHE = false;
//动态合图开关
cc.dynamicAtlasManager.enabled = true;

@ccclass
export default class Helloworld extends cc.Component {
    start(){
        console.log(cc.macro.CLEANUP_IMAGE_CACHE, cc.dynamicAtlasManager.enabled);
    }
}

 

使用4张碎图,理论4碎图+1调试信息文本 = 5 drawcall,但是实际测试drawcall是2。

 

这是因为web默认开启了动态合图。动态合图会额外占用内存,不同平台内存占用不一样。

web平台默认开启动态合图。

小游戏和原生平台默认关闭动态合图。

 

关闭动态合图后,可以看到4碎图+1调试信息 = 5 drawcall。

 

 

1. 动态合图设计目的是因为项目过大贴图过多,导致很难使用静态合图Auto Atlas将图片合并到一个图集上。

2.动态合图会占用内存,在小游戏和原生平台默认关闭。

3.动态合图最大张数5张,单张合图最大2048*2048。 (测试将动态合图的maxAtlasCount=1,使用完后并不会重建,只有切换场景才会重建...

4.如果一直不切换场景,那么随着动态合图的数量增长,渲染效率可能会降低,适得其反。

5.动态合图不用,记得剔除“Dynamic Atlas”模块以减小引擎包体。

6.动态合图源码在引擎目录resources\engine\cocos2d\core\renderer\utils\dynamic-atlas。

 

二  AABB+ABAB测试

现有两个图集,texture和texture2。图集texture中有icon1和icon2,图集texture2中有icon3和icon4。

 

相同图集的图并列摆放,2个图标+2个图标+1调试信息=3 drawcall

    

 

两个图集的图标交叉摆放,2个图标+2个图标+1调试信息 = 5 drawcall

  

 

总结:来自同一图集的图片并列摆放,可以减少drawcall。

 

三 自动合图测试(Auto Atlas)

静态合图可以使用TexturePacker或者AutoAtlas。

因为TexturePacker比较麻烦,每次美术增加或修改了UI,你得再用软件去合图一次, 所以还是直接使用AutoAtlas。

自动合图需要构建时才会生效,平时调试时不会生效的。

 

总结:

使用AutoAtlas。

 

四  系统字体文本测试 

1 系统字体文本打断渲染合批

 

 如果添加系统字体文本label,则会打断合并批次提交。

2 icon_001 + 1调试信息 + 1文本 = 4 drawcall

 

 

2 文本三种缓存模式

 

NONE:

没有任何操作,3个文本会打断icon渲染合批,并且3个文本算3个drawcall。

2icon_001 + 3文本 + 1调试信息 = 6 drawcall

 

BITMAP:

如果关闭动态合图,则这一项没用。依然是

2icon_001 + 3文本 + 1调试信息 = 6 drawcall。

如果开启动态合图,则icon和文本会合并,2个icon和3个文本相当于1个drawcall。

2icon_001 + 3文本 + 1调试信息 = 2 drawcall

 

CHAR:

共享位图的最大尺寸为 2048*2048,占满了之后就没办法再渲染新的字符,需要切换场景才会清除共享位图。

和动态合图无关,字符会缓存到一张图上,所以3个文本相当于1个drawcall。

2icon_001 + 3文本 + 1调试信息 = 4 drawcall

 

总结:

 选择CHAR模式,并将文本并列排放,则能减少文本带来的drawcall。

选择Bitmap模式并且开启动态合图,可以减少文本带来的drawcall。

 

五 BMFont文本测试

1. BMFont会打断渲染合批

2icon_001 + 2BMFont + 1调试信息 = 5 drawcall

 

 

 

 

 2. BMFont没有缓存模式,可以参与Auto Atlas静态合图。

将BMFont的图片和icon图标一起静态合图

2 icon + 2 BMFont + 1 调试信息 = 2 drawcall

 

总结:

大部分BMFont基本都是通用型,可能贯穿游戏很多个界面,所以合图到通用common的大图上比较合适。

在关闭动态合图的情况下,BMFont和系统字体CHAR一样,只能相邻排放来减少drawcall。

 

六 遇到问题

1 显示动态合图的调试信息问题

在浏览器里输入 cc.dynamicAtlasManager.showDebug(true) 可以显示动态合图调试信息,会将动态合图展示在场景上的一个scrollView中。

如果看不见,在场景中放一个cc.Label,设置cacheMode为Bitmap,然后在start里移动合图的node的x和y,才能看得见动态合图。

        let node: cc.Node = cc.dynamicAtlasManager.showDebug(true);
        node.x = 1000;
        node.y = 0;
        console.log(node.x, node.y, node.width, node.height);

  

2 使用autoaltas自动合图能参与动态合图吗

 选择autoaltas,在属性栏中勾选Packable后,可以参与动态合图

 

 

 

但是自动图集超过动态合图的限制,例如512x512之后,自动图集则不会参与动态合图了。

 

3  使用TexturePacker的合图能参与动态合图吗

能参与。无论只用texturePacker大图中其中一张小图,还是多张小图,动态合图时整个大图会合到动态合图中。

所以当TexturePacker的图超过动态合图限制例如512x512时就不会参与动态合图了。

 

4 骨骼动画能不能参与动态合图

不能

摆一个骨骼动画到场景中

 

 cc.dynamicAtlasManager.showDebug(true)显示的调试信息,可以看到骨骼动画并没有参与动态合图。

 

5 文本的Bitmap模式,文字无法重复使用问题

比如一个界面的标题文本设置为了Bitmap,每次进入这个界面,都会添加一次这个标题到动图,而不是重用使用上次的。

现在有个Prefab如下,标题cc.Label的cacheMode设置为Bitmap,重复的创建和destroy这个Prefab。

 

用cc.dynamicAtlasManager.showDebug(true)显示动态合图。

 

可以看到图片仅仅有1张,表示是可重复使用的。

而cc.Label文本则有很多重复的,表示文字不是重复使用的。假如界面中大量使用cc.Label并且模式为Bitmap,由于文本无法重复使用,动图的数量很快就消耗光了。

 

6 资源被release后,会重复添加进动图

还是上面那个Prefab,重复的创建和destroy,destroy后用cc.resources.release资源。

用cc.dynamicAtlasManager.showDebug(true)显示动态合图。

 

 可以看到图片资源如果release后,下次再使用时,动态合图会将图片再添加进动图一次。

 

8 使用cc.dynamicAtlasManager.reset()重建图集

reset会销毁已创建的动态图集,如果直接使用,界面上参与动态合图的cc.Sprite和cc.Label都会变黑了。

所以在reset调用之前,需要将有使用动态合图的prefab都销毁掉,在reset调用之后,再重新创建这些prefab。

 

源码在:Creator\2.4.4\resources\engine\cocos2d\core\renderer\utils\dynamic-atlas\manager.js中

 

 

9 单场景+Prefab无法重置char文本合图问题

char合图的清理是在切换场景时触发的,但是单场景+多Prefab的游戏不需要切换场景,所以只能手动调用清理。

查看源码,没发现可以手动调用的API。源码在:resources\engine\bin\.cache\dev\cocos2d\core\renderer\utils\label\letter-font.js

暂时只能调用下面事件来触发清理char合图
cc.director.emit(cc.Director.EVENT_BEFORE_SCENE_LAUNCH);  

  

调用该事件后,有3个地方监听了该事件,所以会做3个事情
1.重置char合图
2.重置动态合图
3.重置粒子对象池

 

posted on 2021-01-05 15:00  gamedaybyday  阅读(2431)  评论(9编辑  收藏  举报