cocos2dx 3.x中的OpenGL(一)-Cocos2d-x渲染结构
2015-03-16 09:59
295 查看
从本篇文章开始,将分析Cocos2d-x 3.0源代码,第一部分是从Cocos2d-x学习OpenGL,也就是分析Cocos2d-x 3.0的渲染代码,本篇首先介绍Cocos2d-x 3.0的渲染结构,使用的是3.0正式版。
分析的起点是mainLoop函数,这是在主线程里面会调用的循环,其中drawScene函数进行绘制。那么就进一步来看drawScene函数。
其中和绘制相关的是visit的调用和render的调用,其中visit函数会调用节点的draw函数,在3.0之前的版本中draw函数就会直接调用绘制代码,3.0版本是在draw函数中将绘制命令存入到renderer中,然后renderer函数去进行真正的绘制,首先来看sprite的draw函数。
这里面用了两种不同的绘制命令quadCommand初始化后就可以加入到绘制命令中,customDebugDrawCommand传入了一个回调函数,具体的命令种类会在后面介绍。其中自定义的customDebugDrawCommand命令在初始化的时候只传入了全局z轴坐标,因为它的绘制函数全部都在传入的回调函数里面,_quadCommand则需要传入全局z轴坐标,贴图名称,shader,混合,坐标点集合,坐标点集个数,变换。
Render类中的render函数进行真正的绘制,首先排序,再进行绘制,从列表中的第一个组开始绘制。在visitRenderQueue函数中可以看到五种不同类型的绘制命令类型,分别对应五个类,这五个类都继承自RenderCommand。
QUAD_COMMAND:QuadCommand类绘制精灵等。所有绘制图片的命令都会调用到这里,处理这个类型命令的代码就是绘制贴图的openGL代码,下一篇文章会详细介绍这部分代码。
CUSTOM_COMMAND:CustomCommand类自定义绘制,自己定义绘制函数,在调用绘制时只需调用已经传进来的回调函数就可以,裁剪节点,绘制图形节点都采用这个绘制,把绘制函数定义在自己的类里。
这种类型的绘制命令不会在处理命令的时候调用任何一句openGL代码,而是调用你写好并设置给func的绘制函数,后续文章会介绍引擎中的所有自定义绘制,并自己实现一个自定义的绘制。
BATCH_COMMAND:BatchCommand类批处理绘制,批处理精灵和粒子
其实它类似于自定义绘制,也不会再render函数中出现任何一句openGL函数,它调用一个固定的函数,这个函数会在下一篇文章中介绍。
GROUP_COMMAND:GroupCommand类绘制组,一个节点包括两个以上绘制命令的时候,把这个绘制命令存储到另外一个_renderGroups中的元素中,并把这个元素的指针作为一个节点存储到_renderGroups[0]中。
整个GROUP_COMMAND的原理需要从addCommand讲起。
addCommand有“真假”两个,几乎所有添加渲染命令的地方,调用的都是第一个“假” 。
addCommand,它实际上不是真正的把命令添加到_renderGroups中,它是获得需要把命令加入到_renderGroups位置中的索引,这个索引是从_commandGroupStack获得的,_commandGroupStack是个栈,当我们创建一个GROUP_COMMAND时,需要调用pushGroup函数,它是把当前这个命令在_renderGroups的索引位置压到栈顶,当addCommand时,调用top,获得这个位置:
GROUP_COMMAND一般用于绘制的节点有一个以上的绘制命令,把这些命令组织在一起,无需排定它们之间的顺序,他们作为一个整体被调用,所以一定要记住,栈是push,pop对应的,关于这个节点的所有的绘制命令被添加完成后,请调用pop,将这个值从栈顶弹出,否则后面的命令也会被添加到这里。
接下来就可以解释为什么调用的起始只需调用visitRenderQueue(_renderGroups[0]);,为什么只是0,其他的呢?
它们会在处理GROUP_COMMAND被调用:
如有错误,欢迎指出
下一篇介绍贴图和批处理的openGL代码部分
来源网址:/article/1378813.html
voidDisplayLinkDirector::mainLoop() { if(_purgeDirectorInNextLoop) { //只有一种情况会调用到这里来,就是导演类调用end函数 _purgeDirectorInNextLoop = false; //清除导演类 purgeDirector(); } elseif (! _invalid) { //绘制 drawScene(); //清除内存 PoolManager::getInstance()->getCurrentPool()->clear(); } }
分析的起点是mainLoop函数,这是在主线程里面会调用的循环,其中drawScene函数进行绘制。那么就进一步来看drawScene函数。
voidDirector::drawScene() { //计算间隔时间 calculateDeltaTime(); //如果间隔时间过小会被忽略 if(_deltaTime < FLT_EPSILON) { return; } //空函数,也许之后会有作用 if(_openGLView) { _openGLView->pollInputEvents(); } //非暂停状态 if(! _paused) { _scheduler->update(_deltaTime); _eventDispatcher->dispatchEvent(_eventAfterUpdate); } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //切换下一场景,必须放在逻辑后绘制前,否则会出bug if(_nextScene) { setNextScene(); } kmGLPushMatrix(); //创建单位矩阵 kmMat4 identity; kmMat4Identity(&identity); //绘制场景 if(_runningScene) { _runningScene->visit(_renderer, identity, false); _eventDispatcher->dispatchEvent(_eventAfterVisit); } //绘制观察节点,如果你需要在场景中设立观察节点,请调用摄像机的setNotificationNode函数 if(_notificationNode) { _notificationNode->visit(_renderer, identity, false); } //绘制屏幕左下角的状态 if(_displayStats) { showStats(); } //渲染 _renderer->render(); //渲染后 _eventDispatcher->dispatchEvent(_eventAfterDraw); kmGLPopMatrix(); _totalFrames++; if(_openGLView) { _openGLView->swapBuffers(); } //计算绘制时间 if(_displayStats) { calculateMPF(); } }
其中和绘制相关的是visit的调用和render的调用,其中visit函数会调用节点的draw函数,在3.0之前的版本中draw函数就会直接调用绘制代码,3.0版本是在draw函数中将绘制命令存入到renderer中,然后renderer函数去进行真正的绘制,首先来看sprite的draw函数。
voidSprite::draw(Renderer *renderer, constkmMat4 &transform, booltransformUpdated) { //检查是否超出边界,自动裁剪 _insideBounds = transformUpdated ? renderer->checkVisibility(transform, _contentSize) : _insideBounds; if(_insideBounds) { //初始化 _quadCommand.init(_globalZOrder, _texture->getName(), _shaderProgram, _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 } }
这里面用了两种不同的绘制命令quadCommand初始化后就可以加入到绘制命令中,customDebugDrawCommand传入了一个回调函数,具体的命令种类会在后面介绍。其中自定义的customDebugDrawCommand命令在初始化的时候只传入了全局z轴坐标,因为它的绘制函数全部都在传入的回调函数里面,_quadCommand则需要传入全局z轴坐标,贴图名称,shader,混合,坐标点集合,坐标点集个数,变换。
voidRenderer::render() { _isRendering = true; if(_glViewAssigned) { //清除 _drawnBatches = _drawnVertices = 0; //排序 for(auto &renderqueue : _renderGroups) { renderqueue.sort(); } //绘制 visitRenderQueue(_renderGroups[0]); flush(); } clean(); _isRendering = false; }
Render类中的render函数进行真正的绘制,首先排序,再进行绘制,从列表中的第一个组开始绘制。在visitRenderQueue函数中可以看到五种不同类型的绘制命令类型,分别对应五个类,这五个类都继承自RenderCommand。
QUAD_COMMAND:QuadCommand类绘制精灵等。所有绘制图片的命令都会调用到这里,处理这个类型命令的代码就是绘制贴图的openGL代码,下一篇文章会详细介绍这部分代码。
CUSTOM_COMMAND:CustomCommand类自定义绘制,自己定义绘制函数,在调用绘制时只需调用已经传进来的回调函数就可以,裁剪节点,绘制图形节点都采用这个绘制,把绘制函数定义在自己的类里。
这种类型的绘制命令不会在处理命令的时候调用任何一句openGL代码,而是调用你写好并设置给func的绘制函数,后续文章会介绍引擎中的所有自定义绘制,并自己实现一个自定义的绘制。
BATCH_COMMAND:BatchCommand类批处理绘制,批处理精灵和粒子
其实它类似于自定义绘制,也不会再render函数中出现任何一句openGL函数,它调用一个固定的函数,这个函数会在下一篇文章中介绍。
GROUP_COMMAND:GroupCommand类绘制组,一个节点包括两个以上绘制命令的时候,把这个绘制命令存储到另外一个_renderGroups中的元素中,并把这个元素的指针作为一个节点存储到_renderGroups[0]中。
整个GROUP_COMMAND的原理需要从addCommand讲起。
voidRenderer::addCommand(RenderCommand* command) { //获得栈顶的索引 intrenderQueue =_commandGroupStack.top(); //调用真正的addCommand addCommand(command, renderQueue); } voidRenderer::addCommand(RenderCommand* command, intrenderQueue) { CCASSERT(!_isRendering,"Cannot add command while rendering"); CCASSERT(renderQueue >=0, "Invalid render queue"); CCASSERT(command->getType() != RenderCommand::Type::UNKNOWN_COMMAND, "Invalid Command Type"); //将命令加入到数组中 _renderGroups[renderQueue].push_back(command); }
addCommand有“真假”两个,几乎所有添加渲染命令的地方,调用的都是第一个“假” 。
addCommand,它实际上不是真正的把命令添加到_renderGroups中,它是获得需要把命令加入到_renderGroups位置中的索引,这个索引是从_commandGroupStack获得的,_commandGroupStack是个栈,当我们创建一个GROUP_COMMAND时,需要调用pushGroup函数,它是把当前这个命令在_renderGroups的索引位置压到栈顶,当addCommand时,调用top,获得这个位置:
_groupCommand.init(_globalZOrder); renderer->addCommand(&_groupCommand); renderer->pushGroup(_groupCommand.getRenderQueueID());
GROUP_COMMAND一般用于绘制的节点有一个以上的绘制命令,把这些命令组织在一起,无需排定它们之间的顺序,他们作为一个整体被调用,所以一定要记住,栈是push,pop对应的,关于这个节点的所有的绘制命令被添加完成后,请调用pop,将这个值从栈顶弹出,否则后面的命令也会被添加到这里。
接下来就可以解释为什么调用的起始只需调用visitRenderQueue(_renderGroups[0]);,为什么只是0,其他的呢?
它们会在处理GROUP_COMMAND被调用:
elseif(RenderCommand::Type::GROUP_COMMAND == commandType) { flush(); intrenderQueueID = ((GroupCommand*) command)->getRenderQueueID(); visitRenderQueue(_renderGroups[renderQueueID]); }
如有错误,欢迎指出
下一篇介绍贴图和批处理的openGL代码部分
来源网址:/article/1378813.html
相关文章推荐
- cocos2D-X源码分析之从cocos2D-X学习OpenGL(1)----cocos2D-X渲染结构
- 从Cocos2d-x学习OpenGL -- Cocos2d-x渲染结构
- cocos2D-X源码分析之从cocos2D-X学习OpenGL(1)----cocos2D-X渲染结构
- cocos2D-X源码分析之从cocos2D-X学习OpenGL(1)----cocos2D-X渲染结构
- cocos2D-X源码分析之从cocos2D-X学习OpenGL----cocos2D-X渲染结构
- cocos2D-X源码分析之从cocos2D-X学习OpenGL(1)----cocos2D-X渲染结构
- Cocos2d-x3.2与OpenGL渲染总结
- cocos2d-x 3.x的底层渲染机制
- COCOS2DX引擎深入三———渲染结构(3.0)
- Cocos2d-x 3.x 图形学渲染系列五
- Cocos2d-x 3.x 图形学渲染系列八
- [Cocos2d塔防游戏开发]Cocos2dx-3.X完成塔防游戏《王国保卫战》--敌人(一)
- [Cocos2d塔防游戏开发]Cocos2dx-3.X完成塔防游戏《王国保卫战》--防御塔(四)之升级防御塔
- Cocos2d-x 3.x 图形学渲染系列二十七
- Cocos2d-x 3.x 图形学渲染系列二
- Cocos2d-x 3.x 图形学渲染系列三
- Cocos2d-x 3.x 图形学渲染系列四
- Cocos2d-x 3.x 图形学渲染系列十六
- Cocos2d-x3.2与OpenGL渲染总结(一)Cocos2d-x3.2的渲染流程
- Cocos2d-x 3.x 图形学渲染系列二十七