Cocos2d-x引擎学习笔记(二)—— 渲染与绘制源码分析

Cocos2d-x引擎渲染与绘制源码分析


cocos2d-x版本:3.17.2

运行环境:Visual Studio 2017

解决方案配置:Debug Win32


渲染流程图

Cocos2d-x引擎学习笔记(二)—— 渲染与绘制源码分析_第1张图片

1. Renderer中的渲染队列RenderQueue类

Renderer对象在Director(导演类)中,Director一般是单例,因此可以认为Renderer也是全局唯一。Renderer里面存放着渲染命令队列,它的类的简化结构如下:

Cocos2d-x引擎学习笔记(二)—— 渲染与绘制源码分析_第2张图片
RenderQueue类

class RenderQueue {
public:
    /**
    RenderCommand will be divided into Queue Groups.
    */
    enum QUEUE_GROUP
    {
        // globalZ值小于0的物体
        GLOBALZ_NEG = 0,
        // 不透明的3D物体,globalZ都是0
        OPAQUE_3D = 1,
        // 透明的3D物体,globalZ都是0
        TRANSPARENT_3D = 2,
        // globalZ为0的2D物体
        GLOBALZ_ZERO = 3,
        // globalZ大于0的物体
        GLOBALZ_POS = 4,
        QUEUE_COUNT = 5,
    };

public:
    /**Constructor.*/
    RenderQueue();
    /**Push a renderCommand into current renderqueue.*/
    void push_back(RenderCommand* command);
    /**Return the number of render commands.*/
    ssize_t size() const;
    /**Sort the render commands.*/
    void sort();
    /**Treat sorted commands as an array, access them one by one.*/
    RenderCommand* operator[](ssize_t index) const;
    /**Clear all rendered commands.*/
    void clear();
    /**Realloc command queues and reserve with given size. Note: this clears any existing commands.*/
    void realloc(size_t reserveSize);
    /**Get a sub group of the render queue.*/
    std::vector<RenderCommand*>& getSubQueue(QUEUE_GROUP group) { return _commands[group]; }
    /**Get the number of render commands contained in a subqueue.*/
    ssize_t getSubQueueSize(QUEUE_GROUP group) const { return _commands[group].size(); }

    /**Save the current DepthState, CullState, DepthWriteState render state.*/
    void saveRenderState();
    /**Restore the saved DepthState, CullState, DepthWriteState render state.*/
    void restoreRenderState();
    
protected:
    /**The commands in the render queue.*/
    std::vector<RenderCommand*> _commands[QUEUE_COUNT];
    
    /**Cull state.*/
    bool _isCullEnabled;
    /**Depth test enable state.*/
    bool _isDepthEnabled;
    /**Depth buffer write state.*/
    GLboolean _isDepthWrite;
};

2. Renderer::render()分析

之前说到在Director类的mainLoop中,cocos通过Renderer::render()来进行渲染,现在我们来看一下这个函数究竟做了些什么。

void Renderer::render()
{
    //TODO: setup camera or MVP
    _isRendering = true;
    	
    if (_glViewAssigned)
    {
        //Process render commands
        // 对renderqueue中的命令进行排序
        for (auto &renderqueue : _renderGroups)
        {
            renderqueue.sort();
        }
        // 执行渲染
        visitRenderQueue(_renderGroups[0]);
    }
    // 渲染完成后,清空_renderGroups中的所有command
    clean();
    _isRendering = false;
}

其中renderqueue.sort()的函数如下:

void RenderQueue::sort()
{
    // Don't sort _queue0, it already comes sorted
    std::stable_sort(std::begin(_commands[QUEUE_GROUP::TRANSPARENT_3D]), std::end(_commands[QUEUE_GROUP::TRANSPARENT_3D]), compare3DCommand);
    std::stable_sort(std::begin(_commands[QUEUE_GROUP::GLOBALZ_NEG]), std::end(_commands[QUEUE_GROUP::GLOBALZ_NEG]), compareRenderCommand);
    std::stable_sort(std::begin(_commands[QUEUE_GROUP::GLOBALZ_POS]), std::end(_commands[QUEUE_GROUP::GLOBALZ_POS]), compareRenderCommand);
}

