【cocos2d-x-3.1.1系列4】cocos2d-x3.1.1.渲染过程源码简略过程

缩略渲染过程

1、
DisplayLinkDirector ::mainLoop()

{

drawScene

}


2、



程序的主循环

-->DisplayLinkDirector::drawScene()

{

_runningScene->visit

_renderer->render();

}
3、

drawScene里面的一句代码_runningScene->visit

-->visit(_renderer,Mat4::IDENTITY,false);

{

if(!_children.empty())

{

sortAllChildren();

this->draw

}

else

{

this->draw}

}
4、

递归visit

Sprite::draw()

{

产生渲染命令

}
5、

产生渲染命令

-->voidRenderer::visitRenderQueue(constRenderQueue&queue)

{

if(RenderCommand::Type::QUAD_COMMAND)

elseif(RenderCommand::Type::GROUP_COMMAND)

elseif(RenderCommand::Type::CUSTOM_COMMAND)

elseif(RenderCommand::Type::BATCH_COMMAND==commandType)

elseif(RenderCommand::Type::MESH_COMMAND==commandType)

else

}




drawScene里面的一句代码_renderer->render();

排序渲染队列执行opengl命令

void DisplayLinkDirector ::mainLoop()
{
if (_purgeDirectorInNextLoop)
{
_purgeDirectorInNextLoop = false ;
purgeDirector();
}
else if (! _invalid)
{
drawScene();
// release the objects
PoolManager ::getInstance()->getCurrentPool()->clear();
}
}

上面是主循环函数 有个drawScene 跟踪进去
// draw the scene
if (_runningScene)
{
_runningScene->visit(_renderer, Mat4 ::IDENTITY, false );
_eventDispatcher->dispatchEvent(_eventAfterVisit);//事件分发 在每一帧的绘制里面
}
_renderer->render();


上面的visit是产生渲染队列的,上面有个render跟踪进去

void Renderer ::render()
{
//Uncomment this once everything is rendered by new renderer
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//TODO setup camera or MVP
_isRendering = true ;
if (_glViewAssigned)
{
// cleanup
_drawnBatches = _drawnVertices = 0;

//Process render commands
//1. Sort render commands based on ID
for ( auto &renderqueue : _renderGroups)
{
renderqueue.sort();
}
visitRenderQueue(_renderGroups[0]);
flush();
}
clean();
_isRendering = false ;
}

渲染队列排序 之后到函数
void Renderer ::visitRenderQueue( const RenderQueue & queue )
{
ssize_t size = queue .size();
for ( ssize_t index = 0; index < size; ++index)
{
auto command = queue [index];
auto commandType = command->getType();
if ( RenderCommand :: Type :: QUAD_COMMAND == commandType)
{
auto cmd = static_cast < QuadCommand *>(command);
//Batch quads
if (_numQuads + cmd->getQuadCount() > VBO_SIZE)
{
CCASSERT (cmd->getQuadCount()>= 0 && cmd->getQuadCount() < VBO_SIZE, "VBO is not big enough for quad data,please break the quad data down or use customized render command" );
//Draw batched quads if VBO is full
drawBatchedQuads();
}
_batchedQuadCommands.push_back(cmd);
memcpy(_quads + _numQuads,cmd->getQuads(), sizeof ( V3F_C4B_T2F_Quad ) * cmd->getQuadCount());
convertToWorldCoordinates(_quads + _numQuads,cmd->getQuadCount(),cmd->getModelView());
_numQuads += cmd->getQuadCount();

}
else if ( RenderCommand :: Type :: GROUP_COMMAND == commandType)
{
flush();
int renderQueueID = (( GroupCommand *) command)->getRenderQueueID();
visitRenderQueue(_renderGroups[renderQueueID]);
}
else if ( RenderCommand :: Type :: CUSTOM_COMMAND == commandType)
{
flush();
auto cmd = static_cast < CustomCommand *>(command);
cmd->execute();
}
else if ( RenderCommand :: Type :: BATCH_COMMAND == commandType)
{
flush();
auto cmd = static_cast < BatchCommand *>(command);
cmd->execute();
}
else if ( RenderCommand :: Type :: MESH_COMMAND == commandType)
{
flush();
auto cmd = static_cast < MeshCommand *>(command);
cmd->execute();
}
else
{
CCLOGERROR ( "Unknown commands in renderQueue" );
}
}
}
3.0之前是visit后就draw,而draw是真正的OpenGL操作。也就是说,每访问一个对象,先计算节点的渲染数据,然后马上渲染。
3.0也是在visit后就draw,但是draw并不进行OpenGL操作。3.0抽象了一个RenderCommand,在draw的时候其实是生成一个渲染命令,渲染命令其实就是对渲染所需要的数据的封装。RenderCommand作为基类,只包含了两个成员,一个是命令类型_type,这个很必要,正是靠这个来获取子类对象的具体类型的,这里没有用运行时类型,应该是考虑到效率;另一个是z深度_globalOrder,这个也很必要,渲染的时候必然要对节点排序,而z序是唯一的依据。
3.0包含了以下几个RenderCommand的子类:
1,CustomCommand:
顾名思义,是客户自定义的。
使用CustomCommand还有Layer,LableAtlas,LabelBMFont

