cocos2D-X源码分析之从cocos2D-X学习OpenGL(3)----BATCH_COMMAND

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

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

else if(commandType == RenderCommand::Type:: BATCH_COMMAND)
{
     //将之前缓存的绘制
     flush();
     auto cmd = static_cast<BatchCommand*>(command);
     //调用命令
cmd->execute()
}

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

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

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

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

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

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

setUniformsForBuiltins函数

void GLProgram::setUniformsForBuiltins(const kmMat4 &matrixMV)
{
    //通过flag中的变量判断是否使用了相关的矩阵,这些标志变量在updateUniforms被设置
    kmMat4 matrixP;

	kmGLGetMatrix(KM_GL_PROJECTION, &matrixP);

    if(_flags.usesP)
        setUniformLocationWithMatrix4fv(_uniforms[UNIFORM_P_MATRIX], matrixP.mat, 1);

    if(_flags.usesMV)
        setUniformLocationWithMatrix4fv(_uniforms[UNIFORM_MV_MATRIX], matrixMV.mat, 1);

    if(_flags.usesMVP) {
        kmMat4 matrixMVP;
        kmMat4Multiply(&matrixMVP, &matrixP, &matrixMV);
        setUniformLocationWithMatrix4fv(_uniforms[UNIFORM_MVP_MATRIX], matrixMVP.mat, 1);
    }

	if(_flags.usesTime) {
		Director *director = Director::getInstance();
		//这里不会使用真实的每帧时间去设置,那样太耗费效率
        float time = director->getTotalFrames() * director->getAnimationInterval();

        setUniformLocationWith4f(_uniforms[GLProgram::UNIFORM_TIME], time/10.0, time, time*2, time*4);
        setUniformLocationWith4f(_uniforms[GLProgram::UNIFORM_SIN_TIME], time/8.0, time/4.0, time/2.0, sinf(time));
        setUniformLocationWith4f(_uniforms[GLProgram::UNIFORM_COS_TIME], time/8.0, time/4.0, time/2.0, cosf(time));
	}

	if(_flags.usesRandom)
        setUniformLocationWith4f(_uniforms[GLProgram::UNIFORM_RANDOM01], CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1(), CCRANDOM_0_1());
}

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

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

void bindTexture2DN(GLuint textureUnit, GLuint textureId)
{
#if CC_ENABLE_GL_STATE_CACHE
    //做缓存,那么就不用为相同的textureId重复调用了
    CCASSERT(textureUnit < kMaxActiveTexture, "textureUnit is too big");
    if (s_currentBoundTexture[textureUnit] != textureId)
    {
        s_currentBoundTexture[textureUnit] = textureId;
        activeTexture(GL_TEXTURE0 + textureUnit);
        glBindTexture(GL_TEXTURE_2D, textureId);
    }
#else

    glActiveTexture(GL_TEXTURE0 + textureUnit);
    glBindTexture(GL_TEXTURE_2D, textureId);
#endif
}

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

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

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

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

_batchCommand.init(
                       _globalZOrder,
                       _shaderProgram,
                       _blendFunc,
                       _textureAtlas,
                       transform);
renderer->addCommand(&_batchCommand);

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

如有错误,欢迎指出

下一篇介绍图形渲染

cocos2D-X源码分析之从cocos2D-X学习OpenGL(3)----BATCH_COMMAND,布布扣,bubuko.com

时间: 08-13

cocos2D-X源码分析之从cocos2D-X学习OpenGL(3)----BATCH_COMMAND的相关文章

vlc源码分析(七) 调试学习HLS协议

HTTP Live Streaming(HLS)是苹果公司提出来的流媒体传输协议.与RTP协议不同的是,HLS可以穿透某些允许HTTP协议通过的防火墙. 一.HLS播放模式 (1) 点播模式(Video on demand, VOD) 点播模式是指当前时间点可以获取到所有index文件和ts文件,二级index文件中记录了所有ts文件的地址.这种模式允许客户端访问全部内容.上面的例子中就是一个点播模式下的m3u8的结构. (2) 直播模式(Live) 直播模式是指实时生成M3u8和ts文件.它的

Java源码分析——String的设计

Tip:笔者马上毕业了,准备开始Java的进阶学习计划.于是打算先从String类的源码分析入手,作为后面学习的案例.这篇文章寄托着今后进阶系列产出的愿望,希望能坚持下去,不忘初心,让自己保持那份对技术的热爱. 因为学习分析源码,所以借鉴了HollisChuang成神之路的大部分内容,并在此基础上对源码进行了学习,在此感谢. 问题的引入 关于String字符串,对于Java开发者而言,这无疑是一个非常熟悉的类.也正是因为经常使用,其内部代码的设计才值得被深究.所谓知其然,更得知其所以然. 举个例

