QuadCommand

来源:互联网 发布:马步芳 知乎 编辑:程序博客网 时间:2024/06/05 09:38

功能:

这个命令主要用来绘制一个或多个矩形区域。相邻的QuedCommand如果使用相同的纹理,就可以实现自动批绘制。提高绘制效率。

 

条件:

1、不包含自定义的着色器全局变量。

2、使用相同的的shader程序。

3、使用同一张纹理。

4、使用相同的混合模式。

 

在顺序上相邻的且满足上面四个条件的sprite就可以自动实现批绘制了。

  //Start drawing verties in batch    for(const auto& cmd : _batchedQuadCommands)    {        auto newMaterialID = cmd->getMaterialID();        if(_lastMaterialID != newMaterialID || newMaterialID == QuadCommand::MATERIAL_ID_DO_NOT_BATCH)        {            //Draw quads            if(quadsToDraw > 0)            {                glDrawElements(GL_TRIANGLES, (GLsizei) quadsToDraw*6, GL_UNSIGNED_SHORT, (GLvoid*) (startQuad*6*sizeof(_indices[0])) );                _drawnBatches++;                _drawnVertices += quadsToDraw*6;                startQuad += quadsToDraw;                quadsToDraw = 0;            }            //Use new material            cmd->useMaterial();            _lastMaterialID = newMaterialID;        }        quadsToDraw += cmd->getQuadCount();    }

 

实现原理:

Render在访问所以命令前会对他们进行排序,相同类型的命令就会排到一块,遍历命令时,再将相同的且满足自动批绘制条件的精灵加入到内存中,最后进行批绘制。


性能:

1、QuedCommand中使用建立VBO和VAO来提高绘制效率。关于VBO和VAO概念不懂的可以看这篇文章http://blog.csdn.net/bill_man/article/details/38314077。

2、使用glDrawElements进行一次性绘制,减少了函数调用。

  if (Configuration::getInstance()->supportsShareableVAO())    {        //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(quads_[0]) * (n-start), &quads_[start], GL_DYNAMIC_DRAW);        // option 3: orphaning + glMapBuffer        glBufferData(GL_ARRAY_BUFFER, sizeof(_quads[0]) * (_numQuads), nullptr, GL_DYNAMIC_DRAW);        void *buf = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);        memcpy(buf, _quads, sizeof(_quads[0])* (_numQuads));        glUnmapBuffer(GL_ARRAY_BUFFER);        glBindBuffer(GL_ARRAY_BUFFER, 0);        //Bind VAO        GL::bindVAO(_quadVAO);    }    else    {#define kQuadSize sizeof(_quads[0].bl)        glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]);        glBufferData(GL_ARRAY_BUFFER, sizeof(_quads[0]) * _numQuads , _quads, 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]);    }

 

绘制时机:
1、因为所有顶点数据使用一个VBO,当Quad数量超过了VBO所能容纳的最大Quad的数量10922(65536 / 6),将会立即执行前面的绘制。

  //Batch quads            if(_numQuads + cmd->getQuadCount() > VBO_SIZE)            {                CCASSERT(cmd->getQuadCount()>= 0 && cmd->getQuadCount() < VBO_SIZE, "VBO is not big enough for quad data, please break the quad data down or use customized render command");                                //Draw batched quads if VBO is full                drawBatchedQuads();            }            

 

2、如果还没超过,但是转到了其他类型的命令,那么也会立即执行前面的绘制。在Flush2D里会执行。

   else if(RenderCommand::Type::GROUP_COMMAND == commandType)        {            flush();            int renderQueueID = ((GroupCommand*) command)->getRenderQueueID();            visitRenderQueue(_renderGroups[renderQueueID]);        }        else if(RenderCommand::Type::CUSTOM_COMMAND == commandType)        {            flush();            auto cmd = static_cast<CustomCommand*>(command);            cmd->execute();        }        else if(RenderCommand::Type::BATCH_COMMAND == commandType)        {            flush();            auto cmd = static_cast<BatchCommand*>(command);            cmd->execute();        }        else if (RenderCommand::Type::MESH_COMMAND == commandType)        {            flush2D();            auto cmd = static_cast<MeshCommand*>(command);            if (_lastBatchedMeshCommand == nullptr || _lastBatchedMeshCommand->getMaterialID() != cmd->getMaterialID())            {                flush3D();                cmd->preBatchDraw();                cmd->batchDraw();                _lastBatchedMeshCommand = cmd;            }            else            {                cmd->batchDraw();            }        }


 

void Renderer::flush2D(){    drawBatchedQuads();    _lastMaterialID = 0;}

 

3、不满足自动批绘制条件的会直线先进行绘制。满足条件的则会加入到内存中,等到最后一次性绘制。

 if(_lastMaterialID != newMaterialID || newMaterialID == QuadCommand::MATERIAL_ID_DO_NOT_BATCH)        {            //Draw quads            if(quadsToDraw > 0)            {                glDrawElements(GL_TRIANGLES, (GLsizei) quadsToDraw*6, GL_UNSIGNED_SHORT, (GLvoid*) (startQuad*6*sizeof(_indices[0])) );                _drawnBatches++;                _drawnVertices += quadsToDraw*6;                startQuad += quadsToDraw;                quadsToDraw = 0;            }            //Use new material            cmd->useMaterial();            _lastMaterialID = newMaterialID;        }


 

   //Batch quads            if(_numQuads + cmd->getQuadCount() > VBO_SIZE)            {                CCASSERT(cmd->getQuadCount()>= 0 && cmd->getQuadCount() < VBO_SIZE, "VBO is not big enough for quad data, please break the quad data down or use customized render command");                                //Draw batched quads if VBO is full                drawBatchedQuads();            }                        _batchedQuadCommands.push_back(cmd);


 

相似比较:

另外还有一个批绘制命令BatchCommand,这个命令其实一般是配合着SpriteBatchNode使用的,被加入到SpriteBatchNode里的精灵就能进行批绘制。

BatchCommand是用来绘制一个TextrueAtlasde ,如label,TileMap。

所以他们的区别

1、QuadCommand是可以自动批绘制,BatchCommand要手动添加

2、BatchCommand里,我们不能为每个Sprite单独设置相关的opengl ES 绘制参数(????),如混合模式等。所以,SpriteNode适合那些比较简单的模型,如Label,TileMap。

 

使用

 _quadCommand.init(              _globalZOrder,              _textureAtlas->getTexture()->getName(),              getGLProgramState(),              _blendFunc,              _textureAtlas->getQuads(),              _quadsToDraw,              transform);    renderer->addCommand(&_quadCommand);


 

 

0 0