cocos渲染引擎分析(二)-----渲染命令之TrianglesCommand批次合并渲染

从上一章cocos启动流程中知道,cocos的渲染队列中,总共有TRIANGLES_COMMAND, GROUP _COMMAND等七种,其中GROUP_COMMAND是命令集合,QUAD_COMMAND是TRIANGLES_COMMAND的扩展类,真正的渲染命令只有5种:CUSTOM_COMMAND用于自定义绘制,BATCH_COMMAND批次渲染图集,MESH_COMMAND网格渲染,主要用于渲染3D模型(Sprite3D),PRIMITIVE_ COMMAND用于点线等的绘制,TRIANGLES_COMMAND三角形绘制,主要绘制按钮,图片等矩形控件(sprite)。这次主要记录TRIANGLES_COMMAND的绘制。

游戏渲染消耗大的一个重要原因就是drawCall次数太多,drawCall用OPENGL描述就是调用绘制函数(drawElement等)的次数。cocos对TrianglesCommand的命令进行了优化,对使用同一材质的绘制命令中的顶点和索引进行合并,同一材质的命令进行批次渲染,我们项目的3D批次渲染也是这种思想。以sprite的绘制为例,每次渲染遍历场景时调用调用sprite的draw函数(流程见cocos启动流程),生成TrianglesCommand渲染命令,加入到Renderer的渲染队列:

TrianglesCommand _trianglesCommand;  
void Sprite::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
        _trianglesCommand.init(_globalZOrder, 
            _texture, 
            getGLProgramState(), 
            _blendFunc, 
            _polyInfo.triangles, 
            transform, 
            flags);
        renderer->addCommand(&_trianglesCommand);
}

场景遍历完成后,Renderer访问渲染队列时,这里直接跳如处理流程(具体参见:cocos启动流程)如下:

void Renderer::processRenderCommand(RenderCommand* command)
{
    auto commandType = command->getType();
    if( RenderCommand::Type::TRIANGLES_COMMAND == commandType)
    {
        // flush other queues
        flush3D();
        auto cmd = static_cast<TrianglesCommand*>(command);
        // queue it 将TrianglesCommand加入到队列
        _queuedTriangleCommands.push_back(cmd);
        _filledIndex += cmd->getIndexCount();
        _filledVertex += cmd->getVertexCount();
    }
   。。。。。。。。
}

其他渲染命令,一般在此处绘制,TRIANGLES_COMMAND 渲染命令只是将所有渲染命令加入到统一队列,再访问过同一渲染类型(只是renderGroup一个渲染类型的集合,如透明和不透明)的所有渲染指令后,调用flush函数:

void Renderer::visitRenderQueue(RenderQueue& queue)
{
    。。。。。
    const auto& zZeroQueue = queue.getSubQueue(RenderQueue::QUEUE_GROUP::GLOBALZ_ZERO);
    if (zZeroQueue.size() > 0)
    {
        for (auto it = zZeroQueue.cbegin(); it != zZeroQueue.cend(); ++it)
        {
            processRenderCommand(*it);
        }
        flush();
     }
     。。。。。。。。
 }

flush函数会调用flush2D(),这里只看flush2D,最终调用drawBatchedTriangles:

void Renderer::drawBatchedTriangles()
{
    /*******1: Setup up vertices/indices 将所有的顶点和索引统一*************/
    for(auto it ; it != std::end(_queuedTriangleCommands); ++it)
    {
        fillVerticesAndIndices(cmd);//集合顶点和索引到同一数组
        // in the same batch ?是否在一个drawCall里渲染,根据材质ID和设置判断
        if (batchable && (prevMaterialID == currentMaterialID || firstCommand))
        {
            _triBatchesToDraw[batchesTotal].indicesToDraw += cmd->getIndexCount();
            _triBatchesToDraw[batchesTotal].cmd = cmd;
        }
        else
        {
            _triBatchesToDraw[batchesTotal].cmd = cmd;
            _triBatchesToDraw[batchesTotal].indicesToDraw = (int) cmd->getIndexCount();
            // is this a single batch ? Prevent creating a batch group then
        }
    }

    /***** 2: Copy vertices/indices to GL objects将数组索引映射到渲染缓存*************/
          glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]);
          glBufferData(。。。。);
          GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POS_COLOR_TEX);
    //
    /******3 根据合成的批次进行渲染 *************/
    for (int i=0; i<batchesTotal; ++i)
        glDrawElements(。。。。。) );

    /******4: Cleanup解除数组和索引到缓存的绑定 *************/
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    _queuedTriangleCommands.clear();

}

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值