2,QuadCommand:
和CustomCommand不同,这个类包含了很多属性:纹理_textureID,Program _shader,混合函数_blendType,定点数据_quad,模型视图矩阵_mv,还有一个材质属性_materialID。。
值得一提的是3.0主要是对QuadCommand进行了优化,实际上游戏中也大多数是这种情况。在Render::render()函数中,如果当前是QuadCommand,则顶点和Command放入数组,如果是其它,则先渲染此前的QuadCommand数组,然后再渲染当前命令。
使用CustomCommand命令的类有Sprite,ParticleSystemQuad,而Sprite应该是游戏中最常用的类,所以3.0的优化还是很有意义的。

3,BatchCommand
看名字就知道,BatchCommand是CCSpriteBatchNode的改进,而事实上,也的确是CCSpriteBatchNode和CCPaticleBatchNode使用了BatchCommand。BatchCommand的属性和QuadCommand很相似,不过没有了顶点数据_quad,变成了_textureAtlas,其渲染函数也和此前的差别不大,都是材质三剑客(shader,texutre,blend)

4,GroupCommand:
这是一个Command组合,但是GroupCommand只有一个属性_renderQueueID,而GroupCommand的所有子Command其实存放在Render中。GroupCommand像其它Command一样,存放在同一个队列中,遍历的时候,如果是GroupCommand,则获取其_renderQueueID,然后根据_renderQueueID找到指定的RenderCommand队列,进而渲染这个队列。可见,在Render中,可以包含多个Command队列,一些是根节点队列(没有父Command),其它的是指定ID的GroupCommand的子命令队列。
使用GroupCommand的主要有RenderTexture,因为RenderTexture包含了两次分隔的渲染操作,一次是begin(),一次是end()。


命令从哪里来的呢????
这个是刚刚的visit函数:
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 ,dirty);

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

// reset for next frame
_orderOfArrival = 0;
director->popMatrix( MATRIX_STACK_TYPE :: MATRIX_STACK_MODELVIEW );
}


看到源码如果没有儿子了 那么调用draw Node:draw是空的 因为node不画 画的是sprite这些
上面代码的这一句 this ->draw( renderer ,dirty);


void Sprite ::draw( Renderer * renderer , const Mat4 & transform , bool transformUpdated )
{
// Don't do calculate the culling if the transform was not updated
_insideBounds = transformUpdated ? renderer ->checkVisibility( transform ,_contentSize) : _insideBounds;

if (_insideBounds)
{
_quadCommand.init(_globalZOrder,_texture->getName(),getGLProgramState(),_blendFunc,&_quad,1, transform );
renderer ->addCommand(&_quadCommand);
#if CC_SPRITE_DEBUG_DRAW
_customDebugDrawCommand.init(_globalZOrder);
_customDebugDrawCommand.func = CC_CALLBACK_0(Sprite::drawDebugData, this );
renderer->addCommand(&_customDebugDrawCommand);
#endif //CC_SPRITE_DEBUG_DRAW
}
}

相关文章

    本文实践自 RayWenderlich、Ali Hafizji 的文章《...
Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@1...
第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从C...
    Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发...
1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《...
   Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试...