zhishu520 / blog

一个关于游戏开发的博客(*^__^*)
3 stars 0 forks source link

cocos2dx 是如何渲染的 #1

Open zhishu520 opened 5 years ago

zhishu520 commented 5 years ago

cocos2dx 是如何渲染的

先给个,大致的图,然后会详细讲解每个函数。


image

Application::run 底层循环

这个函数是平台相关的,不同平台下有不同的实现,它们所能保证的就是不停的调用Director::mainLoop

Director::mainLoop 主循环

mainloop函数做了三件事

  1. 自身数据创建和销毁
  2. 渲染场景
  3. 自动缓存池对象释放
void Director::mainLoop()
{

    // 游戏结束 销毁对象 Director::getInstance()->end(); 
    if (_purgeDirectorInNextLoop)
    {
        _purgeDirectorInNextLoop = false;
        purgeDirector();
    }
    // 重启整个游戏流程  Director::getInstance()->restart();
    else if (_restartDirectorInNextLoop)
    {
        _restartDirectorInNextLoop = false;
        restartDirector();
    }
    else if (! _invalid)
    {
        // 渲染场景
        drawScene();

        // 释放加到缓存池里的对象
        PoolManager::getInstance()->getCurrentPool()->clear();
    }
}

渲染函数 Director::drawScene

void Director::drawScene()
{
    if (_openGLView)
    {
        // glfwPollEvents() 轮询事件
        _openGLView->pollEvents();
    }

    // 清理上一帧渲染数据
    _renderer->clear();
    experimental::FrameBuffer::clearAllFBOs();

    //该节点的转换矩阵入栈
    pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);

    if (_runningScene)
    {
        //clear draw stats
        _renderer->clearDrawStats();

        // 添加渲染命令到 Renderer的 RenderQuene中去
        if(_openGLView)
            _openGLView->renderScene(_runningScene, _renderer);
    }

    // Renderer 绘制加入的所有 render command
    _renderer->render();

    // 该节点的转换矩阵出栈
    popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);

    // 交换缓冲区
    if (_openGLView)
    {
        _openGLView->swapBuffers();
    }
}

Node::visit 遍历节点

排序子节点,遍历子节点,调用Draw方法

void Node::visit(Renderer* renderer, const Mat4 &parentTransform, uint32_t parentFlags)
{

    if (!_visible)
    {
        return;
    }

    uint32_t flags = processParentFlags(parentTransform, parentFlags);

    _director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    _director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewTransform);

    bool visibleByCamera = isVisitableByVisitingCamera();

    int i = 0;

    if(!_children.empty())
    {
        sortAllChildren();
        // 遍历子节点
        for(auto size = _children.size(); i < size; ++i)
        {
            auto node = _children.at(i);

            if (node && node->_localZOrder < 0)
                node->visit(renderer, _modelViewTransform, flags);
            else
                break;
        }
        // 调用draw方法
        if (visibleByCamera)
            this->draw(renderer, _modelViewTransform, flags);

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

    _director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
}

Sprite::draw 绘画

Spritedraw 函数并不是直接就调用opengl函数开始绘制, 而是创建 RenderCommand 并加入 RenderQuene 然后集中处理, 之所以这样是因为希望用一个独立的线程来处理和GPU的交互。

void Sprite::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags)
{
    if (_texture == nullptr)
    {
        return;
    }

    {
        _trianglesCommand.init(_globalZOrder, 
                               _texture,
                               getGLProgramState(),
                               _blendFunc,
                               _polyInfo.triangles,
                               transform,
                               flags);

        renderer->addCommand(&_trianglesCommand);
    }
}