前文说完了,opengl初始化结束。接着就是cocos进行绘制了。在Application-win32.cpp实现的Application::run(),可以看到程序通过CCDirector的mainloop()来绘制,而mainloop具体实现是在其子类DisplayLinkDirector实现的。
PVRFrameEnableControlWindow(false); // Main message loop: LARGE_INTEGER nLast; LARGE_INTEGER nNow; QueryPerformanceCounter(&nLast); initGLContextAttrs(); // Initialize instance and cocos2d. if (!applicationDidFinishLaunching()) { return 0; } auto director = Director::getInstance(); auto glview = director->getOpenGLView(); // Retain glview to avoid glview being released in the while loop glview->retain(); while(!glview->windowShouldClose()) { QueryPerformanceCounter(&nNow); if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart) { nLast.QuadPart = nNow.QuadPart - (nNow.QuadPart % _animationInterval.QuadPart); <strong> director->mainLoop(); glview->pollEvents();</strong> } else { Sleep(1); } } // Director should still do a cleanup if the window was closed manually. if (glview->isOpenGLReady()) { director->end(); director->mainLoop(); director = nullptr; } glview->release(); return true;
这里简单讲解下背景知识。
Cocos2Dx使用了模型视图矩阵、投影矩阵和纹理矩阵。
模型视图矩阵完成模型和视图的变换,包括平移、旋转和缩放。
投影矩阵完成三维空间的顶点映射到二维的屏幕上,有两种投影:正射投影和透视投影。
纹理矩阵用来对纹理进行变换。
OpenGL使用栈来存放矩阵,而且为上述的3种矩阵分别定义了栈(std::stack实现),而OpenGL可以通过矩阵乘法完成平移、旋转和缩放等变换。
cocos会在第一次创建CCDirector类的时候初始化3个矩阵。
bool Director::init(void) { setDefaultValues(); //初始化变量值,如_runningScene,_nextScene,_notificationNode //以及创建调度器和动作管理器,_scheduler,_scheduler ... //初始化纹理缓冲区TextureCache initTextureCache(); //初始化矩阵栈 initMatrixStack(); //创建渲染类 _renderer = new (std::nothrow) Renderer; return true; }初始化矩阵时,先清空栈空间,然后每个栈压入一个单位矩阵(单位矩阵左乘任何顶点,顶点不会变化。单位矩阵不会影响后续的变换)
void Director::initMatrixStack() { while (!_modelViewMatrixStack.empty()) { _modelViewMatrixStack.pop(); } while (!_projectionMatrixStack.empty()) { _projectionMatrixStack.pop(); } while (!_textureMatrixStack.empty()) { _textureMatrixStack.pop(); } _modelViewMatrixStack.push(Mat4::IDENTITY); _projectionMatrixStack.push(Mat4::IDENTITY); _textureMatrixStack.push(Mat4::IDENTITY); }
0.CCDirector::mainloop()中会调用drawScene绘制场景。
void DisplayLinkDirector::mainLoop() { if (_purgeDirectorInNextLoop) { _purgeDirectorInNextLoop = false; purgeDirector(); } else if (_restartDirectorInNextLoop) { _restartDirectorInNextLoop = false; restartDirector(); } else if (! _invalid) { <span style="color:#33cc00;"> //调用scene绘制 drawScene(); // release the objects PoolManager::getInstance()->getCurrentPool()->clear(); } }
1.CCDirector绘制场景。
<pre name="code" class="cpp">void Director::drawScene() { <span style="color:#33cc00;">//清理上次drawScene可能带来的影响</span> ... <span style="color:#33cc00;">//复制一个模式视图矩阵栈的单位矩阵,然后放到栈顶上,假设为T1</span> pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); if (_runningScene) { #if CC_USE_PHYSICS //update Box2d物理引擎的状态 auto physicsWorld = _runningScene->getPhysicsWorld(); if (physicsWorld && physicsWorld->isAutoStep()) { physicsWorld->update(_deltaTime,false); } #endif //clear draw stats _renderer->clearDrawStats(); <span style="color:#33cc00;">//使用T1矩阵,渲染当前场景</span> _runningScene->render(_renderer); _eventDispatcher->dispatchEvent(_eventAfterVisit); } <span style="color:#33cc00;">//_notificationNode ,独立于当前运行的scene,可用于全局的信息提示</span> if (_notificationNode) { _notificationNode->visit(_renderer,Mat4::IDENTITY,0); } if (_displayStats) { showStats(); } _renderer->render(); _eventDispatcher->dispatchEvent(_eventAfterDraw); <span style="color:#33cc00;">//绘制完毕后,矩阵出栈</span> popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); _totalFrames++; // swap buffers if (_openGLView) { _openGLView->swapBuffers(); } if (_displayStats) { calculateMPF(); } }
2.上述的_runningScene->render(_renderer)就是cocos中具体的渲染过程。
<pre name="code" class="cpp">void Scene::render(Renderer* renderer) { auto director = Director::getInstance(); Camera* defaultCamera = nullptr; <span style="color:#33cc00;">//返回一个矩阵,可以转换子UI的坐标到父UI的坐标</span> const auto& transform = getNodeToParentTransform(); if (_cameraOrderDirty) { stable_sort(_cameras.begin(),_cameras.end(),camera_cmp); _cameraOrderDirty = false; } for (const auto& camera : _cameras) { if (!camera->isVisible()) continue; Camera::_visitingCamera = camera; if (Camera::_visitingCamera->getCameraFlag() == CameraFlag::DEFAULT) { defaultCamera = Camera::_visitingCamera; } director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); <span style="color:#33cc00;"> //添加Camer的投影矩阵</span> director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION,Camera::_visitingCamera->getViewProjectionMatrix()); <span style="color:#33cc00;">//访问scene的children并且递归绘制</span> visit(renderer,transform,0); renderer->render(); irector->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); } Camera::_visitingCamera = nullptr; }
3.CCNode的visit()函数
这里解释一下_director->pushMatrix(),_director->loadMatrix()和_director->popMatrix()
_director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW)会复制当前指定栈的栈顶并入栈
_director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW,_modelViewTransform),将当前指定矩阵栈改为当前Node的模型试图矩阵
director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW),出栈
在完成前2步后,程序就会访问并绘制该节点的children,这时通过矩阵栈将当前Node的模型视图矩阵传递给了children,这样保证当children平移,旋转等计算时使用的变换矩阵是一样的,完毕后,出栈删除该矩阵。
那视图模型矩阵究竟起什么作用呢?那就是各自类自身draw所决定的,大体的作用是移动,旋转时用来计算用的。详细的以后再研究
void Node::visit(Renderer* renderer,const Mat4 &parentTransform,uint32_t parentFlags) { // quick return if not visible. children won't be drawn. if (!_visible) { return; } uint32_t flags = processParentFlags(parentTransform,parentFlags); // 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 <strong> _director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); _director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW,_modelViewTransform);</strong> bool visibleByCamera = isVisitableByVisitingCamera(); int i = 0; if(!_children.empty()) { sortAllChildren(); // draw children zOrder < 0 for( ; i < _children.size(); i++ ) { auto node = _children.at(i); <strong><span style="color:#33cc00;">//递归访问</span></strong> if (node && node->_localZOrder < 0) node->visit(renderer,_modelViewTransform,flags); else break; } <span style="color:#33cc00;"> //绘制Node</span> if (visibleByCamera) this->draw(renderer,flags); for(auto it=_children.cbegin()+i; it != _children.cend(); ++it) (*it)->visit(renderer,flags); } else if (visibleByCamera) { <span style="color:#33cc00;">//绘制</span> this->draw(renderer,flags); } <strong> _director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);</strong> }
这样就分析完了,程序是如何渲染scene的,接下来就是各种类各自的渲染了,见下一章。
背景知识:http://my.oschina.net/sulliy/blog/299437
http://blog.csdn.net/augusdi/article/details/19998787
http://blog.csdn.net/teng_ontheway/article/details/26078869
http://blog.sina.com.cn/s/blog_7a2ffd5c0100trz8.html