
1开始,先创建一个Layercolor
Scene *scene=Scene::create(); director->runWithScene(scene); //目标 auto layer = Layercolor::create(color4B(0,255,0,255),100,100); //主要的步骤就是设置了node 的 _position layer->setposition(10,10); scene->addChild(layer);
2 看一下Layercolor的初始化方法
bool Layercolor::initWithcolor(const color4B& color,GLfloat w,GLfloat h){ if (Layer::init()) { // default blend function //指定混合模式 _blendFunc = BlendFunc::Alpha_NON_PREMulTIPLIED; /* realcolor和displayedcolor 记录元素本身的颜色属性 displayedcolor和displayedOpacity方法用于表示和父亲元素叠加过后的最终绘制颜色 sprite用于父亲颜色和自己纹理的混合,Laycolor默认一致,不叠加颜色 */ _displayedcolor.r = _realcolor.r = color.r; _displayedcolor.g = _realcolor.g = color.g; _displayedcolor.b = _realcolor.b = color.b; _displayedOpacity = _realOpacity = color.a; //四个顶点 初始化 for (size_t i = 0; i<sizeof(_squareVertices) / sizeof( _squareVertices[0]); i++ ) { _squareVertices[i].x = 0.0f; _squareVertices[i].y = 0.0f; } //四个顶点的颜色归一化,颜色是一样的 updatecolor(); //w,h 为 设计分辨率,设置顶点的范围 setContentSize(Size(w,h)); /* 每个node拥有一个GLProgramState实例 查找这种类型的shader GLProgram SHADER_name_position_color_NO_MVP */ GLProgramState* state=GLProgramState::getorCreateWithGLProgramname(GLProgram::SHADER_name_position_color_NO_MVP); setGLProgramState(state); return true; } return false;}
/// overrIDe contentSizevoID Layercolor::setContentSize(const Size & size){ //没有赋值的为0,也就是 0(0,0) 1(w,0) 2 (0,h) 3(w,h) //绘制顺序为012 213 _squareVertices[1].x = size.wIDth; _squareVertices[2].y = size.height; _squareVertices[3].x = size.wIDth; _squareVertices[3].y = size.height; Layer::setContentSize(size);}voID Node::setContentSize(const Size & size){ if ( ! size.equals(_contentSize)) { _contentSize = size; //得到锚点在本地坐标系下的坐标 _anchorPointInPoints = Vec2(_contentSize.wIDth * _anchorPoint.x,_contentSize.height * _anchorPoint.y ); //告诉该更新了 _transformUpdated = _transformDirty = _inverseDirty = _contentSizeDirty = true; }}
3 Director::drawScene方法为正式绘图,如下
voID Director::drawScene(){ //省略部分代码 glClear(GL_color_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //兼容cocos2.0,暂时忽略 pushmatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); // draw the scene if (_runningScene) {//正式访问 _runningScene->visit(_renderer,Mat4::IDENTITY,false);//第一次的矩阵是单位矩阵 _eventdispatcher->dispatchEvent(_eventAfterVisit); } //开始真正的opengl _renderer->render(); popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); _totalFrames++; // swap buffers if (_openGLVIEw) { _openGLVIEw->swapBuffers();//这个之后再看 } if (_displayStats) { calculateMPF();//不知道啥意思 }}
标红不分为开始遍历节点,但不进行opengl绘制,进入代码如下:
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 /* 为了便于迁移到v3.0,我们仍然支持Mat4堆栈, 但它已被弃用,您的代码不应该依赖它 */ Director* director = Director::getInstance(); director->pushmatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); //把刚生产的模型视图矩阵加入到顶部的modevIEw【对scene来说,执行下面代码之前,里面已经有3个modelvIEw】 //这个代码针对2.0的,对3.1没啥意义了 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,flags); else break; } // self draw this->draw(renderer,flags); for(auto it=_children.cbegin()+i; it != _children.cend(); ++it) (*it)->visit(renderer,flags); } else { this->draw(renderer,flags); } /* 画完了就退出战,是兼容2.0的时候,现在不需要这个了 矩阵的转换都在GPU的shader中了 */ director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); // FIX ME: Why need to set _orderOfArrival to 0?? // Please refer to https://github.com/cocos2d/cocos2d-x/pull/6920 // reset for next frame // _orderOfArrival = 0;}
uint32_t Node::processparentFlags(const Mat4& parenttransform,uint32_t parentFlags){ uint32_t flags = parentFlags;//先把父亲的改动标志传过来 //如果转置矩阵 变化了, 标记为脏数据,要更新 flags |= (_transformUpdated ? FLAGS_transform_DIRTY : 0); //如果大小改变了,标记为脏数据,要更新 flags |= (_contentSizeDirty ? FLAGS_CONTENT_SIZE_DIRTY : 0); // if(_usingnormalizedposition && (flags & FLAGS_CONTENT_SIZE_DIRTY)) { CCASSERT(_parent,"setnormalizedposition() doesn‘t work with orphan nodes"); auto s = _parent->getContentSize(); _position.x = _normalizedposition.x * s.wIDth; _position.y = _normalizedposition.y * s.height; _transformUpdated = _transformDirty = _inverseDirty = true; } //转置矩阵和大小其中一个变了 if(flags & FLAGS_DIRTY_MASK) _modelVIEwtransform = this->transform(parenttransform);//节点自己的转换矩阵,节点的本地坐标乘以这个矩阵就会得到世界坐标 //更新完毕,标记为false _transformUpdated = false; _contentSizeDirty = false; return flags;}
self->draw为绘制自己,但不是真的绘制,而是让自己关联一个绘制命令Command,Layercolor的draw方法重写如下:
//transform为本地坐标转世界坐标的矩阵voID Layercolor::draw(Renderer *renderer,const Mat4 &transform,uint32_t flags){ _customCommand.init(_globalZOrder); //回调函数 _customCommand.func = CC_CALLBACK_0(Layercolor::onDraw,this,transform,flags); //把绘制命令的东西放到renderer里面 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;//齐次坐标 //得出来的pos就是世界坐标下的pos了 _modelVIEwtransform.transformVector(&pos); //pos.w 世界坐标的w始终为1 //这个世界坐标会在shader内乘以相机矩阵和裁剪矩阵,得出最后的视口需要的坐标 _noMVPVertices[i] = Vec3(pos.x,pos.y,pos.z)/pos.w; }}
代码把需要绘制的信息加入到了customCommand里面。
4 _renderer->render(); 负责执行command内的opengl绘制命令,代码如下:
voID Renderer::render(){ //Process render commands //1. Sort render commands based on ID //renderGroups包括若干rederqueue,默认使用第一个, //renderquque包括若干个rendercommand for (auto &renderqueue : _renderGroups) { renderqueue.sort(); } visitRenderQueue(_renderGroups[0]); flush(); clean(); }
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::CUSTOM_COMMAND == commandType)//比如 Layercolor { flush(); auto cmd = static_cast<CustomCommand*>(command); cmd->execute();//会调用Layercolor::onDraw,直接开始绘图 } }}
5 cmd->execute会调用customCommand的回调函数,在Layercolor中为onDraw,代码如下:
//通过自定义方法进行回调 transform为 本地坐标转世界坐标的旋转矩阵voID Layercolor::onDraw(const Mat4& transform,uint32_t flags){ getGLProgram()->use();//layercolor 的tansform为相机矩阵*裁剪矩阵 getGLProgram()->setUniformsForBuiltins(transform);//设置顶点着色器中全局变量的值,如MVP矩阵 //启用 顶点坐标和颜色 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); setGLBufferData(_squarecolors,4 * sizeof(color4F),1); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_color,4,0);#else //找到顶点的索引 _noMVPVertices为世界坐标中的四个顶点的值,存在了cpu中,没有存到显存 glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_position,3,0,_noMVPVertices); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_color,_squarecolors);#endif // EMSCRIPTEN //混合,源和目标 颜色的混合 GL::blendFunc( _blendFunc.src,_blendFunc.dst ); //画这四个点 glDrawArrays(GL_TRIANGLE_STRIP,4); //这是记录图元和顶点吗 // CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,4); auto __renderer__ = Director::getInstance()->getRenderer(); __renderer__->addDrawnBatches(1); __renderer__->addDrawnVertices(4); }
Layercolor绘制过程比较简单,没有纹理设置,只有顶点和颜色,通过glDrawArrays绘制完成
总结以上是内存溢出为你收集整理的cocos源码分析--LayerColor的绘制过程全部内容,希望文章能够帮你解决cocos源码分析--LayerColor的绘制过程所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)