QuadCommand
来源:互联网 发布:马步芳 知乎 编辑:程序博客网 时间:2024/06/05 09:38
功能:
这个命令主要用来绘制一个或多个矩形区域。相邻的QuedCommand如果使用相同的纹理,就可以实现自动批绘制。提高绘制效率。
条件:
1、不包含自定义的着色器全局变量。
2、使用相同的的shader程序。
3、使用同一张纹理。
4、使用相同的混合模式。
在顺序上相邻的且满足上面四个条件的sprite就可以自动实现批绘制了。
//Start drawing verties in batch for(const auto& cmd : _batchedQuadCommands) { auto newMaterialID = cmd->getMaterialID(); if(_lastMaterialID != newMaterialID || newMaterialID == QuadCommand::MATERIAL_ID_DO_NOT_BATCH) { //Draw quads if(quadsToDraw > 0) { glDrawElements(GL_TRIANGLES, (GLsizei) quadsToDraw*6, GL_UNSIGNED_SHORT, (GLvoid*) (startQuad*6*sizeof(_indices[0])) ); _drawnBatches++; _drawnVertices += quadsToDraw*6; startQuad += quadsToDraw; quadsToDraw = 0; } //Use new material cmd->useMaterial(); _lastMaterialID = newMaterialID; } quadsToDraw += cmd->getQuadCount(); }
实现原理:
Render在访问所以命令前会对他们进行排序,相同类型的命令就会排到一块,遍历命令时,再将相同的且满足自动批绘制条件的精灵加入到内存中,最后进行批绘制。
性能:
1、QuedCommand中使用建立VBO和VAO来提高绘制效率。关于VBO和VAO概念不懂的可以看这篇文章http://blog.csdn.net/bill_man/article/details/38314077。
2、使用glDrawElements进行一次性绘制,减少了函数调用。
if (Configuration::getInstance()->supportsShareableVAO()) { //Set VBO data glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]); // option 1: subdata// glBufferSubData(GL_ARRAY_BUFFER, sizeof(_quads[0])*start, sizeof(_quads[0]) * n , &_quads[start] ); // option 2: data// glBufferData(GL_ARRAY_BUFFER, sizeof(quads_[0]) * (n-start), &quads_[start], GL_DYNAMIC_DRAW); // option 3: orphaning + glMapBuffer glBufferData(GL_ARRAY_BUFFER, sizeof(_quads[0]) * (_numQuads), nullptr, GL_DYNAMIC_DRAW); void *buf = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); memcpy(buf, _quads, sizeof(_quads[0])* (_numQuads)); glUnmapBuffer(GL_ARRAY_BUFFER); glBindBuffer(GL_ARRAY_BUFFER, 0); //Bind VAO GL::bindVAO(_quadVAO); } else {#define kQuadSize sizeof(_quads[0].bl) glBindBuffer(GL_ARRAY_BUFFER, _buffersVBO[0]); glBufferData(GL_ARRAY_BUFFER, sizeof(_quads[0]) * _numQuads , _quads, GL_DYNAMIC_DRAW); GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POS_COLOR_TEX); // vertices glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof(V3F_C4B_T2F, vertices)); // colors glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, kQuadSize, (GLvoid*) offsetof(V3F_C4B_T2F, colors)); // tex coords glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_TEX_COORD, 2, GL_FLOAT, GL_FALSE, kQuadSize, (GLvoid*) offsetof(V3F_C4B_T2F, texCoords)); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _buffersVBO[1]); }
绘制时机:
1、因为所有顶点数据使用一个VBO,当Quad数量超过了VBO所能容纳的最大Quad的数量10922(65536 / 6),将会立即执行前面的绘制。
//Batch quads if(_numQuads + cmd->getQuadCount() > VBO_SIZE) { CCASSERT(cmd->getQuadCount()>= 0 && cmd->getQuadCount() < VBO_SIZE, "VBO is not big enough for quad data, please break the quad data down or use customized render command"); //Draw batched quads if VBO is full drawBatchedQuads(); }
2、如果还没超过,但是转到了其他类型的命令,那么也会立即执行前面的绘制。在Flush2D里会执行。
else if(RenderCommand::Type::GROUP_COMMAND == commandType) { flush(); int renderQueueID = ((GroupCommand*) command)->getRenderQueueID(); visitRenderQueue(_renderGroups[renderQueueID]); } else if(RenderCommand::Type::CUSTOM_COMMAND == commandType) { flush(); auto cmd = static_cast<CustomCommand*>(command); cmd->execute(); } else if(RenderCommand::Type::BATCH_COMMAND == commandType) { flush(); auto cmd = static_cast<BatchCommand*>(command); cmd->execute(); } else if (RenderCommand::Type::MESH_COMMAND == commandType) { flush2D(); auto cmd = static_cast<MeshCommand*>(command); if (_lastBatchedMeshCommand == nullptr || _lastBatchedMeshCommand->getMaterialID() != cmd->getMaterialID()) { flush3D(); cmd->preBatchDraw(); cmd->batchDraw(); _lastBatchedMeshCommand = cmd; } else { cmd->batchDraw(); } }
void Renderer::flush2D(){ drawBatchedQuads(); _lastMaterialID = 0;}
3、不满足自动批绘制条件的会直线先进行绘制。满足条件的则会加入到内存中,等到最后一次性绘制。
if(_lastMaterialID != newMaterialID || newMaterialID == QuadCommand::MATERIAL_ID_DO_NOT_BATCH) { //Draw quads if(quadsToDraw > 0) { glDrawElements(GL_TRIANGLES, (GLsizei) quadsToDraw*6, GL_UNSIGNED_SHORT, (GLvoid*) (startQuad*6*sizeof(_indices[0])) ); _drawnBatches++; _drawnVertices += quadsToDraw*6; startQuad += quadsToDraw; quadsToDraw = 0; } //Use new material cmd->useMaterial(); _lastMaterialID = newMaterialID; }
//Batch quads if(_numQuads + cmd->getQuadCount() > VBO_SIZE) { CCASSERT(cmd->getQuadCount()>= 0 && cmd->getQuadCount() < VBO_SIZE, "VBO is not big enough for quad data, please break the quad data down or use customized render command"); //Draw batched quads if VBO is full drawBatchedQuads(); } _batchedQuadCommands.push_back(cmd);
相似比较:
另外还有一个批绘制命令BatchCommand,这个命令其实一般是配合着SpriteBatchNode使用的,被加入到SpriteBatchNode里的精灵就能进行批绘制。
BatchCommand是用来绘制一个TextrueAtlasde ,如label,TileMap。
所以他们的区别
1、QuadCommand是可以自动批绘制,BatchCommand要手动添加
2、BatchCommand里,我们不能为每个Sprite单独设置相关的opengl ES 绘制参数(????),如混合模式等。所以,SpriteNode适合那些比较简单的模型,如Label,TileMap。
使用
_quadCommand.init( _globalZOrder, _textureAtlas->getTexture()->getName(), getGLProgramState(), _blendFunc, _textureAtlas->getQuads(), _quadsToDraw, transform); renderer->addCommand(&_quadCommand);
- QuadCommand
- 07-渲染流程-5-Sprite渲染-QuadCommand
- 说明指针作为函数参数(一)
- Sonos完整体验:发烧音质,匠心之作
- APT-X 技术
- 【Qt编程】QWT在QtCreator中的安装与使用
- Java多态性理解
- QuadCommand
- 使用指针输出数组元素
- hdu-2038-简易版之最短距离
- Go by Example: Multiple Return Values
- Lua环境搭建
- ceph存储 Linux下rpm制作中spec文件编写规范
- MPLS L2VPN技术VPWS笔记
- samba服务器安装和配置
- game theory week1 problem set 1