CCSpriteBatchNode
a和 normal之间的主要区别在于CCSprite
,a 一次CCSpriteBatchNode
将所有精灵的所有数据发送到 GPU,而不是为每个精灵执行此操作。
绘图调用的CCSprite
工作方式如下:
glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (void*) (offset + diff));
glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (void*)(offset + diff));
glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (void*)(offset + diff));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
基本上会进行 3 次调用来设置精灵的数据,然后调用到glDrawArrays
。如果您有 100 个精灵,则此代码将执行 100 次。
现在让我们看一下CCSpriteBatchNode
(我选择了没有VAO的实现,这是另一种可能的优化):
glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, vertices));
glVertexAttribPointer(kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, colors));
glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof( ccV3F_C4B_T2F, texCoords));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffersVBO_[1]);
glDrawElements(GL_TRIANGLE_STRIP, (GLsizei) n*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(indices_[0])) );
现在这段代码一次设置了所有精灵的所有数据,因为它存储在连续的内存中。这个调用对于 1、10、100 都是一样的,不管精灵的数量是多少。
这就是它更高效的原因,但同时,由于数据连续存储在内存中,当删除或添加或修改子项时,必须相应地更改数组并在 GPU 中更新。这就是添加和删除成本的来源(甚至隐藏的 CCSprite 只是跳过渲染阶段,而批处理节点中的隐藏 CCSprite 则不会)
根据个人经验,我可以告诉您,成本通常可以忽略不计,并且您应该始终CCSpriteBatchNode
在可能的情况下使用 a(因为它们有其限制,例如在整个节点上混合而不是基于每个精灵和类似的东西)并且当您绘制多个相同类型/原因的精灵。
不过,为自己设定基准应该很容易。