上一章跟踪了 cocos2d-x调用CCScene::draw()的过程,直到访问子节点以及渲染,本章就具体看看几个类的渲染。
voID Scene::render(Renderer* renderer){ auto director = Director::getInstance(); Camera* defaultCamera = nullptr; 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); director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION,Camera::_visitingCamera->getVIEwProjectionMatrix()); //visit the scene visit(renderer,transform,0); renderer->render();</strong> // director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); } Camera::_visitingCamera = nullptr;}
visit递归访问该场景的子节点,传递transform(当前节点相对父节点的变换矩阵)和flags(该节点transform是否改变和大小变化)给子节点,子节点根据父节点的transform以及自身的参数来渲染,通过2种方式:直接执行opengl命令和将opengl传递给render对象
renderer->render()会执行渲染对象render的opengl渲染命令,对象render通过队列来存储opengl渲染命令。
通过一下类的draw(),可以很明显看出来。
voID Sprite::draw(Renderer *renderer,const Mat4 &transform,uint32_t flags){ //根据父节点flags(是否变化,位移、大小),自身的transform flag以及是否可见来判定是否渲染#if CC_USE_CulliNG _insIDeBounds = (flags & FLAGS_transform_DIRTY) ? renderer->checkVisibility(transform,_contentSize) : _insIDeBounds; if(_insIDeBounds)#endif { //初始化渲染参数 _quadCommand.init(_globalZOrder,_texture->getname(),getGLProgramState(),_blendFunc,&_quad,1,flags); //将渲染命令添加到队列中 renderer->addCommand(&_quadCommand);#if CC_SPRITE_DEBUG_DRAW _deBUGDrawNode->clear(); Vec2 vertices[4] = { Vec2( _quad.bl.vertices.x,_quad.bl.vertices.y ),Vec2( _quad.br.vertices.x,_quad.br.vertices.y ),Vec2( _quad.tr.vertices.x,_quad.tr.vertices.y ),Vec2( _quad.tl.vertices.x,_quad.tl.vertices.y ),}; _deBUGDrawNode->drawpoly(vertices,4,true,color4F(1.0,1.0,1.0));#endif //CC_SPRITE_DEBUG_DRAW }}1.SpriteBatchNode类
voID SpriteBatchNode::draw(Renderer *renderer,const Mat4 &transform,uint32_t flags){ // Optimization: Fast dispatch //判断是否有quads(V3F_C4B_T2F_Quad结构,记录顶点,纹理和颜色3种数据) if( _textureAtlas->getTotalQuads() == 0 ) { return; } for (const auto &child : _children) {#if CC_USE_PHYSICS auto physicsBody = child->getPhysicsBody(); if (physicsBody) { child->updatetransformFromPhysics(transform,flags); }#endif //有子节点的情况下,先更新子节点的transform child->updatetransform(); } //opengl渲染,初始化渲染命令 _batchCommand.init(_globalZOrder,getGLProgram(),_textureAtlas,flags); //添加渲染函数到render对象 renderer->addCommand(&_batchCommand);}
为什么要先调用子类updatetransform(),以后有机会再谈。这里谈下Sprite和SpriteBatchNode的关系SpriteBatchNode一般用于多个Sprite使用相同的纹理,可以将这些Sprite加入SpriteBatchNode,这样渲染的时候就仅仅需要渲染一次.Node在visit的时候,针对其子节点,会先排序,排完后仅递归访问zorder<0的子节点。而排序函数会使用变量变量_reorderChildDirty标志位。当Sprite加入SpriteBatchNode的时候,会处理次标志位,这样加入SpriteBatchNode的Sprite就不会递归visit了。
可以看到SpriteBatchNode的渲染方式是通过添加Opengl的命令到render进程的。
voID Layercolor::draw(Renderer *renderer,uint32_t flags){ //这里的渲染有点不同,它有个回调 _customCommand.init(_globalZOrder,flags); _customCommand.func = CC_CALLBACK_0(Layercolor::onDraw,this,flags); renderer->addCommand(&_customCommand); for(int i = 0; i < 4; ++i) { Vec4 pos; pos.x = _squareVertices[i].x; pos.y = _squareVertices[i].y; pos.z = _positionZ; pos.w = 1; _modelVIEwtransform.transformVector(&pos); _noMVPVertices[i] = Vec3(pos.x,pos.y,pos.z)/pos.w; }}
voID Layercolor::onDraw(const Mat4& transform,uint32_t flags) { //gluseProgram(program) getGLProgram()->use(); //设置uniform矩阵的 getGLProgram()->setUniformsForBuiltins(transform); //打开OPENGL的状态 GL::enabLevertexAttribs( GL::VERTEX_ATTRIB_FLAG_position | GL::VERTEX_ATTRIB_FLAG_color ); // // Attributes //#ifdef EMSCRIPTEN //设置缓冲数据 setGLBufferData(_noMVPVertices,4 * sizeof(Vec3),0); //位置渲染 glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_position,3,GL_float,GL_FALSE,0,0); //设置数据 setGLBufferData(_squarecolors,4 * sizeof(color4F),1); //颜色渲染 glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_color,0);#else glBindBuffer(GL_ARRAY_BUFFER,0); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_position,_noMVPVertices); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_color,_squarecolors);#endif // EMSCRIPTEN //颜色混合 GL::blendFunc( _blendFunc.src,_blendFunc.dst ); //从数组中读取顶点数据 glDrawArrays(GL_TRIANGLE_STRIP,4); // auto __renderer__ = Director::getInstance()->getRenderer(); // __renderer__->addDrawnBatches(__drawcalls__); // __renderer__->addDrawnVertices(__vertices__); CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,4);}
上面的回调函数是直接调用openglAPI 进行渲染了。
补充说明opengl相关的东西:
Node会存储一个GLProgramState指针_glProgramState,该指针持有其成员指针GLPromgram的“状态”(我理解成值,即uniforms和attributes)。
uniform变量是外部application程序传递给(vertex和fragment)shader的变量,一般用来表示:变换矩阵,材质,光照参数和颜色等信息。
attribute变量是只能在vertex shader中使用的变量,一般用来表示一些顶点的数据,如:顶点坐标,法线,纹理坐标,顶点颜色等。
voID Label::draw(Renderer *renderer,const Mat4 &transform,uint32_t flags){ // Don't do calculate the culling if the transform was not updated bool transformUpdated = flags & FLAGS_transform_DIRTY;#if CC_USE_CulliNG _insIDeBounds = transformUpdated ? renderer->checkVisibility(transform,_contentSize) : _insIDeBounds; if(_insIDeBounds)#endif { _customCommand.init(_globalZOrder,flags); //渲染回调 _customCommand.func = CC_CALLBACK_0(Label::onDraw,this,transformUpdated); renderer->addCommand(&_customCommand); }}通过代码可以看出,Label的渲染方式与colorLayer类似,重点在于起回调函数onDraw.
oID Label::onDraw(const Mat4& transform,bool transformUpdated){ CC_PROfileR_START("Label - draw"); // Optimization: Fast dispatch if( _batchNodes.size() == 1 && _textureAtlas->getTotalQuads() == 0 ) { return; } //获取Label的GLProgram auto glprogram = getGLProgram(); //gluseProgram(program), installs the program object specifIEd by program as part //of current rendering state.安装program作为当前渲染状态 glprogram->use(); GL::blendFunc( _blendFunc.src,_blendFunc.dst ); if (_currentLabelType == LabelType::TTF) { glprogram->setUniformlocationWith4f(_uniformTextcolor,_textcolorF.r,_textcolorF.g,_textcolorF.b,_textcolorF.a); }//描边或者发光效果 if (_currLabelEffect == LabelEffect::OUTliNE || _currLabelEffect == LabelEffect::GLOW) { glprogram->setUniformlocationWith4f(_uniformEffectcolor,_effectcolorF.r,_effectcolorF.g,_effectcolorF.b,_effectcolorF.a); } //阴影效果 if(_shadowEnabled && _shadowBlurRadius <= 0) { drawShadowWithoutBlur(); } //设置uniforms矩阵 glprogram->setUniformsForBuiltins(transform); //下面的2个for循环类似域Sprite和SpirteBatchNode的渲染 for(const auto &child: _children) { if(child->getTag() >= 0) child->updatetransform(); } for (const auto& batchNode:_batchNodes) { batchNode->getTextureAtlas()->drawQuads(); } CC_PROfileR_Stop("Label - draw");}
渲染暂时就写这么多,关于更多的类,大家可以自己进代码看下,以及更加详细的调用都可以直接看到。opengl的使用以及原理可以查看下面的网址:
http://www.jb51.cc/article/p-ytwajipz-so.html
http://www.jb51.cc/article/p-xacaethn-tc.html
http://www.songho.ca/opengl/gl_transform.html
以上是内存溢出为你收集整理的cocos-2dx 渲染(3)全部内容,希望文章能够帮你解决cocos-2dx 渲染(3)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)