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、
|
产生渲染命令
|
-->void Renderer ::visitRenderQueue(const RenderQueue& queue) { if( RenderCommand::Type ::QUAD_COMMAND ) else if (RenderCommand ::Type ::GROUP_COMMAND ) else if (RenderCommand ::Type ::CUSTOM_COMMAND) else if (RenderCommand ::Type ::BATCH_COMMAND == commandType) else if (RenderCommand ::Type ::MESH_COMMAND == commandType) else
}
|
在drawScene里面的一句代码_renderer->render(); 排序渲染队列 执行opengl命令 |
【cocos2d-x-3.1.1系列4】cocos2d-x3.1.1.渲染过程源码简略过程
最新推荐文章于 2020-04-07 15:33:57 发布
缩略渲染过程
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 ,
_modelViewTransform, dirty);
for( auto it=_children.cbegin()+i;
it != _children.cend(); ++it)
(*it)->visit( renderer ,
_modelViewTransform, dirty);
}
else
{
this ->draw(renderer ,
_modelViewTransform, dirty);
}
// reset for next frame
_orderOfArrival = 0;
director->popMatrix( MATRIX_STACK_TYPE ::MATRIX_STACK_MODELVIEW );
}
看到源码如果没有儿子了 那么调用draw Node:draw是空的 因为node不画 画的是sprite这些
上面代码的这一句this ->draw(renderer ,
_modelViewTransform, 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
}
}