cocoscreator 浅析Label 的三种缓存模式

为了解决系统字经常打断合批的问题,cocos提供了三种缓存模式:官网文档

image.png

CacheMode.NONE: 先用网页canvas渲染文字,然后用Texture2D.initWithElement(canvas)获取纹理
CacheMode.BITMAP: 跟CacheMode.NONE差不多,区别就是会将实时获取到的纹理放到动态合集里,于是就能跟附近的同类型Label或者使用动态图集的Sprite进行合批。
CacheMode.CHAR:会先将label拆成一个个单独的字,每一个字都用以上的方法获取生成的纹理,放在一个专门存放此类字符纹理的大图内,然后渲染的时候使用多个顶点,按每个字符一个矩形渲染。

我们先来看下几种缓存模式下运行时的区别
image.png

如上图,None模式下,每个label都占一个drawcall,即使内容相同也不例外,此时内存中三个label纹理+一个sprite纹理+FPS label纹理。
Bitmap模式下,三个Label和Sprite共占一个drawcall,是因为三张label的纹理和sprite的纹理打到了一个动态图集里面。我们可以打印出动态图集:

let _debugNode = cc.dynamicAtlasManager.showDebug(true);
_debugNode.getComponent(cc.ScrollView).content.children[0].color = cc.Color.RED
_debugNode.scale = 0.5;
image.png

红色的就是动态图集,可以注意到即使是一模一样的Label,在自动图集里也不会共用贴图,有多少个BITMAP缓存模式的Label,就有多少份字体贴图,所以如果我们的游戏里有大量相同的label,更加适合用CHAR缓存模式。

再看CHAR模式,CHAR模式下相当于是全局共用一个2048x2048的位图字体:cc.Label._shareAtlas
我们打印一下该字体的纹理:

let shareLabelTex = cc.Label._shareAtlas.getTexture()
let spr = _debugNode.getComponent(cc.ScrollView).content.children[0].getComponent(cc.Sprite)
spr.spriteFrame.setTexture(shareLabelTex)
image.png

从上图顺便可以看出,系统FPS信息Label就是用的CHAR模式。

下面我们跟着Label源码来看看,几种模式分别是怎么装配渲染数据的

我们今天讨论的范围是非native环境下2d系统字。


image.png

从这段代码可知,CHAR模式下对应的Assembler是Letter,NONE模式和BITMAP模式的Assembler都是TTF。Label组件就是通过这些Assembler将字体数据变成纹理数据进而显示的,先看看他们是怎么关联的:


image.png

每次系统字相关设置发生变化,组件都会调用_applyFontTexture重新初始化纹理数据,非CHAR模式下,是直接创建一个新的Texture2D纹理,通过canvas初始化(红框部分)。
而每次诸如Label.string发生改变后,会更新渲染数据,让canvas重新绘制字体,从而使_ttfTexture得到刷新:
(因为用到了web端的画布渲染,所以显然不能适用于native端,native端另有适配)

尝试写入一份纹理拷贝到自动图集

NONE模式和BITMAP模式的Assembler都是TTF,唯一的区别就是BITMAP模式下,会在生成完纹理后,将该纹理拷贝一份到自动图集,然后使用自动图集里面的内容。所以BITMAP的优势是能与周围使用自动图集的碎图一起合批,但同时也会加大自动图集的消耗。内容或字体大小等频繁变化的不要使用BITMAP模式,因为每刷新一次,就会拷贝一次最新纹理到自动图集。

关于CHAR模式,就有点绕了,生成纹理的方式还是一样,但不是 每个Label生成一个纹理,而是每个先把Label字符串分开,按每个字符去生成纹理,然后尝试拷贝纹理到共用的LetterAtlas大图,然后下次再遇到相同参数的字符,就直接取大图纹理。


image.png

上图中,红色的就是CHAR LABEL的公共纹理,可以看到,字体大小不同时,即使内容相同,也会使用不同的纹理内容。


image.png

所谓相同参数,就是上图的shareLabelInfo的color、fontSize、fontFamily、outline、margin,然后再与字符内容相加,得到的hash值,然后维护一个_letterDefinitions表,每增加一个新的letterTexture,就拷贝一份到公共大纹理,然后保存纹理坐标、宽、高等信息,hash为键值。


image.png

其实跟向动态图集插入纹理差不多,只不过系统字刚好有一些可以比较衡量的参数,所以比动态图集更方便的是可以判断某个小的字符纹理有没有被加到大图中,有的话就直接取。

然后再一点就是CHAR模式下,顶点数据有所不同,普通的Sprite或者Label,都是一个矩形、4个顶点、两个三角形,CHAR模式下,每个字符所用的纹理是不连续的,可能在大图中的任意位置,所以必须每个字符使用一套纹理坐标,有n个字符,就有n x 4个顶点。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容