cocos2dx Sprite使用同一张纹理会只调用一次渲染
2017-02-22 01:12
447 查看
cocos2dx3.x中,Sprite调用draw函数时会添加一个TrianglesCommand类型的渲染指令。
在render执行这个指令时,TrianglesCommand并不会立即执行opengl的渲染,而是把它添加到一个std::vector
这里做了一个限制,如果当前顶点缓冲区满了,就会立即执行opengl的渲染,所以当Sprite足够多时,虽然他们使用的是同一张纹理,也会调用多次渲染。
这个函数就是用来绘制TriangleCommand指令的,这里出现了一个新的类型TriBatchToDraw
TriBatchToDraw 有三个成员变量,渲染指令cmd,需要渲染的顶点数量indicesToDraw,顶点数据在顶点缓冲区初始的偏移位置offset
如果一个渲染指令的MaterialID和上一个指令的MaterialID相等,就会把两条渲染指令整合到一起,如果两条指令使用了相同的MaterialID但是两条指令不连续,就不会整合到一个渲染指令里。
所以cocos2dx的Sprite使用同一张纹理时,必须是连续添加到父节点,中间不会有使用其他纹理的Sprite添加到父节点,才会达到SpriteBatchNode的效果
CCSprite.cpp
_trianglesCommand.init(_globalZOrder, _texture, getGLProgramState(), _blendFunc, _polyInfo.triangles, transform, flags); renderer->addCommand(&_trianglesCommand);
在render执行这个指令时,TrianglesCommand并不会立即执行opengl的渲染,而是把它添加到一个std::vector
CCRender.cpp
if( RenderCommand::Type::TRIANGLES_COMMAND == commandType) { // flush other queues flush3D(); auto cmd = static_cast<TrianglesCommand*>(command); // flush own queue when buffer is full if(_filledVertex + cmd->getVertexCount() > VBO_SIZE || _filledIndex + cmd->getIndexCount() > INDEX_VBO_SIZE) { CCASSERT(cmd->getVertexCount()>= 0 && cmd->getVertexCount() < VBO_SIZE, "VBO for vertex is not big enough, please break the data down or use customized render command"); CCASSERT(cmd->getIndexCount()>= 0 && cmd->getIndexCount() < INDEX_VBO_SIZE, "VBO for index is not big enough, please break the data down or use customized render command"); drawBatchedTriangles(); } // queue it _queuedTriangleCommands.push_back(cmd); _filledIndex += cmd->getIndexCount(); _filledVertex += cmd->getVertexCount(); }
这里做了一个限制,如果当前顶点缓冲区满了,就会立即执行opengl的渲染,所以当Sprite足够多时,虽然他们使用的是同一张纹理,也会调用多次渲染。
CCRender.cpp
void Renderer::drawBatchedTriangles() { if(_queuedTriangleCommands.empty()) return; CCGL_DEBUG_INSERT_EVENT_MARKER("RENDERER_BATCH_TRIANGLES"); _filledVertex = 0; _filledIndex = 0; /************** 1: Setup up vertices/indices *************/ _triBatchesToDraw[0].offset = 0; _triBatchesToDraw[0].indicesToDraw = 0; _triBatchesToDraw[0].cmd = nullptr; int batchesTotal = 0; int prevMaterialID = -1; bool firstCommand = true; for(auto it = std::begin(_queuedTriangleCommands); it != std::end(_queuedTriangleCommands); ++it) { const auto& cmd = *it; auto currentMaterialID = cmd->getMaterialID(); const bool batchable = !cmd->isSkipBatching(); fillVerticesAndIndices(cmd); // in the same batch ? if (batchable && (prevMaterialID == currentMaterialID || firstCommand)) { CC_ASSERT(firstCommand || _triBatchesToDraw[batchesTotal].cmd->getMaterialID() == cmd->getMaterialID() && "argh... error in logic"); _triBatchesToDraw[batchesTotal].indicesToDraw += cmd->getIndexCount(); _triBatchesToDraw[batchesTotal].cmd = cmd; } else { // is this the first one? if (!firstCommand) { batchesTotal++; _triBatchesToDraw[batchesTotal].offset = _triBatchesToDraw[batchesTotal-1].offset + _triBatchesToDraw[batchesTotal-1].indicesToDraw; } _triBatchesToDraw[batchesTotal].cmd = cmd; _triBatchesToDraw[batchesTotal].indicesToDraw = (int) cmd->getIndexCount(); // is this a single batch ? Prevent creating a batch group then if (!batchable) currentMaterialID = -1; } // capacity full ? if (batchesTotal + 1 >= _triBatchesToDrawCapacity) { _triBatchesToDrawCapacity *= 1.4; _triBatchesToDraw = (TriBatchToDraw*) realloc(_triBatchesToDraw, sizeof(_triBatchesToDraw[0]) * _triBatchesToDrawCapacity); } prevMaterialID = currentMaterialID; firstCommand = false; } batchesTotal++; /************** 2: Copy vertices/indices to GL objects *************/ auto conf = Configuration::getInstance(); if (conf->supportsShareableVAO() && conf->supportsMapBuffer()) { //Bind VAO GL::bindVAO(_buffersVAO); //Set VBO data glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]); // option 1: subdata // glBufferSubData(GL_ARRAY_BUFFER, sizeof(_quads[0])*start, sizeof(_quads[0]) * n , &_quads[start] ); // option 2: data // glBufferData(GL_ARRAY_BUFFER, sizeof(_verts[0]) * _filledVertex, _verts, GL_STATIC_DRAW); // option 3: orphaning + glMapBuffer // FIXME: in order to work as fast as possible, it must "and the exact same size and usage hints it had before." // source: https://www.opengl.org/wiki/Buffer_Object_Streaming#Explicit_multiple_buffering // so most probably we won't have any benefit of using it glBufferData(GL_ARRAY_BUFFER, sizeof(_verts[0]) * _filledVertex, nullptr, GL_STATIC_DRAW); void *buf = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); memcpy(buf, _verts, sizeof(_verts[0]) * _filledVertex); glUnmapBuffer(GL_ARRAY_BUFFER); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _buffersVBO[1]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(_indices[0]) * _filledIndex, _indices, GL_STATIC_DRAW); } else { // Client Side Arrays #define kQuadSize sizeof(_verts[0]) glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(_verts[0]) * _filledVertex , _verts, GL_DYNAMIC_DRAW); GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); // 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]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(_indices[0]) * _filledIndex, _indices, GL_STATIC_DRAW); } /************** 3: Draw *************/ for (int i=0; i<batchesTotal; ++i) { CC_ASSERT(_triBatchesToDraw[i].cmd && "Invalid batch"); _triBatchesToDraw[i].cmd->useMaterial(); glDrawElements(GL_TRIANGLES, (GLsizei) _triBatchesToDraw[i].indicesToDraw, GL_UNSIGNED_SHORT, (GLvoid*) (_triBatchesToDraw[i].offset*sizeof(_indices[0])) ); _drawnBatches++; _drawnVertices += _triBatchesToDraw[i].indicesToDraw; } /************** 4: Cleanup *************/ if (Configuration::getInstance()->supportsShareableVAO()) { //Unbind VAO GL::bindVAO(0); } else { glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } _queuedTriangleCommands.clear(); _filledVertex = 0; _filledIndex = 0; }
这个函数就是用来绘制TriangleCommand指令的,这里出现了一个新的类型TriBatchToDraw
struct TriBatchToDraw { TrianglesCommand* cmd; // needed for the Material GLushort indicesToDraw; GLushort offset; };
TriBatchToDraw 有三个成员变量,渲染指令cmd,需要渲染的顶点数量indicesToDraw,顶点数据在顶点缓冲区初始的偏移位置offset
如果一个渲染指令的MaterialID和上一个指令的MaterialID相等,就会把两条渲染指令整合到一起,如果两条指令使用了相同的MaterialID但是两条指令不连续,就不会整合到一个渲染指令里。
所以cocos2dx的Sprite使用同一张纹理时,必须是连续添加到父节点,中间不会有使用其他纹理的Sprite添加到父节点,才会达到SpriteBatchNode的效果
相关文章推荐
- 渲染到纹理(Render to texture):使用FrameBuffer
- 处理2D图像和纹理——使用SpriteBatch类显示2D图像:加载和绘制图像
- 实例:使用纹理对象创建Sprite对象
- [cocos2dx笔记013]一个使用CCRenderTexture创建动态纹理显示数字的类
- cocos2dx 使用jni实现java调用c++
- 使用mesh渲染复杂模型(调用.x 文件)
- cocos2dx 与android函数的互相调用及使用jni
- 罗大柚OpenGL ES教程系列_LessonY_使用2D纹理渲染文字
- cocos2d-x 常用代码、高频使用代码【CCLayer、CCEditBox编辑框、CCControlButton按钮、CCLabelTTF标签、CCSpriteBatchNode渲染、CCMen】
- 探cocos2dx裁剪结点、拖尾效果、进度效果、渲染纹理实现(misc_nodes),源码版本(2.2.3)
- 利用DSHOW中的VMR9 filter 将视频渲染成纹理 供D3D使用
- 【loadrunner使用篇】LR调用QTP脚本来实现性能测试(一次现场特殊需求的解决方案)
- cocos2d使用纹理渲染需要注意的地方
- 实例:使用纹理对象创建Sprite对象
- cocos2dx 使用Texturepacker制作纹理相册以及使用
- 使用渲染到纹理例子
- WebGL自学课程(5):使用一张贴图纹理绘制地球
- opengl离屏渲染(不需要和窗口绑定,仅当作一个可以渲染一张图片的API使用)+ opencv显示
- CCTextureAtlas(Atlas地图集图册-表示将小纹理组成一张纹理集以达到批量渲染目的 方法->TextureAtlas维护了一个ccV3F_C4B_T2F_Quad数组)
- HTML如何使用一张图片做背景只显示一次