cocos2d-x版本:3.17.2
运行环境:Visual Studio 2017
解决方案配置:Debug Win32
渲染流程图
Renderer对象在Director(导演类)中,Director一般是单例,因此可以认为Renderer也是全局唯一。Renderer里面存放着渲染命令队列,它的类的简化结构如下:
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;
};
之前说到在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;
}