cocos2D-X源码分析之从cocos2D-X学习OpenGL3----BATCH_COMMAND

个人原创,欢迎转载,转载请注明原文地址http://blog.csdn.net/bill_man

上一篇介绍了QUAD_COMMAND渲染命令,顺带介绍了VAO和VBO,这一篇介绍批处理渲染命令BatchCommand,批处理命令的处理在Render中比较简单

  1. elseif(commandType==RenderCommand::Type::BATCH_COMMAND)
  2. {
  3. //将之前缓存的绘制
  4. flush();
  5. autocmd=static_cast<BatchCommand*>(command);
  6. //调用命令
  7. cmd->execute()
  8. }

首先调用flush将之前缓存的VBO绘制出来,然后调用命令自己的执行函数,这个过程和CUSTOM_COMMAND是一样的,不同的是这里的execute调用的是BatchCommand确定的绘制函数,CUSTOM_COMMAND调用是传入的func函数,这里看一下BatchCommand的execute函数

    voidBatchCommand::execute()
  1. //设置渲染材质
  2. //shader
  3. _shader->use();
  4. //先取得MV和P,然后将MV和P相乘得到MVP,即模型视图投影矩阵
  5. _shader->setUniformsForBuiltins(_mv);
  6. //选择纹理单元,建立一个绑定到目标纹理的有名称的纹理
  7. GL::bindTexture2D(_textureID);
  8. //混合
  9. GL::blendFunc(_blendType.src,_blendType.dst);
  10. //绘制
  11. _textureAtlas->drawQuads();
  12. }

首先介绍其中一个重要的概念MVP,MVP即模型(Model)、视图(View)、投影(Projection)。

模型矩阵:所有物体都处于世界空间中,所以绘制和做变换的前提是把物体由模型空间转换到世界空间中,而这个转换就需要乘以模型矩阵。

视图矩阵:下一步需要把世界空间转换到相机空间或者是视角空间中,这需要乘以视图矩阵。

投影矩阵:最后需要将3d的立方体投影到一个2d平面上,需要从观察坐标系到齐次坐标系,需要乘以投影矩阵。整个过程如下图所示:



setUniformsForBuiltins函数

    voidGLProgram::setUniformsForBuiltins(constkmMat4&matrixMV)
  1. //通过flag中的变量判断是否使用了相关的矩阵,这些标志变量在updateUniforms被设置
  2. kmMat4matrixP;
  3. kmGLGetMatrix(KM_GL_PROJECTION,&matrixP);
  4. if(_flags.usesP)
  5. setUniformlocationWithmatrix4fv(_uniforms[UNIFORM_P_MATRIX],matrixP.mat,1);
  6. if(_flags.usesMV)
  7. setUniformlocationWithmatrix4fv(_uniforms[UNIFORM_MV_MATRIX],matrixMV.mat,1);
  8. if(_flags.usesMVP){
  9. kmMat4matrixMVP;
  10. kmMat4Multiply(&matrixMVP,&matrixP,&matrixMV);
  11. setUniformlocationWithmatrix4fv(_uniforms[UNIFORM_MVP_MATRIX],matrixMVP.mat,248)"> }
  12. if(_flags.usesTime){
  13. Director*director=Director::getInstance();
  14. //这里不会使用真实的每帧时间去设置,那样太耗费效率
  15. floattime=director->getTotalFrames()*director->getAnimationInterval();
  16. setUniformlocationWith4f(_uniforms[GLProgram::UNIFORM_TIME],time/10.0,time,time*2,time*4);
  17. setUniformlocationWith4f(_uniforms[GLProgram::UNIFORM_SIN_TIME],time/8.0,time/4.0,time/2.0,sinf(time));
  18. setUniformlocationWith4f(_uniforms[GLProgram::UNIFORM_COS_TIME],cosf(time));
  19. if(_flags.usesRandom)
  20. setUniformlocationWith4f(_uniforms[GLProgram::UNIFORM_RANDOM01],CCRANDOM_0_1(),CCRANDOM_0_1());
  21. }

这个函数里,有一个频繁出现的变量名uniforms,uniform是一种和着色器相关的,它必须被声明为全局变量,用于整个图元批次向保持不变的着色器传递数据,对于顶点着色器来说,可能最普遍的统一值就是变换矩阵,它通过调用gluniformXXXX系列函数向着色器传递数据,这里这个函数被封装了,调用setUniformlocationXXXX系列函数可以设置uniforms,这个函数首先通过调用updateUniformlocation函数判断这个uniforms的值是否确实被更新(在一个hash表里存上曾经设置过的键值对),如果确实需要被更新再调用gluniformXXXX更新这个uniforms,节约效率

bindTexture2DN函数主要是调用glActiveTexture和glBindTexture做贴图的绑定

    voidbindTexture2DN(gluinttextureUnit,gluinttextureId)
  1. #ifCC_ENABLE_GL_STATE_CACHE
  2. //做缓存,那么就不用为相同的textureId重复调用
  3. CCASSERT(textureUnit<kMaxActiveTexture,"textureUnitistoobig");
  4. if(s_currentBoundTexture[textureUnit]!=textureId)
  5. {
  6. s_currentBoundTexture[textureUnit]=textureId;
  7. activeTexture(GL_TEXTURE0+textureUnit);
  8. glBindTexture(GL_TEXTURE_2D,textureId);
  9. }
  10. #else
  11. glActiveTexture(GL_TEXTURE0+textureUnit);
  12. glBindTexture(GL_TEXTURE_2D,textureId);
  13. #endif
  14. }

glActiveTexture选择一个纹理单元,线面的纹理函数将作用于该纹理单元上,参数为符号常量GL_TEXTUREi ,i的取值范围为0~N-1,N是opengl实现支持的最大纹理单元数,这里,因为批处理只有一个纹理,所以textureUnit一直是0,由于使用缓存,只会被调用一次

glBindTexture建立一个绑定到目标纹理的有名称的纹理。比如把一个贴图绑定到一个形状上。

最后调用的绘制函数上一篇介绍的类似,另外关于shader和混合的问题,将在后面单独开文章介绍

在引擎中使用BatchCommand这个命令的地方有两处ParticleBatchNode和SpriteBatchNode,使用方法很简单。

    _batchCommand.init(
  1. _globalZOrder,
  2. _shaderProgram,
  3. _blendFunc,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> _textureAtlas,248)"> transform);
  4. renderer->addCommand(&_batchCommand);

需要说明的是,在3.0之后的版本中,由于添加了auto-batch功能,ParticleBatchNode和SpriteBatchNode的节约效率的功能已经不那么明显,但是3.0之前的版本中,把精灵放在SpriteBatchNode父节点上和将粒子系统放在ParticleBatchNode,是能够把相同的精灵批处理,对于相同的贴图只调用一次绘制函数,还是对提升效率很有帮助的。

相关文章

    本文实践自 RayWenderlich、Ali Hafizji 的文章《...
Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@1...
第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从C...
    Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发...
1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《...
   Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试...