我们可以看到,RenderQueue::sort()中只对TRANSPARENT_3D,GLOBALZ_NEG和GLOBALZ_POS三种类型的队列进行了排序,并且使用不同的比较函数,3D使用的是深度比较,而NEG与POS使用的是globalOrder的比较

compare3DCommand函数是比较两个command的_depth值,如下:

static bool compare3DCommand(RenderCommand* a, RenderCommand* b)
{
    return  a->getDepth() > b->getDepth();
}

compareRenderCommand函数比较的是两个command的_globalOrder值。如下:

static bool compareRenderCommand(RenderCommand* a, RenderCommand* b)
{
    return a->getGlobalOrder() < b->getGlobalOrder();
}

排序完成后,执行visitRenderQueue()函数

void Renderer::visitRenderQueue(RenderQueue& queue)
{
    // 保存Render的状态
    queue.saveRenderState();
    
    //
    //处理Global-Z < 0物体的渲染
    //
    const auto& zNegQueue = queue.getSubQueue(RenderQueue::QUEUE_GROUP::GLOBALZ_NEG);
    if (zNegQueue.size() > 0)
    {
        if(_isDepthTestFor2D)
        {
            glEnable(GL_DEPTH_TEST);
            glDepthMask(true);
            glEnable(GL_BLEND);
            RenderState::StateBlock::_defaultState->setDepthTest(true);
            RenderState::StateBlock::_defaultState->setDepthWrite(true);
            RenderState::StateBlock::_defaultState->setBlend(true);
        }
        else
        {
            glDisable(GL_DEPTH_TEST);
            glDepthMask(false);
            glEnable(GL_BLEND);
            RenderState::StateBlock::_defaultState->setDepthTest(false);
            RenderState::StateBlock::_defaultState->setDepthWrite(false);
            RenderState::StateBlock::_defaultState->setBlend(true);
        }
        glDisable(GL_CULL_FACE);
        RenderState::StateBlock::_defaultState->setCullFace(false);
        
        // 根据不同的命令类型进行相应的渲染
        for (const auto& zNegNext : zNegQueue)
        {
            processRenderCommand(zNegNext);
        }
        flush();
    }
    
    //
    //Process Opaque Object
    //
    ···
    
    //
    //Process 3D Transparent object
    //
    ···
    //
    //Process Global-Z = 0 Queue
    //
    ···
    //
    //Process Global-Z > 0 Queue
    //
    ···
    // 恢复opengl状态
    queue.restoreRenderState();
}

在visitRenderQueue函数中,因为在处理队列的过程中,可能会改变OpenGL当前的状态,因此,首先调用了queue.saveRenderState(); 它是为了保存当前的OpenGL状态,在完成队列的渲染后,再调用queue.restoreRenderState();来恢复OpenGL状态。

在查找完Render的队列元素后,将这些元素的不同的渲染命令放入processRenderCommand()来进行渲染。

void Renderer::processRenderCommand(RenderCommand* command)
{
    auto commandType = command->getType();
    if( RenderCommand::Type::TRIANGLES_COMMAND == commandType)
    {
        ···
    }
    else if (RenderCommand::Type::MESH_COMMAND == commandType)
    {
        ···
    }
    else if(RenderCommand::Type::GROUP_COMMAND == commandType)
    {
        ···
    }
    else if(RenderCommand::Type::CUSTOM_COMMAND == commandType)
    {
        ···
    }
    else if(RenderCommand::Type::BATCH_COMMAND == commandType)
    {
        ···
    }
    else if(RenderCommand::Type::PRIMITIVE_COMMAND == commandType)
    {
        flush();
        auto cmd = static_cast<PrimitiveCommand*>(command);
        CCGL_DEBUG_INSERT_EVENT_MARKER("RENDERER_PRIMITIVE_COMMAND");
        cmd->execute();
    }
    else
    {
        CCLOGERROR("Unknown commands in renderQueue");
    }
}

根据不同的指令再执行不同类的execute()进行渲染。

渲染完成后执行clean()函数

void Renderer::clean()
{
    // Clear render group
    for (size_t j = 0, size = _renderGroups.size() ; j < size; j++)
    {
        _renderGroups[j].clear();
    }

    // Clear batch commands
    _queuedTriangleCommands.clear();
    _filledVertex = 0;
    _filledIndex = 0;
    _lastBatchedMeshCommand = nullptr;
}

你可能感兴趣的:(Cocos2d引擎)