一、GLProgram Shader
下面是是最简单着色器。
#version 200 // 版本声明uniform vec4 color; // uniform 声明#define MOTHER_FUCKER 1 // 宏定义attribute vec4 a_position; // 顶点属性声明void main(){...... // 函数体}
cocos自己封装了一个GLProgram类,用于构建shader Program。它将一个着色器的代码划分成以下几个部分:
- header(自定义)
- 版本声明,如#version 100
- 精度声明,如precision mediump float
- 内置uniforms变量
- 指的cocos预定义的,并不是glsl内置的
- 宏定义(自定义)
- source
- uniforms(**自定义**)
- 注意不要和内置重叠
- 顶点属性
- 包含内置、自定义,注意不要重叠
- 其他全局定义(自定义)
- main
- uniforms(**自定义**)
详情见以下:
// ****************************************************// ************ 一、shader header// ****************************************************if 自定义header:......; // 使用自定义的headerelse: // 没有自定义,则默认采用以下规则:if CC_PLATFORM_WINRTif vertex_shaderprecision mediump float;precision mediump int;elseprecision mediump float;precision mediump int;if CC_PLATFORM_ANDROID#version 100precision highp float;precision highp int;if not CC_PLATFORM_WIN32 and not CC_PLATFORM_LINUX and not CC_PLATFORM_MACif vertex_shader:precision highp float;precision highp int;elseprecision mediump float;precision mediump int;// ****************************************************// ************ 二、内置uniforms,// ****************************************************// 这些是会自动添加的,没有使用到的在link阶段将被优化掉uniform vec4 CC_AmbientColor; //uniform mat4 CC_PMatrix; // 投影矩阵,如果顶点坐标已经是世界坐标了就用这个。uniform mat4 CC_MultiViewPMatrix[4]; // 多视图的投影矩阵uniform mat4 CC_MVMatrix; // ModelView矩阵,简称MV矩阵uniform mat4 CC_MVPMatrix; // ModelViewProjection矩阵,简称MVP矩阵uniform mat4 CC_MultiViewMVPMatrix[4]; // 多视图的MVP矩阵uniform mat3 CC_NormalMatrix; // 法线矩阵:https://www.yuque.com/tvvhealth/cs/yavt4r#wl0P2// time = 总运行时间 = totalFrames x intervaluniform vec4 CC_Time; // [0]:time/10; [1]:time; [2]:time*2; [3]:time*4uniform vec4 CC_SinTime; // [0]:time/8; [1]:time/4; [2]:time/2; [3]:sin(time)uniform vec4 CC_CosTime; // [0]:time/8; [1]:time/4; [2]:time/2; [3]:cos(time)uniform vec4 CC_Random01; // [0]:0~1; [1]:0~1; [2]:0~1; [3]:0~1;uniform sampler2D CC_Texture0; //uniform sampler2D CC_Texture1; //uniform sampler2D CC_Texture2; //uniform sampler2D CC_Texture3; //// ****************************************************// ************ 三、宏定义// ****************************************************// 自定义的,将字符串按一下规则解析:// 将字符串:FUCK;SHIT 1;MOTHER 1;,转换成下面的宏定义// #define FUCK// #define SHIT 1// #define MOTHER 1// ****************************************************// ************ 四、source// ****************************************************// 这部分都要自定义,但是有一些规则,不能随便写。//********************* 自定义uniformsuniform vec3 motherfucker; //自定义uniforms,注意不要和上面内置的重叠,没有使用到的在link阶段将被优化掉......//********************* 顶点属性attributes,没有使用到的在link阶段将被优化掉// 以下是cocos固定的内置顶点属性,不会自定添加要我们自己写attribute vec4 a_position; // location=0,对应枚举值:VERTEX_ATTRIB_POSITION=0attribute vec4 a_color; // location=1,对应枚举值:VERTEX_ATTRIB_COLOR=1attribute vec2 a_texCoord; // location=2,对应枚举值:VERTEX_ATTRIB_TEX_COORD=2attribute vec2 a_texCoord1; // location=3,对应枚举值:VERTEX_ATTRIB_TEX_COORD1=3attribute vec2 a_texCoord2; // location=4,对应枚举值:VERTEX_ATTRIB_TEX_COORD2=4attribute vec2 a_texCoord3; // location=5,对应枚举值:VERTEX_ATTRIB_TEX_COORD3=5attribute vec3 a_normal; // location=6,对应枚举值:VERTEX_ATTRIB_NORMAL=6attribute vec4 a_blendWeight; // location=7,对应枚举值:VERTEX_ATTRIB_BLEND_WEIGHT=7attribute vec4 a_blendIndex; // location=8,对应枚举值:VERTEX_ATTRIB_BLEND_INDEX=8attribute vec3 a_tangent; // location=9,对应枚举值:VERTEX_ATTRIB_TANGENT=9attribute vec3 a_binormal; // location=10,对应枚举值:VERTEX_ATTRIB_BINORMAL=10attribute in vec3 shit; // 这里是我们自定义的顶点属性......;......; // 这里是我们自定义的其他一些全局定义void main() { // main函数体。......}
二、数据结构
struct Uniform // 保存uniform变量除值以外的信息{GLint location; // 位置值,glGetUniformLocation得到GLenum type; // 分量的数据类型,GL_FLOAT、GL_UNSIGNED_BYTE等。GLint size; // 分量数量,0~4,size * type = 数据类型大小string name; // 变量名称};struct VertexAttrib // 保存顶点属性除值以外的信息{GLuint index; // location,glGetAttribLocation的返回值GLenum type; // 分量数据类型,GL_FLOAT、GL_UNSIGNED_BYTE等。GLint size; // 分量数量,0~4,size * type = 数据类型大小string name; // 变量名称};class CC_DLL GLProgram : public Ref{GLuint _program; // GL program对象句柄。GLuint _vertShader; // 顶点着色器句柄GLuint _fragShader; // 片段着色器句柄GLint _builtInUniforms[UNIFORM_MAX]; // cocos内置的uniform全局变量的location,并不是glsl内置的// key: index,枚举实现,唯一识别该变量// value: location,该变量的位置值。unordered_map<std::string, Uniform> _userUniforms;// link之后,也就是active的非cocos内置的uniform变量,link会把代码中只定义但没有被使用的部分优化掉// cocos内置的都是CC_开头的。// key: uniform name// value: uniform除了值的所有信息,如name,location,type,sizeunordered_map<std::string, VertexAttrib> _vertexAttribs;// link之后,也就是active的attribute变量// key: attribute name// value: attribute除了值的所有信息,如index, name,type,sizeunordered_map<GLint, std::pair<GLvoid*, unsigned int>> _hashForUniforms;// 在C++端缓存了一份所有uniform变量的值,目的是在更新uniform时可以先和缓存比较,看值是否有改变,如果没有则不执行gl call更新// key: uniform location// value: 是一个pair,// frist: 存储uniform value的内存,动态分配,用于保存可能频繁更新的uniform值。// second: 内存大小,也是uniform数据类型大小。Director* _director; // cached director pointer for callingUniformFlags _flags; // 标识用到了哪些内置的uniforms,下面的位域bitfield实现。struct UniformFlags {unsigned int usesTime:1; // 占1it,以下相同,总共1byte = 8bitunsigned int usesNormal:1;unsigned int usesMVP:1;unsigned int usesMultiViewMVP:1;unsigned int usesMV:1;unsigned int usesP:1;unsigned int usesMultiViewP:1;unsigned int usesRandom:1;UniformFlags() { memset(this, 0, sizeof(*this)); } // 初始都为0};};
三、创建
class CC_DLL GLProgram : public Ref{// ****************************************// !!!注意,所有的create方法创建的实例都不会自动缓存到GLProgramCache中。需要手动调用。// 内置的Shader,则会在初始化的时候就缓存起来了。// !!!注意,如果我们要直接操作GLProgram对象,务必自己retain起来维护,因为它是一个autorelease对象。// ****************************************// 生成一个编译、链接好的GL program,着色器代码内容如下:// header:默认// uniforms:内置// 宏定义:空// source: vShaderByteArray、fShaderByteArraystatic GLProgram* createWithByteArrays(const GLchar* vShaderByteArray, // 顶点着色器代码const GLchar* fShaderByteArray); // 片段着色器代码static GLProgram* createWithFilenames(......); // 文件路径版本,参数相同// header:默认// uniforms:内置// 宏定义:compileTimeDefines// source: vShaderByteArray、fShaderByteArraystatic GLProgram* createWithByteArrays(const GLchar* vShaderByteArray, // 顶点着色器代码const GLchar* fShaderByteArray, // 片段着色器代码const std::string& compileTimeDefines); // 宏定义,格式见上面static GLProgram* createWithFilenames(......); // 文件路径版本,参数相同// header:compileTimeHeaders// uniforms:内置// 宏定义:compileTimeDefines// source: vShaderByteArray、fShaderByteArraystatic GLProgram* createWithByteArrays(const GLchar* vShaderByteArray, // 顶点着色器代码const GLchar* fShaderByteArray, // 片段着色器代码const std::string& compileTimeHeaders, // 自定义header,见上面const std::string& compileTimeDefines); // 宏定义,格式见上面static GLProgram* createWithFilenames(......); // 文件路径版本,参数相同}
创建过程如下:
GLProgram* GLProgram::createWithByteArrays(const GLchar* vShaderByteArray, // 顶点着色器代码,source部分,见上面const GLchar* fShaderByteArray, // 片段着色器代码,source部分,见上面const std::string& compileTimeHeaders, // header部分,见上面const std::string& compileTimeDefines) // 宏定义{auto ret = new (std::nothrow) GLProgram();if(ret && ret->initWithByteArrays(vShaderByteArray, // 拼好shader代码,然后编译shader并attch to programfShaderByteArray,compileTimeHeaders,compileTimeDefines)){// 1、将source定义的内置attribute,按上面的内置attribute规则build好,name对应的location// 2、链接gl program// 3、获取所有active的attributes// 4、获取所有active的uniformsret->link(); // do jobs above。ret->updateUniforms(); // 获得内置的uniforms,没有active的uniform则更新相应flagret->autorelease();return ret;}CC_SAFE_DELETE(ret);return nullptr;}
1、initWithByteArrays
// 相关函数源码如下:bool GLProgram::initWithByteArrays(const GLchar* vShaderByteArray,const GLchar* fShaderByteArray,const std::string& compileTimeHeaders,const std::string& compileTimeDefines){_program = glCreateProgram(); // create program objectCHECK_GL_ERROR_DEBUG(); // 检查上一次glGetError到现在之间gl调用的log// 将字符串:FUCK;SHIT 1;MOTHER 1;,转换成下面的宏定义// #define FUCK// #define SHIT 1// #define MOTHER 1std::string replacedDefines = "";replaceDefines(compileTimeDefines, replacedDefines); // 插入宏定义,详细见上面。_vertShader = _fragShader = 0; // shader object idif (vShaderByteArray) {if (!compileShader( // 编译并生成一个vertex shader object&_vertShader, // 保存生成的vertex shader object idGL_VERTEX_SHADER, // 要生成的是vertex shader objectvShaderByteArray, // source部分:顶点着色器代码compileTimeHeaders, // header部分replacedDefines)) { // 宏定义CCLOG("cocos2d: ERROR: Failed to compile vertex shader");return false;}}//......; // 片段着色器的创建同上,只是source部分不同。if (_vertShader) {glAttachShader(_program, _vertShader);}CHECK_GL_ERROR_DEBUG();if (_fragShader) {glAttachShader(_program, _fragShader);}clearHashUniforms(); // 回收之前的uniform变量的值的存储区。CHECK_GL_ERROR_DEBUG();return true;}
2、compileShader
在initWithByteArrays中调用。
// 生成并编译好一个shaderbool GLProgram::compileShader(GLuint* shader, // 保存shader object idGLenum type, // GL_VERTEX_SHADER or GL_FRAGMENT_SHADERconst GLchar* source, // source部分const std::string& compileTimeHeaders, // header部分const std::string& convertedDefines) // 宏定义部分{GLint status;if (!source){return false;}// 实现上面的shader header部分逻辑std::string headersDef;if (compileTimeHeaders.empty()) {#if CC_TARGET_PLATFORM == CC_PLATFORM_WINRTheadersDef = (type == GL_VERTEX_SHADER ? "precision mediump float;\n precision mediump int;\n" : "precision mediump float;\n precision mediump int;\n");// Bugfix to make shader variables types constant to be understood by the current Android Virtual Devices or Emulators. This will also eliminate the 0x501 and 0x502 OpenGL Errors during emulation.// Changed shader data types mediump to highp to remove possible sprite joggling on some Android phones.#elif CC_TARGET_PLATFORM == CC_PLATFORM_ANDROIDheadersDef = "#version 100\n precision highp float;\n precision highp int;\n";#elif (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32 && CC_TARGET_PLATFORM != CC_PLATFORM_LINUX && CC_TARGET_PLATFORM != CC_PLATFORM_MAC)headersDef = (type == GL_VERTEX_SHADER ? "precision highp float;\n precision highp int;\n" : "precision mediump float;\n precision mediump int;\n");#endif}else{headersDef = compileTimeHeaders;}// shader代码的合成const GLchar *sources[] = {headersDef.c_str(), // 1、header部分COCOS2D_SHADER_UNIFORMS, // 2、内置uniforms,在代码中没有使用的,在link时会被优化掉。convertedDefines.c_str(), // 3、宏定义source}; // 4、source部分,attribute变量在这里。*shader = glCreateShader(type); // 创建一个shader objectglShaderSource( // 写入shader code*shader, // shader objectsizeof(sources)/sizeof(*sources), // sources的元素个数sources, // sourcesnullptr);glCompileShader(*shader); // 编译glGetShaderiv(*shader, GL_COMPILE_STATUS, &status); // 检查编译结果if (! status) { // 编译出错,获取日志GLsizei length;glGetShaderiv(*shader, GL_SHADER_SOURCE_LENGTH, &length);GLchar* src = (GLchar *)malloc(sizeof(GLchar) * length);glGetShaderSource(*shader, length, nullptr, src);CCLOG("cocos2d: ERROR: Failed to compile shader:\n%s", src);if (type == GL_VERTEX_SHADER){CCLOG("cocos2d: %s", getVertexShaderLog().c_str());}else{CCLOG("cocos2d: %s", getFragmentShaderLog().c_str());}free(src);return false;}return (status == GL_TRUE);}
3、link
在createWithByteArrays中调用。
bool GLProgram::link() {CCASSERT(_program != 0, "Cannot link invalid program");GLint status = GL_TRUE;bindPredefinedVertexAttribs(); // 将source中定义的内置attribute,按规则设置好location,见下面源码glLinkProgram(_program);// Calling glGetProgramiv(...GL_LINK_STATUS...) will force linking of the program at this moment.// Otherwise, they might be linked when they are used for the first time. (I guess this depends on the driver implementation)// So it might slow down the "booting" process on certain devices. But, on the other hand it is important to know if the shader// linked successfully. Some shaders might be downloaded in runtime so, release version should have this check.// For more info, see Github issue #16231glGetProgramiv(_program, GL_LINK_STATUS, &status);if (status == GL_FALSE){CCLOG("cocos2d: ERROR: Failed to link program: %i", _program);GL::deleteProgram(_program);_program = 0;}else{parseVertexAttribs(); // 见下面源码,获得所有的active的attributeparseUniforms(); // 见下面源码,获得所有的active的uniformclearShader();}return (status == GL_TRUE);}// 将source中定义的内置attribute,按规则设置好locationvoid GLProgram::bindPredefinedVertexAttribs(){static const struct {const char *attributeName;int location;} attribute_locations[] ={{GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION},{GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR},{GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORD},{GLProgram::ATTRIBUTE_NAME_TEX_COORD1, GLProgram::VERTEX_ATTRIB_TEX_COORD1},{GLProgram::ATTRIBUTE_NAME_TEX_COORD2, GLProgram::VERTEX_ATTRIB_TEX_COORD2},{GLProgram::ATTRIBUTE_NAME_TEX_COORD3, GLProgram::VERTEX_ATTRIB_TEX_COORD3},{GLProgram::ATTRIBUTE_NAME_NORMAL, GLProgram::VERTEX_ATTRIB_NORMAL},};// layout(location=0) in vec4 a_position; // location=0,对应枚举值:VERTEX_ATTRIB_POSITION=0// layout(location=1) in vec4 a_color; // location=1,对应枚举值:VERTEX_ATTRIB_COLOR=1// layout(location=2) in vec2 a_texCoord; // location=2,对应枚举值:VERTEX_ATTRIB_TEX_COORD=2// layout(location=3) in vec2 a_texCoord1; // location=3,对应枚举值:VERTEX_ATTRIB_TEX_COORD1=3// layout(location=4) in vec2 a_texCoord2; // location=4,对应枚举值:VERTEX_ATTRIB_TEX_COORD2=4// layout(location=5) in vec2 a_texCoord3; // location=5,对应枚举值:VERTEX_ATTRIB_TEX_COORD3=5// layout(location=6) in vec3 a_normal; // location=6,对应枚举值:VERTEX_ATTRIB_NORMAL=6const int size = sizeof(attribute_locations) / sizeof(attribute_locations[0]);for(int i=0; i<size;i++) {// 指定_program的attribute的locationglBindAttribLocation(_program, attribute_locations[i].location, attribute_locations[i].attributeName);}}void GLProgram::parseVertexAttribs() // 获得所有active的attribute{//_vertexAttribs.clear();// Query and store vertex attribute meta-data from the program.GLint activeAttributes;GLint length;glGetProgramiv(_program, GL_ACTIVE_ATTRIBUTES, &activeAttributes); // the number of active attribute variables for program.if(activeAttributes > 0){VertexAttrib attribute;// returns the length of the longest active attribute name for program,// including the null termination characterglGetProgramiv(_program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &length);if(length > 0) {GLchar* attribName = (GLchar*) alloca(length + 1);for(int i = 0; i < activeAttributes; ++i) {// Query attribute info.glGetActiveAttrib(_program, i, length, nullptr, &attribute.size, &attribute.type, attribName);attribName[length] = '\0';attribute.name = std::string(attribName);// Query the pre-assigned attribute locationattribute.index = glGetAttribLocation(_program, attribName);_vertexAttribs[attribute.name] = attribute;}}}else{GLchar ErrorLog[1024];glGetProgramInfoLog(_program, sizeof(ErrorLog), nullptr, ErrorLog);CCLOG("Error linking shader program: '%s'\n", ErrorLog);}}void GLProgram::parseUniforms() // 获得所有active的uniforms,和上面同理。{//_userUniforms.clear();// Query and store uniforms from the program.GLint activeUniforms;glGetProgramiv(_program, GL_ACTIVE_UNIFORMS, &activeUniforms);if(activeUniforms > 0){GLint length;glGetProgramiv(_program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &length);if(length > 0){Uniform uniform;GLchar* uniformName = (GLchar*)alloca(length + 1);for(int i = 0; i < activeUniforms; ++i){// Query uniform info.glGetActiveUniform(_program, i, length, nullptr, &uniform.size, &uniform.type, uniformName);uniformName[length] = '\0';// Only add uniforms that are not built-in.// The ones that start with 'CC_' are built-insif(strncmp("CC_", uniformName, 3) != 0) {// remove possible array '[]' from uniform nameif(length > 3){char* c = strrchr(uniformName, '[');if(c){*c = '\0';}}uniform.name = std::string(uniformName);uniform.location = glGetUniformLocation(_program, uniformName);GLenum __gl_error_code = glGetError();if (__gl_error_code != GL_NO_ERROR){CCLOG("error: 0x%x uniformName: %s", (int)__gl_error_code, uniformName);}assert(__gl_error_code == GL_NO_ERROR);_userUniforms[uniform.name] = uniform;}}}}else{GLchar ErrorLog[1024];glGetProgramInfoLog(_program, sizeof(ErrorLog), nullptr, ErrorLog);CCLOG("Error linking shader program: '%s'\n", ErrorLog);}}
4、updateUniforms
在createWithByteArrays中调用。
// 获得gl program link成功后,active的uniforms// active的意思就是在代码使用到的uniform变量。void GLProgram::updateUniforms(){// _userUniforms里面其实已经有了,不知道为什么这里还要再gl call,难道这个方法还会被外调?_builtInUniforms[UNIFORM_AMBIENT_COLOR] = glGetUniformLocation(_program, UNIFORM_NAME_AMBIENT_COLOR);_builtInUniforms[UNIFORM_P_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_P_MATRIX);_builtInUniforms[UNIFORM_MULTIVIEW_P_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_MULTIVIEW_P_MATRIX);_builtInUniforms[UNIFORM_MV_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_MV_MATRIX);_builtInUniforms[UNIFORM_MVP_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_MVP_MATRIX);_builtInUniforms[UNIFORM_MULTIVIEW_MVP_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_MULTIVIEW_MVP_MATRIX);_builtInUniforms[UNIFORM_NORMAL_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_NORMAL_MATRIX);_builtInUniforms[UNIFORM_TIME] = glGetUniformLocation(_program, UNIFORM_NAME_TIME);_builtInUniforms[UNIFORM_SIN_TIME] = glGetUniformLocation(_program, UNIFORM_NAME_SIN_TIME);_builtInUniforms[UNIFORM_COS_TIME] = glGetUniformLocation(_program, UNIFORM_NAME_COS_TIME);_builtInUniforms[UNIFORM_RANDOM01] = glGetUniformLocation(_program, UNIFORM_NAME_RANDOM01);_builtInUniforms[UNIFORM_SAMPLER0] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER0);_builtInUniforms[UNIFORM_SAMPLER1] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER1);_builtInUniforms[UNIFORM_SAMPLER2] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER2);_builtInUniforms[UNIFORM_SAMPLER3] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER3);// 更新bitfiled,哪些内置uniforms在被使用。_flags.usesP = _builtInUniforms[UNIFORM_P_MATRIX] != -1;_flags.usesMultiViewP = _builtInUniforms[UNIFORM_MULTIVIEW_P_MATRIX] != -1;_flags.usesMV = _builtInUniforms[UNIFORM_MV_MATRIX] != -1;_flags.usesMVP = _builtInUniforms[UNIFORM_MVP_MATRIX] != -1;_flags.usesMultiViewMVP = _builtInUniforms[UNIFORM_MULTIVIEW_MVP_MATRIX] != -1;_flags.usesNormal = _builtInUniforms[UNIFORM_NORMAL_MATRIX] != -1;_flags.usesTime = (_builtInUniforms[UNIFORM_TIME] != -1 ||_builtInUniforms[UNIFORM_SIN_TIME] != -1 ||_builtInUniforms[UNIFORM_COS_TIME] != -1);_flags.usesRandom = _builtInUniforms[UNIFORM_RANDOM01] != -1;this->use(); // glUseProgram()// Since sampler most probably won't change, set it to 0,1,2,3 now.if(_builtInUniforms[UNIFORM_SAMPLER0] != -1)setUniformLocationWith1i(_builtInUniforms[UNIFORM_SAMPLER0], 0); // 更准确的写法应该是GL_TEXTURE0 - GL_TEXTURE0if(_builtInUniforms[UNIFORM_SAMPLER1] != -1)setUniformLocationWith1i(_builtInUniforms[UNIFORM_SAMPLER1], 1); // 更准确的写法应该是GL_TEXTURE1 - GL_TEXTURE0if(_builtInUniforms[UNIFORM_SAMPLER2] != -1)setUniformLocationWith1i(_builtInUniforms[UNIFORM_SAMPLER2], 2); // 更准确的写法应该是GL_TEXTURE2 - GL_TEXTURE0if(_builtInUniforms[UNIFORM_SAMPLER3] != -1)setUniformLocationWith1i(_builtInUniforms[UNIFORM_SAMPLER3], 3); // 更准确的写法应该是GL_TEXTURE3 - GL_TEXTURE0glGetError(); // 这里为什么又不用宏CHECK_GL_ERROR_DEBUG了,太不专业了。}
四、获取attribute
class CC_DLL GLProgram : public Ref{// 从_vertexAttribs缓存中获取变量名称为name的顶点属性的信息。// 这个缓存是在link之后建立的。并没有发生GL callVertexAttrib* getVertexAttrib(const std::string &name);// 通过GL call 获取变量名称为attributeName的顶点属性的locationGLint getAttribLocation(const std::string &attributeName) const;}// *************************** 下面是获取cocos内置attribute的例子auto program = GLProgram::createWithFilenames(......);program->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_COLOR); // attribute vec4 a_colorprogram->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_POSITION); // attribute vec4 a_positionprogram->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_TEX_COORD); // attribute vec2 a_texCoordprogram->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_TEX_COORD1); // attribute vec2 a_texCoord1program->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_TEX_COORD2); // attribute vec2 a_texCoord2program->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_TEX_COORD3); // attribute vec2 a_texCoord3program->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_NORMAL); // attribute vec3 a_normalprogram->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_BLEND_WEIGHT); // attribute vec4 a_blendWeightprogram->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_BLEND_INDEX); // attribute vec4 a_blendIndexprogram->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_TANGENT); // attribute vec3 a_tangentprogram->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_BINORMAL); // attribute vec3 a_binormal
五、获得uniform
class CC_DLL GLProgram : public Ref{// 从_userUniforms获取user define的uniform的信息,也即不是cocos 内置的CC_开头的uniform,// _userUniforms缓存是在link的时候建立的Uniform* getUniform(const std::string& name);// 下面这两个是一样的效果,通过GL call获得变量名称为name的uniform的location// 这源码写的有够随便的。GLint getUniformLocation(const std::string& name) const;GLint getUniformLocationForName(const char* name) const;}// *************************** 下面是获取cocos内置uniform的例子auto program = GLProgram::createWithFilenames(......);// 注意getUniform无法获得cocos内置uniformprogram->getUniformLocation(GLProgram::UNIFORM_NAME_AMBIENT_COLOR); // uniform vec4 CC_AmbientColorprogram->getUniformLocation(GLProgram::UNIFORM_NAME_P_MATRIX); // uniform mat4 CC_PMatrixprogram->getUniformLocation(GLProgram::UNIFORM_NAME_MULTIVIEW_P_MATRIX); // uniform mat4 CC_MultiViewPMatrix[4]program->getUniformLocation(GLProgram::UNIFORM_NAME_MV_MATRIX); // uniform mat4 CC_MVMatrixprogram->getUniformLocation(GLProgram::UNIFORM_NAME_MVP_MATRIX); // uniform mat4 CC_MVPMatrixprogram->getUniformLocation(GLProgram::UNIFORM_NAME_MULTIVIEW_MVP_MATRIX); // uniform mat4 CC_MultiViewMVPMatrix[4]program->getUniformLocation(GLProgram::UNIFORM_NAME_NORMAL_MATRIX); // uniform mat3 CC_NormalMatrixprogram->getUniformLocation(GLProgram::UNIFORM_NAME_TIME); // uniform vec4 CC_Timeprogram->getUniformLocation(GLProgram::UNIFORM_NAME_SIN_TIME); // uniform vec4 CC_SinTimeprogram->getUniformLocation(GLProgram::UNIFORM_NAME_COS_TIME); // uniform vec4 CC_CosTimeprogram->getUniformLocation(GLProgram::UNIFORM_NAME_RANDOM01); // uniform vec4 CC_Random01program->getUniformLocation(GLProgram::UNIFORM_NAME_SAMPLER0); // uniform sampler2D CC_Texture0program->getUniformLocation(GLProgram::UNIFORM_NAME_SAMPLER1); // uniform sampler2D CC_Texture1program->getUniformLocation(GLProgram::UNIFORM_NAME_SAMPLER2); // uniform sampler2D CC_Texture2program->getUniformLocation(GLProgram::UNIFORM_NAME_SAMPLER3); // uniform sampler2D CC_Texture3program->getUniformLocation(GLProgram::UNIFORM_NAME_ALPHA_TEST_VALUE); // uniform vec4 CC_AmbientColor
六、更新uniform
以下是更新program中uniform值的接口,注意这些更新操作都会先和本地缓存的uniform值检查,如果没有改变则不执行glUniform的更新操作。
注意,最好要使用这些方法进行更新,不要自私调用GL CALL,否则会导致uniform值缓存的不同步。
class CC_DLL GLProgram : public Ref{// uniform int shit = i1void setUniformLocationWith1i(GLint location, GLint i1);// uniform ivec2 shit = ivec2(i1, i2)void setUniformLocationWith2i(GLint location, GLint i1, GLint i2);// uniform ivec3 shit = ivec2(i1, i2, i3)void setUniformLocationWith3i(GLint location, GLint i1, GLint i2, GLint i3);// uniform ivec4 shit = ivec2(i1, i2, i3, i4)void setUniformLocationWith4i(GLint location, GLint i1, GLint i2, GLint i3, GLint i4);// uniform ivec2[] shitvoid setUniformLocationWith2iv( GLint location, GLint* ints, unsigned int numberOfArrays);// uniform ivec3[] shitvoid setUniformLocationWith3iv(GLint location, GLint* ints, unsigned int numberOfArrays);// uniform ivec4[] shitvoid setUniformLocationWith4iv(GLint location, GLint* ints, unsigned int numberOfArrays);// uniform float shitvoid setUniformLocationWith1f(GLint location, GLfloat f1);// uniform vec2 shitvoid setUniformLocationWith2f(GLint location, GLfloat f1, GLfloat f2);// uniform vec3 shitvoid setUniformLocationWith3f(GLint location, GLfloat f1, GLfloat f2, GLfloat f3);// uniform vec4 shitvoid setUniformLocationWith4f(GLint location, GLfloat f1, GLfloat f2, GLfloat f3, GLfloat f4);// uniform float[] shitvoid setUniformLocationWith1fv(GLint location, const GLfloat* floats, unsigned int numberOfArrays);// uniform vec2[] shitvoid setUniformLocationWith2fv(GLint location, const GLfloat* floats, unsigned int numberOfArrays);// uniform vec3[] shitvoid setUniformLocationWith3fv(GLint location, const GLfloat* floats, unsigned int numberOfArrays);// uniform vec4[] shitvoid setUniformLocationWith4fv(GLint location, const GLfloat* floats, unsigned int numberOfArrays);// uniform mat2[] shitvoid setUniformLocationWithMatrix2fv(GLint location, const GLfloat* matrixArray, unsigned int numberOfMatrices);// uniform mat3[] shitvoid setUniformLocationWithMatrix3fv(GLint location, const GLfloat* matrixArray, unsigned int numberOfMatrices);// uniform mat4[] shitvoid setUniformLocationWithMatrix4fv(GLint location, const GLfloat* matrixArray, unsigned int numberOfMatrices);void setUniformsForBuiltins(const Mat4 &modelView); // 更新内置uniforms的值void setUniformsForBuiltins(); // modelView是当前栈顶的MV}