Android 上千实例源码分析以及开源分析

Android 上千实例源码分析以及开源分析(百度云分享) 要下载的直接翻到最后吧,项目实例有点多. 首先 介绍几本书籍(下载包中)吧. 01_Android系统概述 02_Android系统的开发综述 03_Android的Linux内核与驱动程序 04_Android的底层库和程序 05_Android的JAVA虚拟机和JAVA环境 06_Android的GUI系统 07_Android的Audio系统 08_Android的Video 输入输出系统 09_Android的多媒体系统 10_

【Cocos2d-x】源码分析之 2d/ui/UILayoutDefine.h

#ifndef __UILAYOUTDEFINE_H__ #define __UILAYOUTDEFINE_H__ #include "cocos2d.h" NS_CC_BEGIN namespace ui { /** *控件 距离四周的间隙 *设置间隙之后 相当于控件的大小扩大了 *不会和周围控件紧挨着 有一定间距 * */ class Margin { public: float left; float top; float right; float bottom; public:

【Cocos2d-x】源码分析之 2d/ui/Widget

从今天开始 咱也模仿 红孩儿这些大牛分析源码 ,由于水平有限 不对之处欢迎狂喷.哈哈. #ifndef __UIWIDGET_H__ #define __UIWIDGET_H__ #include "ui/CCProtectedNode.h" #include "ui/UILayoutDefine.h" #include "ui/UILayoutParameter.h" #include "ui/GUIDefine.h" NS

【Cocos2d-x】源码分析之 2d/ui/UILayout

#ifndef __LAYOUT_H__ #define __LAYOUT_H__ #include "ui/UIWidget.h" NS_CC_BEGIN namespace ui { typedef enum { LAYOUT_COLOR_NONE,//空 LAYOUT_COLOR_SOLID,//单一固定颜色的 LAYOUT_COLOR_GRADIENT//有梯度变化的 }LayoutBackGroundColorType;//容器背景颜色类型 typedef enum { LA

cocos2d-x 源码分析 : Ref (CCObject) 源码分析 cocos2d-x内存管理策略

源码版本来自3.x,转载请注明 cocos2d-x 源码分析总目录: http://blog.csdn.net/u011225840/article/details/31743129 1.Ref,AutoreleasePool,PoolManager Ref中包含了一个叫referenceCount的引用计数,当一个Ref类的变量被new的时候,其referenceCount的引用计数被置为1. 其中有三个重要的操作,retain,release,autorelease,下面源码分析时会详细说明

Cocos2dx-3.x 中CCCamera相机类详解及源码分析

Cocos2d-x 3.3版本中加入了相机这个类,该类在3D游戏中是必不可少的,在3D立体游戏中,往往需要视野角度的变化,通过相机的变换才能观察和体验整个游戏世界. CCCamera类基本使用 在游戏中一般有两种类型的相机:一种是透视相机,它在3D游戏中十分常见:另一种是正交相机,它没有透视相机的近大远小的效果而是相机内任何位置的物体大小比例都是一样的. 上图是透视相机的原理图,一般来说,我们通过以下代码创建: _camera = Camera::createPerspective(60, (G

Cocos2d-x 源码分析 : Scheduler(定时器) 源码分析

源码版本 3.1r,转载请注明 我也终于不out了,开始看3.x的源码了,此时此刻的心情只能是wtf!!!!!!!!!!不过也终于告别CC时代了. cocos2d-x 源码分析目录 http://blog.csdn.net/u011225840/article/details/31743129 1.继承结构 没错,是两张图.(你没有老眼昏花..我脑子也没有秀逗..)Ref就是原来的CCObject,而Timer类是与Scheduler类密切相关的类,所以需要把他们放在一起说.Timer和Sche

CCTextureCache类源码分析 (1)

CCTextureCache类源码分析(1): 1. CCTextureCache类: 这个类跟纹理缓存有关,我们跟着代码分析下这个类是怎么对纹理进行缓存的. /** Returns the shared instance of the cache * 单例 */ static CCTextureCache * sharedTextureCache(); 2.我们在创建精灵的时候会调用 CCTextureCache::sharedTextureCache()->addImage(pszFilen