【cocos2d-x-3.1.1系列4】cocos2d-x3.1.1.渲染过程源码简略过程

缩略渲染过程

1、
DisplayLinkDirector ::mainLoop()

{

drawScene

}

 

 

2、



程序的主循环

-->DisplayLinkDirector ::drawScene()

{

     _runningScene->visit

     _renderer->render();

}
3、

drawScene里面的一句代码_runningScene->visit

 

-->visit(_renderer, Mat4::IDENTITY, false );

{

if(!_children.empty())

    {

        sortAllChildren();

        this->draw

    }

    else

    {

        this->draw    }

}
4、

递归visit

-->Sprite ::draw()

{

产生渲染命令

}
5、

产生渲染命令

 

-->void Renderer ::visitRenderQueue(const RenderQueue& queue)

{

if( RenderCommand::Type ::QUAD_COMMAND )

else if (RenderCommand ::Type ::GROUP_COMMAND )

 else if (RenderCommand ::Type ::CUSTOM_COMMAND)

else if (RenderCommand ::Type ::BATCH_COMMAND == commandType)

else if (RenderCommand ::Type ::MESH_COMMAND == commandType)

else

       

}




drawScene里面的一句代码_renderer->render();

排序渲染队列  执行opengl命令

void DisplayLinkDirector ::mainLoop()
{
    if (_purgeDirectorInNextLoop)
    {
        _purgeDirectorInNextLoop = false;
        purgeDirector();
    }
    else if (! _invalid)
    {
        drawScene();
    
        // release the objects
        PoolManager::getInstance()->getCurrentPool()->clear();
    }
}

上面是主循环函数  有个drawScene  跟踪进去
 // draw the scene
    if (_runningScene)
    {
        _runningScene->visit(_renderer, Mat4::IDENTITY, false );
        _eventDispatcher->dispatchEvent(_eventAfterVisit);//事件分发  在每一帧的绘制里面
    }
     _renderer->render();


上面的visit是产生渲染队列的,上面有个render跟踪进去

void Renderer ::render()
{
    //Uncomment this once everything is rendered by new renderer
    //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //TODO setup camera or MVP
    _isRendering = true;
   
    if (_glViewAssigned)
    {
        // cleanup
        _drawnBatches = _drawnVertices = 0;

        //Process render commands
        //1. Sort render commands based on ID
        for ( auto &renderqueue : _renderGroups)
        {
            renderqueue.sort();
        }
        visitRenderQueue(_renderGroups[0]);
        flush();
    }
    clean();
    _isRendering = false;
}

渲染队列排序  之后到函数
void Renderer ::visitRenderQueue(const RenderQueue& queue)
{
    ssize_t size = queue.size();
   
    for (ssize_t index = 0; index < size; ++index)
    {
        auto command = queue [index];
        auto commandType = command->getType();
        if( RenderCommand::Type ::QUAD_COMMAND == commandType)
        {
            auto cmd = static_cast <QuadCommand*>(command);
            //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);
           
            memcpy(_quads + _numQuads, cmd->getQuads(), sizeof(V3F_C4B_T2F_Quad ) * cmd->getQuadCount());
            convertToWorldCoordinates(_quads + _numQuads, cmd->getQuadCount(), cmd->getModelView());
           
            _numQuads += cmd->getQuadCount();

        }
        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)
        {
            flush();
            auto cmd = static_cast <MeshCommand*>(command);
            cmd->execute();
        }
        else
        {
            CCLOGERROR("Unknown commands in renderQueue" );
        }
    }
}
3.0之前是visit后就draw,而draw是真正的OpenGL操作。也就是说,每访问一个对象,先计算节点的渲染数据,然后马上渲染。
3.0也是在visit后就draw,但是draw并不进行OpenGL操作。3.0抽象了一个RenderCommand,在draw的时候其实是生成一个渲染命令,渲染命令其实就是对渲染所需要的数据的封装。RenderCommand作为基类,只包含了两个成员,一个是命令类型_type,这个很必要,正是靠这个来获取子类对象的具体类型的,这里没有用运行时类型,应该是考虑到效率;另一个是z深度_globalOrder,这个也很必要,渲染的时候必然要对节点排序,而z序是唯一的依据。
3.0包含了以下几个RenderCommand的子类:
1,CustomCommand:
顾名思义,是客户自定义的。
使用CustomCommand还有Layer,LableAtlas,LabelBMFont

