减少drawcall是游戏开发过程中的重要优化手段,在移动设备上更低的drawcall意味着更低的发热和更高的系统流畅度。
cocos显示对象把渲染数据放在RenderCommand中,然后在Renderer类render函数中统一进行渲染。这么设计是为了对渲染进行统一的管理,包括可以进行合并drawcall,还可以用独立的线程来进行渲染,但是cocos目前并没有这么做。
cocos渲染数据的组织结构是,显示元素->RenderCommand->RenderQueue->_renderGroups。cocos默认使用RenderGrop[0]进行渲染,一些需要独立渲染的对象会开启新的RenderGroup,例如ClippingNode。
void Renderer::render()
{
_isRendering = true;
if (_glViewAssigned)
{
//对所有randerqueue进行排序
for (auto &renderqueue : _renderGroups)
{
renderqueue.sort();
}
//默认渲染RenderGrop[0]
visitRenderQueue(_renderGroups[0]);
}
//清空所有渲染数据
clean();
_isRendering = false;
}
RanderQueue的排序过程非常简单,只对GlobalZOrder不为0的和透明的3D对象才进行渲染排序。
void RenderQueue::sort()
{
// Don't sort _queue0, it already comes sorted
std::sort(std::begin(_commands[QUEUE_GROUP::TRANSPARENT_3D]), std::end(_commands[QUEUE_GROUP::TRANSPARENT_3D]), compare3DCommand);
std::sort(std::begin(_commands[QUEUE_GROUP::GLOBALZ_NEG]), std::end(_commands[QUEUE_GROUP::GLOBALZ_NEG]), compareRenderCommand);
std::sort(std::begin(_commands[QUEUE_GROUP::GLOBALZ_POS]), std::end(_commands[QUEUE_GROUP::GLOBALZ_POS]), compareRenderCommand);
}
visitRenderQueue函数按照指定的顺序对各种RenderQueue中的各个RenderCommand统一进行渲染,渲染单个RenderCommand的函数是processRenderCommand。
void Renderer::visitRenderQueue(RenderQueue& queue)
{
//保存渲染前的opengl状态
queue.saveRenderState();
//渲染GlobalZ小于0的RenderQueque
const auto& zNegQueue = queue.getSubQueue(RenderQueue::QUEUE_GROUP::GLOBALZ_NEG);
if (zNegQueue.size() > 0)
{
//设置opengl状态
......
for (auto it = zNegQueue.cbegin(); it != zNegQueue.cend(); ++it)
{
processRenderCommand(*it);
}
flush();
}
//渲染不透明的3D对象的RenderQueque
const auto& opaqueQueue = queue.getSubQueue(RenderQueue::QUEUE_GROUP::OPAQU