QuadCommand

功能:

这个命令主要用来绘制一个或多个矩形区域。相邻的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.youkuaiyun.com/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);


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值