cocos2dx 实现 SpriteBatchNode合批

234 阅读2分钟

之前实现了MultiTexture,想要在SpriteBatchNode中也使MultiTexture生效。

SpriteBatchNode细节

  • SpriteBatchNode下边的Child Sprite必须是使用相同的纹理
  • 凡是加到SpriteBatchNode下边的children都不会被visit,所以也不用担心那些Sprite会提交RenderCommand了
// override visit
// don't call visit on it's children
void SpriteBatchNode::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t parentFlags)
{
}

因为SpriteBatchNode使用了BatchCommand,而BatchCommand是不能合批的。

要让SpriteBatchNode也受MultiTexture影响实现合批,2个思路:

  1. BatchCommand迁徙到TrianglesCommand。

  2. 仅改造SpriteBatchNode就行了,这样的影响范围最小。

内存上限

realloc尝试重新调整之前调用 malloc 或 calloc 所分配的 ptr 所指向的内存块的大小。理论没有上限制

不需要自己额外申请内存,借用BatchCommand的TextureAtlas的即可

render的memory size问题

static const int VBO_SIZE = 65536;
V3F_C4B_T2F _verts[VBO_SIZE];// 直接申请了一个很大内存的空间,用来存放顶点数据
memcpy(&_verts[_filledVertex], cmd->getVertices(), sizeof(V3F_C4B_T2F) * cmd->getVertexCount());

如果超过了内存大小,就会提交一个批次,即使能够合批

测试数据

使用SpriteBatch会提升渲染性能,相反create性能有轻微的影响。

  • windows: 3w个Sprite
--batchnormal
fps2111
creat time1.43s1.36s
  • android: 1w个Spirite
--batchnormal
fps1313.7
creat time0.75s0.82s

shader

    setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP, texture));
    setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR, tex));

BatchCommand

batchCommand使用TextureAtlas进行了渲染。

  • draw和TrianglesCommand的VertexAttributePointer是相同的,可以合并
// vertices
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof(V3F_C4B_T2F, vertices));
// colors
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (GLvoid*) offsetof(V3F_C4B_T2F, colors));
// tex coords
glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof(V3F_C4B_T2F, texCoords));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _buffersVBO[1]);
// GLAPI void GLAPIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
glDrawElements(GL_TRIANGLES, (GLsizei)numberOfQuads*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(_indices[0])));

是存放在

ssize_t             _totalQuads; // 要绘制的四边形数量,一个四边形是由2个三角形组成
GLushort*           _indices; // 索引数据,在确定容量后,直接对所有顶点索引数据进行了填充,只需要一次即可
V3F_C4B_T2F_Quad*   _quads;   // 顶点数据
quadvertexindices
146
2812
31218

合批示例

配置多纹理:

MultiTexturePackage(plist1.png / plist2.png

Node结构如下:

  • Node
    • SpriteBatchNode1(plist1.png
      • Sprite1(plist1-a.png)
      • Sprite2(plist1-b.png)
    • SpriteBatchNode2(plist2.png
      • Sprite1(plist2-a.png)
      • Sprite2(plist2-b.png)

此时就会触发多纹理和SpriteBatchNode进一步合批,DrawCall为1

vs2019的一个bug

image.png