2,QuadCommand:
和CustomCommand不同,这个类包含了很多属性:纹理_textureID,Program _shader,混合函数_blendType,定点数据_quad,模型视图矩阵_mv,还有一个材质属性_materialID。。
值得一提的是3.0主要是对QuadCommand进行了优化,实际上游戏中也大多数是这种情况。在Render::render()函数中,如果当前是QuadCommand,则顶点和Command放入数组,如果是其它,则先渲染此前的QuadCommand数组,然后再渲染当前命令。
使用CustomCommand命令的类有Sprite,ParticleSystemQuad,而Sprite应该是游戏中最常用的类,所以3.0的优化还是很有意义的。

3,BatchCommand
看名字就知道,BatchCommand是CCSpriteBatchNode的改进,而事实上,也的确是CCSpriteBatchNode和CCPaticleBatchNode使用了BatchCommand。BatchCommand的属性和QuadCommand很相似,不过没有了顶点数据_quad,变成了_textureAtlas,其渲染函数也和此前的差别不大,都是材质三剑客(shader, texutre, blend)

4,GroupCommand:
这是一个Command组合,但是GroupCommand只有一个属性_renderQueueID,而GroupCommand的所有子Command其实存放在Render中。GroupCommand像其它Command一样,存放在同一个队列中,遍历的时候,如果是GroupCommand,则获取其_renderQueueID,然后根据_renderQueueID找到指定的RenderCommand队列,进而渲染这个队列。可见,在Render中,可以包含多个Command队列,一些是根节点队列(没有父Command),其它的是指定ID的GroupCommand的子命令队列。
使用GroupCommand的主要有RenderTexture,因为RenderTexture包含了两次分隔的渲染操作,一次是begin(),一次是end()。


命令从哪里来的呢????
这个是刚刚的visit函数:
void Node ::visit( Rendererrendererconst Mat4 & parentTransformbool parentTransformUpdated )
{
    // quick return if not visible. children won't be drawn.
    if (!_visible)
    {
        return ;
    }

    bool dirty = _transformUpdated || parentTransformUpdated ;
    if(dirty)
        _modelViewTransform = this ->transform(parentTransform );
    _transformUpdated = false ;


    // IMPORTANT:
    // To ease the migration to v3.0, we still support the Mat4 stack,
    // but it is deprecated and your code should not rely on it
    Director* director = Director ::getInstance();
    CCASSERT( nullptr != director, "Director is null when seting matrix stack");
    director->pushMatrix( MATRIX_STACK_TYPE ::MATRIX_STACK_MODELVIEW );
    director->loadMatrix( MATRIX_STACK_TYPE ::MATRIX_STACK_MODELVIEW , _modelViewTransform);

    int i = 0;

    if(!_children.empty())
    {
        sortAllChildren();
        // draw children zOrder < 0
        for( ; i < _children.size(); i++ )
        {
            auto node = _children.at(i);

            if ( node && node->_localZOrder < 0 )
                node->visit( renderer , _modelViewTransform, dirty);
            else
                break ;
        }
        // self draw
        this ->draw(renderer , _modelViewTransform, dirty);

        for( auto it=_children.cbegin()+i; it != _children.cend(); ++it)
            (*it)->visit( renderer , _modelViewTransform, dirty);
    }
    else
    {
        this ->draw(renderer , _modelViewTransform, dirty);
    }

    // reset for next frame
    _orderOfArrival = 0;
 
    director->popMatrix( MATRIX_STACK_TYPE ::MATRIX_STACK_MODELVIEW );
}


看到源码如果没有儿子了 那么调用draw  Node:draw是空的  因为node不画  画的是sprite这些
上面代码的这一句this ->draw(renderer , _modelViewTransform, dirty);


void Sprite ::draw( Renderer * rendererconst Mat4 & transformbool transformUpdated )
{
    // Don't do calculate the culling if the transform was not updated
    _insideBounds = transformUpdated ? renderer ->checkVisibility(transform , _contentSize) : _insideBounds;

    if(_insideBounds)
    {
        _quadCommand.init(_globalZOrder, _texture->getName(), getGLProgramState(), _blendFunc, &_quad, 1, transform );
        renderer ->addCommand(&_quadCommand);
#if CC_SPRITE_DEBUG_DRAW
        _customDebugDrawCommand.init(_globalZOrder);
        _customDebugDrawCommand.func = CC_CALLBACK_0(Sprite::drawDebugData, this );
        renderer->addCommand(&_customDebugDrawCommand);
#endif //CC_SPRITE_DEBUG_DRAW
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值