首页 > 代码库 > Cocos2dx引擎12-OpenGLES渲染之LayerColor
Cocos2dx引擎12-OpenGLES渲染之LayerColor
在前面微博中讲述了Cocos2dx引擎OpenGL渲染准备Shader方面,本博客中将使用LayerColor来讲述OpenGL的渲染过程。
1、LayerColor对象创建
添加LayerColor元素到游戏中:
autolayerColor = LayerColor::create(Color4B(255, 0, 0, 255), 100, 100); layerColor->setPosition(100,100); this->addChild(layerColor);
下面是LayerColor::create方法:
LayerColor* LayerColor::create(const Color4B& color, GLfloat width, GLfloat height) { LayerColor * layer = new LayerColor(); if( layer &&layer->initWithColor(color,width,height)) { layer->autorelease(); return layer; } CC_SAFE_DELETE(layer); return nullptr; }
1、使用new操作符创建新LayerColor对象
2、使用initWithColor方法初始化新建的LayerColor对象
3、LayerColor创建并初始化成功后,将该对象加热自动内存管理
在LayerColor::initWithColor方法中:
boolLayerColor::initWithColor(const Color4B& color, GLfloat w, GLfloat h){ if (Layer::init()){ _blendFunc =BlendFunc::ALPHA_NON_PREMULTIPLIED; _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(); setContentSize(Size(w, h)); setGLProgramState(GLProgramState::getOrCreateWithGLProgramName(GLProgram::SHADER_NAME_POSITION_COLOR_NO_MVP)); return true; } return false; }
1、调用Layer::init()方法,该方法的主要作用设置默认大小,其实在下面会重新设置LayerColor大小
2、设置混合模式为_blendFunc =BlendFunc::ALPHA_NON_PREMULTIPLIED
3、设置四个顶点的颜色
4、设置四个顶点的坐标,并设置Layer的大小
5、设置LayerColor渲染所使用Shader程序对应的GLProgramState
LayerColor其实是一个四边形,OpenGL会以四边形的方式渲染LayerColor,故需要设置四边形的顶点坐标&顶点颜色;所有的GLProgramState都会保持在GLProgramStateCache::_glProgramStates中,首次获取该GLProgramState时会新建GLProgramState对象,然后将该对象插入到GLProgramStateCache::_glProgramStates中。
2、LayerColor渲染
首先先看一下游戏的Function调用流程:
Application::run() { …… DisplayLinkDirector::mainLoop() …… } DisplayLinkDirector::mainLoop() { …… Director::drawScene() …… …… } Director::drawScene() { …… Node::visit(…) …… Renderer::render() …… } Node::visit(…) { …… LayerColor::draw(…) …… }
LayerColor::draw(…)方法如下:
voidLayerColor::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) { _customCommand.init(_globalZOrder); _customCommand.func =CC_CALLBACK_0(LayerColor::onDraw, this, transform, 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; } }
1、初始化_customCommand对象,_customCommand是一个渲染指令
2、设置_customCommand的回调函数为LayerColor::onDraw
3、将该LayerColor的渲染指令_customCommand加入到渲染队列中
4、分别将四个顶点坐标通过模型视图矩阵转换
Renderer::addCommand(…)方法如下:
voidRenderer::addCommand(RenderCommand* command) { int renderQueue =_commandGroupStack.top(); addCommand(command, renderQueue); } voidRenderer::addCommand(RenderCommand* command, int renderQueue) { _renderGroups[renderQueue].push_back(command); }
1、 获取_commandGroupStack的堆栈,其实_commandGroupStack存储的是_renderGroups数组的位置编号
2、 将新的渲染命令加入_renderGroups[renderQueue]堆栈中
Renderer::render()方法如下:
voidRenderer::render() { _isRendering = true; if (_glViewAssigned) { _drawnBatches = _drawnVertices = 0; for (auto &renderqueue : _renderGroups){ renderqueue.sort(); } visitRenderQueue(_renderGroups[0]); flush(); } clean(); _isRendering = false; }
1、将_isRendering该帧是否渲染标志设为true
2、遍历_renderGroups,并对RenderQueue进行排序
3、真正的渲染部分,其实在_renderGroups中只目前只存在一个渲染集合
4、刷新OpenGL中参数
5、将_renderGroups能够所有CommandClean
RenderQueue::sort()渲染命令排序方法:
voidRenderQueue::sort() { std::sort(std::begin(_queueNegZ),std::end(_queueNegZ), compareRenderCommand); std::sort(std::begin(_queuePosZ), std::end(_queuePosZ),compareRenderCommand); } staticbool compareRenderCommand(RenderCommand* a, RenderCommand* b) { return a->getGlobalOrder() < b->getGlobalOrder(); }
1、将Command中元素Z坐标小于0的Command集合,按照重小到大排序
2、将Command中元素Z坐标大于0的Command集合,按照重小到大排序
Renderer::visitRenderQueue方法如下:
voidRenderer::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) { …… }else if(RenderCommand::Type::GROUP_COMMAND== commandType) { …… }else if(RenderCommand::Type::CUSTOM_COMMAND== commandType) { …… }else if(RenderCommand::Type::BATCH_COMMAND ==commandType) { …… }else if (RenderCommand::Type::MESH_COMMAND== commandType) { …… } } }
1、获取RenderQueue长度
2、遍历RenderQueue列表,并对不同类型的渲染Command分别处理
3、当渲染Commad类型为QUAD_COMMAND时
4、当渲染Commad类型为GROUP_COMMAND时
5、当渲染Commad类型为CUSTOM_COMMAND时
6、当渲染Commad类型为BATCH_COMMAND时
7、当渲染Commad类型为MESH_COMMAND时
由于篇幅有限,每种渲染的具体流程后续会分别讨论,由于LayerColor使用的是CustomCommand,下面会分析CustomCommand的具体渲染方法
elseif(RenderCommand::Type::CUSTOM_COMMAND == commandType) { flush(); auto cmd = static_cast<CustomCommand*>(command); cmd->execute(); }
1、更新OpenGL参数,每次渲染前都需执行的操作,作用是将OpenGL参数设置为默认状态
2、请强制转换类型,并执行渲染Command
voidCustomCommand::execute() { if(func) { func(); } }
判断func是否为空,若func不为空,执行该方法;func是一个回调函数,在添加LayerColor渲染命时指定,如:_customCommand.func= CC_CALLBACK_0(LayerColor::onDraw, this, transform, flags)
LayerColor真正的渲染部分:
voidLayerColor::onDraw(const Mat4& transform, uint32_t flags) { getGLProgram()->use(); getGLProgram()->setUniformsForBuiltins(transform); GL::enableVertexAttribs( GL::VERTEX_ATTRIB_FLAG_POSITION| GL::VERTEX_ATTRIB_FLAG_COLOR ); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION,3, GL_FLOAT, GL_FALSE, 0, _noMVPVertices); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR,4, GL_FLOAT, GL_FALSE, 0, _squareColors); GL::blendFunc( _blendFunc.src, _blendFunc.dst); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,4); }
1、使用对应的Shader程序
2、设置对应的Uniforms 矩阵
3、使能OpenGL中顶点数组和颜色数组功能
4、设置四边形的四个顶点和颜色
5、设置混合模式
6、glDrawArrays画四边形
LayerColor其实是一个有颜色的四边形,渲染LayerColor只需要在正确的位置画一个有颜色的四边形即可;Cocos2dx使用渲染方式是OpenGL ES(Windows平台不同),在OpenGL ES中并没有直接画四边形的方法,故需要借助画三角形的方法画四边形,如glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)为画四边形;
Cocos2dx引擎12-OpenGLES渲染之LayerColor