cocos2dx的label如果使用的ttf时,是无法合批的
原因分析
可以看到label的draw函数
void Label::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags){ if (!_shadowEnabled && (_currentLabelType == LabelType::BMFONT || _currentLabelType == LabelType::CHARMAP)) { _quadCommand.init(_globalZOrder, texture, getGLProgramState(), _blendFunc, textureAtlas->getQuads(), textureAtlas->getTotalQuads(), transform, flags); renderer->addCommand(&_quadCommand); } else { _customCommand.init(_globalZOrder, transform, flags); _customCommand.func = CC_CALLBACK_0(Label::onDraw, this, transform, transformUpdated); renderer->addCommand(&_customCommand); } }
label的类型不同,会采用不同的renderCommand,而ttf类型使用的CustomCommand
QuadCommand _quadCommand; CustomCommand _customCommand;
而当使用bmfont时,使用的QuadCommand
是继承自TrianglesCommand
class CC_DLL QuadCommand : public TrianglesCommand
从渲染逻辑框架中,我们看到只有TRIANGLES_COMMAND
才能进行合批处理
所以,无论你怎么对label节点进行排序,都无法完成合批操作,因为渲染流程压根就不支持。
怎么支持合批
一种比较彻底的方式就是,调整render流程,就像TrianglesCommand
那样,将CMD收集起来,然后再进行合批处理,但是这样的话,改动非常大,毕竟渲染流程是整个engine正常运行的基础,如果没有充裕的时间,大概率重构出来的新渲染流程经不起项目考虑,况且这种级别的重构,非常考验个人的见识和架构能力,是一项非常充满挑战性的工作。
另外一个方式相对来说改动不是那么大,主体思路就是在ttf模式下,我们不使用CustomCommand
,继续使用QuadCommand
就能在原有渲染框架下完成合批,那么要解决的问题就变成了:
怎么在ttf模式下使用QuadCommand
或者TrianglesCommand
?
现有的CustomCommand
所做的事情大概如下:
- 先绘制阴影效果
- 当有描边时,绘制描边后的效果
- 再绘制字体本身的效果
可以看到描边是一个非常特殊的操作,会发生多次draw
要使用TrianglesCommand
模式完成以上的流程,其实还是挺麻烦的,因为label的效果不同,所使用的shader也不同,而TrianglesCommand
是对应的固定shader,要实现合批,就不能像现在那样动态切换shader,所以我们就不得不把带有文字效果的图片,集中放到一个RenderTexture里面。
其实这里面还牵扯到FontAtlas的问题,因为这里面存储的是从freetype绘制的位图字体文件,如果放到RenderTexture后,这个fontAtlas就是一个中间的缓冲池,这个fontAtlas可以避免我们重复生成位图字体文件,可能我们也需要处理这个中间文件,因为有些情况下某些字体配置创建一次后就再也不会使用这种情况的字体配置了,当然这算是优化了。
顺着RenderTexture
的逻辑往下走,其实问题就变成了如何得到带有effect的字体位图,因为描边、阴影等效果都是动态生成的,这里可以考虑使用frame buffer,不过我就fbo就不太了解了,后续再展开这个思路。