cocos渲染引擎分析(三)-----渲染命令之MeshCommand

本文详细解析了Cocos3D引擎中Sprite3D的渲染过程,包括MeshCommand的生成及执行流程,揭示了3D物体的渲染机制,并指出了当前版本中批次渲染的局限性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

cocos的3D部分是在2D部分的基础上加上去,虽然经历很多版本迭代,然而3D部分,只是一个简单架子搭了起来,如果想要譬如高光,阴影,批次渲染等功能,都是需要自己添加的。这里简单讲下3D渲染命令MeshCommand,MeshCommand主要用于渲染Sprite3D 和3D粒子,这里以Sprite3D 的绘制流程为例,记录MeshCommand的渲染流程。

引擎渲染3D场景时,首先遍历场景节点信息,最终调用每个sprite3D节点的draw函数(流程见cocos启动流程),然后遍历调用3D物体的Mesh,生成MeshCommand渲染命令,加入到渲染器Renderer(游戏启动后,只有一个,由Director进行维护)的渲染队列:

void Sprite3D::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
    const auto& scene = Director::getInstance()->getRunningScene();
     if (usingLight != _shaderUsingLight)
     {
            genMaterial(usingLight);//如果材质不存在,生成新材质
     }
    for (auto mesh: _meshes)
    {
        //调用mesh的draw生成渲染命令
        mesh->draw(.......);
    }
}

Sprite3D与2D物体的差别在于,渲染更加多样,一个物体有多个部位,每个部位的渲染信息也各不相同(然而cocos是相同的,一个物体只有一个材质,后面项目已经改成多材质),因此需要一个物体分成多个MESH进行渲染,并且需要为每个mesh的材质传入自己uniform变量,Mesh的draw函数如下:

void Mesh::draw(Renderer* renderer.......)
{
   //生成渲染指令
    _meshCommand.init(........);
    //每个mesh有多个通道,为每个通道传入shader的uniform值(光照信息,朝向信息等)
    for(const auto pass : technique->_passes)
    {
        auto programState = pass->getGLProgramState();
        programState->setUniformVec4("u_color", color);
        if (scene && scene->getLights().size() > 0 && pass->ifAcceptLight())
            setLightUniforms(pass, scene, color, lightMask);
    }
    //添加到渲染队列
    renderer->addCommand(&_meshCommand);
}

遍历完成后,渲染器访问渲染队列,根据渲染类型(global<0,3D不透明,3D透明,2D,global>0)遍历执行渲染命令,处理MeshCommand的命令如下:

void Renderer::processRenderCommand(RenderCommand* command)
{
    auto commandType = command->getType();
   if (RenderCommand::Type::MESH_COMMAND == commandType)
    {
        auto cmd = static_cast<MeshCommand*>(command);
        if (.......)
        {
            flush3D();
            if(cmd->isSkipBatching())//用于判断是否批次,实际只是判断是否透明,透明物体以及粒子
                cmd->execute();
            else
            {
                cmd->preBatchDraw();
                cmd->batchDraw();
                _lastBatchedMeshCommand = cmd;
            }
        }
        else
            cmd->batchDraw();//不会执行,设计未完成,虽然写着批次渲染,然而并未实现
    }
}

MeshCommand虽然写了批次渲染的接口,只是挂羊头买狗肉,最终都是单个渲染,batchDraw和execute,两边并无区别,代码如下:

void MeshCommand::batchDraw()
{
    if (_material)
    {
        for(const auto& pass: _passes)
        {
            //设置渲染状态以及Uniform,顶点属性变量
            pass->bind(_mv);
            glDrawElements(_primitive, (GLsizei)_indexCount, _indexFormat, 0);
            pass->unbind();
        }
    }
    else
    {
        //设置渲染状态以及Uniform,顶点属性变量
        _glProgramState->applyGLProgram(_mv);
        // set render state
        applyRenderState();
        // Draw
        glDrawElements(_primitive, (GLsizei)_indexCount, _indexFormat, 0);
    }
}

如果要实现3D的批次渲染,需要使用CutomMeshCommand,自己进行批次渲染的合并,3D批次渲染代码太多就不贴了。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值