cocos3.1源码分析(2)渲染流程分析

上一篇分析启动流程的时候,看到了最后是进入了一个循环,在里面有一个函数是drawScene,实现如下

// Draw the Scene
void Director::drawScene()
{
    // calculate "global" dt

 //计算两帧的时间间隔,在这里补充一点,在游戏开发中,很重要的一点就是游戏的帧,一般来说游戏的帧数要达到30帧以上才算上比较流畅,60帧的话就很好了,游戏的帧是不稳定的,你可能在一帧做了比较多的事情,导致时间较长,也可能这一帧很快就结束了。
    calculateDeltaTime();
    
    // skip one flame when _deltaTime equal to zero.

//#define FLT_EPSILON     1.192092896e-07F

//显然就是说当一帧的时间间隔小于FLT_EPSILON这个值的时候,直接就返回了,
    if(_deltaTime < FLT_EPSILON)
    {
        return;
    }


    if (_openGLView)
    {

//没有看到实现的函数,暂时不清楚
        _openGLView->pollInputEvents();
    }


    //tick before glClear: issue #533
    if (! _paused)
    {

//显然这就是当我们在继承Layer的类中如果调用了this->scheduleUpdate(),然后每帧都会调用update(float dt)的原理了,关于调度器,以后在分析
        _scheduler->update(_deltaTime);

//接下来就是cocos的事件分发器了,也以后在做分析
        _eventDispatcher->dispatchEvent(_eventAfterUpdate);
    }
//opengl的函数,清楚当前颜色缓冲区和深度缓冲区的值,为渲染做准备
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    /* to avoid flickr, nextScene MUST be here: after tick and before draw.
     XXX: Which bug is this one. It seems that it can't be reproduced with v0.9 */
    if (_nextScene)
    {

//切换场景的时候会调用的,因为切换场景的时候_nextScene的值肯定是不为空的,关于这个以后在分析,在setNextScene里面我们也可以知道切换场景的时候的执行顺序为什么是这样 (onEnter() ------》onEnterTransitionDidFinish();)实现在下面
        setNextScene();
    }

//OPENGL的操作
    pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
//如果现在是用场景在运行着的。就会进入visit的函数,今天主要分析的就是这里,真够绕的,_runningScene是Scene类型,然后Scene继承Node,而Scene里面没有实现visit,所以会调用Node的visit,
在下面有这个函数的实现

    // draw the scene
    if (_runningScene)
    {
        _runningScene->visit(_renderer, Mat4::IDENTITY, false);

//分发事件
        _eventDispatcher->dispatchEvent(_eventAfterVisit);
    }

    // draw the notifications node
    if (_notificationNode)
    {

//通知事件的分发
        _notificationNode->visit(_renderer, Mat4::IDENTITY, false);
    }

    if (_displayStats)
    {
        showStats();
    }
//游戏的渲染
    _renderer->render();
    _eventDispatcher->dispatchEvent(_eventAfterDraw);


    popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
//执行到这里,一次循环就结束了,所以总帧数加一
    _totalFrames++;
//OPENGL的交换缓冲区
    // swap buffers
    if (_openGLView)
    {
        _openGLView->swapBuffers();
    }


    if (_displayStats)
    {

//这也是时间的计数,就是模拟器上显示的时间
        calculateMPF();
    }
}


void Director::setNextScene()
{
    bool runningIsTransition = dynamic_cast<TransitionScene*>(_runningScene) != nullptr;
    bool newIsTransition = dynamic_cast<TransitionScene*>(_nextScene) != nullptr;


    // If it is not a transition, call onExit/cleanup
     if (! newIsTransition)
     {
         if (_runningScene)
         {
             _runningScene->onExitTransitionDidStart();
             _runningScene->onExit();
         }
 
         // issue #709. the root node (scene) should receive the cleanup message too
         // otherwise it might be leaked.
         if (_sendCleanupToScene && _runningScene)
         {
             _runningScene->cleanup();
         }
     }


    if (_runningScene)
    {
        _runningScene->release();
    }
    _runningScene = _nextScene;
    _nextScene->retain();
    _nextScene = nullptr;


    if ((! runningIsTransition) && _runningScene)
    {
        _runningScene->onEnter();
        _runningScene->onEnterTransitionDidFinish();
    }
}

//CCNode.cpp

.....................

void Node::visit(Renderer* renderer, const Mat4 &parentTransform, bool 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);
}

红色的部分是这次分析的重点,这部分显然就说明了,首先会对Node的节点进行排序(从小到大的排序),然后会调用每个孩子节点的Draw函数,把每个孩子节点渲染出来,所以像精灵等Node的孩子节点都会有一个draw函数,然后把孩子节点渲染出来。这就是抽象的好处了,在父类中实现一个vector容器,把所有的节点放入里面,然后在遍历容器,取出孩子,在对具体的孩子进行渲染。这也就说明了为什么我们一定要进行addChild以后,才能把我们需要的东西在屏幕上显示出来。

今天的分析就这样了,下一篇将对Render类和Sprite类进行分析。个人理解可能有出入,欢迎各位大神指出不当之处。。。微笑



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值