一、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:
......; // 使用自定义的header
else: // 没有自定义,则默认采用以下规则:
if CC_PLATFORM_WINRT
if vertex_shader
precision mediump float;
precision mediump int;
else
precision mediump float;
precision mediump int;
if CC_PLATFORM_ANDROID
#version 100
precision highp float;
precision highp int;
if not CC_PLATFORM_WIN32 and not CC_PLATFORM_LINUX and not CC_PLATFORM_MAC
if vertex_shader:
precision highp float;
precision highp int;
else
precision 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 interval
uniform vec4 CC_Time; // [0]:time/10; [1]:time; [2]:time*2; [3]:time*4
uniform 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
// ****************************************************
// 这部分都要自定义,但是有一些规则,不能随便写。
//********************* 自定义uniforms
uniform vec3 motherfucker; //自定义uniforms,注意不要和上面内置的重叠,没有使用到的在link阶段将被优化掉
......
//********************* 顶点属性attributes,没有使用到的在link阶段将被优化掉
// 以下是cocos固定的内置顶点属性,不会自定添加要我们自己写
attribute vec4 a_position; // location=0,对应枚举值:VERTEX_ATTRIB_POSITION=0
attribute vec4 a_color; // location=1,对应枚举值:VERTEX_ATTRIB_COLOR=1
attribute vec2 a_texCoord; // location=2,对应枚举值:VERTEX_ATTRIB_TEX_COORD=2
attribute vec2 a_texCoord1; // location=3,对应枚举值:VERTEX_ATTRIB_TEX_COORD1=3
attribute vec2 a_texCoord2; // location=4,对应枚举值:VERTEX_ATTRIB_TEX_COORD2=4
attribute vec2 a_texCoord3; // location=5,对应枚举值:VERTEX_ATTRIB_TEX_COORD3=5
attribute vec3 a_normal; // location=6,对应枚举值:VERTEX_ATTRIB_NORMAL=6
attribute vec4 a_blendWeight; // location=7,对应枚举值:VERTEX_ATTRIB_BLEND_WEIGHT=7
attribute vec4 a_blendIndex; // location=8,对应枚举值:VERTEX_ATTRIB_BLEND_INDEX=8
attribute vec3 a_tangent; // location=9,对应枚举值:VERTEX_ATTRIB_TANGENT=9
attribute vec3 a_binormal; // location=10,对应枚举值:VERTEX_ATTRIB_BINORMAL=10
attribute 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,size
unordered_map<std::string, VertexAttrib> _vertexAttribs;
// link之后,也就是active的attribute变量
// key: attribute name
// value: attribute除了值的所有信息,如index, name,type,size
unordered_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 calling
UniformFlags _flags; // 标识用到了哪些内置的uniforms,下面的位域bitfield实现。
struct UniformFlags {
unsigned int usesTime:1; // 占1it,以下相同,总共1byte = 8bit
unsigned 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、fShaderByteArray
static GLProgram* createWithByteArrays(
const GLchar* vShaderByteArray, // 顶点着色器代码
const GLchar* fShaderByteArray); // 片段着色器代码
static GLProgram* createWithFilenames(......); // 文件路径版本,参数相同
// header:默认
// uniforms:内置
// 宏定义:compileTimeDefines
// source: vShaderByteArray、fShaderByteArray
static GLProgram* createWithByteArrays(
const GLchar* vShaderByteArray, // 顶点着色器代码
const GLchar* fShaderByteArray, // 片段着色器代码
const std::string& compileTimeDefines); // 宏定义,格式见上面
static GLProgram* createWithFilenames(......); // 文件路径版本,参数相同
// header:compileTimeHeaders
// uniforms:内置
// 宏定义:compileTimeDefines
// source: vShaderByteArray、fShaderByteArray
static 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 program
fShaderByteArray,
compileTimeHeaders,
compileTimeDefines))
{
// 1、将source定义的内置attribute,按上面的内置attribute规则build好,name对应的location
// 2、链接gl program
// 3、获取所有active的attributes
// 4、获取所有active的uniforms
ret->link(); // do jobs above。
ret->updateUniforms(); // 获得内置的uniforms,没有active的uniform则更新相应flag
ret->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 object
CHECK_GL_ERROR_DEBUG(); // 检查上一次glGetError到现在之间gl调用的log
// 将字符串:FUCK;SHIT 1;MOTHER 1;,转换成下面的宏定义
// #define FUCK
// #define SHIT 1
// #define MOTHER 1
std::string replacedDefines = "";
replaceDefines(compileTimeDefines, replacedDefines); // 插入宏定义,详细见上面。
_vertShader = _fragShader = 0; // shader object id
if (vShaderByteArray) {
if (!compileShader( // 编译并生成一个vertex shader object
&_vertShader, // 保存生成的vertex shader object id
GL_VERTEX_SHADER, // 要生成的是vertex shader object
vShaderByteArray, // 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中调用。
// 生成并编译好一个shader
bool GLProgram::compileShader(
GLuint* shader, // 保存shader object id
GLenum type, // GL_VERTEX_SHADER or GL_FRAGMENT_SHADER
const 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_WINRT
headersDef = (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_ANDROID
headersDef = "#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 object
glShaderSource( // 写入shader code
*shader, // shader object
sizeof(sources)/sizeof(*sources), // sources的元素个数
sources, // sources
nullptr);
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 #16231
glGetProgramiv(_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的attribute
parseUniforms(); // 见下面源码,获得所有的active的uniform
clearShader();
}
return (status == GL_TRUE);
}
// 将source中定义的内置attribute,按规则设置好location
void 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=6
const int size = sizeof(attribute_locations) / sizeof(attribute_locations[0]);
for(int i=0; i<size;i++) {
// 指定_program的attribute的location
glBindAttribLocation(_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 character
glGetProgramiv(_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 location
attribute.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-ins
if(strncmp("CC_", uniformName, 3) != 0) {
// remove possible array '[]' from uniform name
if(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_TEXTURE0
if(_builtInUniforms[UNIFORM_SAMPLER1] != -1)
setUniformLocationWith1i(_builtInUniforms[UNIFORM_SAMPLER1], 1); // 更准确的写法应该是GL_TEXTURE1 - GL_TEXTURE0
if(_builtInUniforms[UNIFORM_SAMPLER2] != -1)
setUniformLocationWith1i(_builtInUniforms[UNIFORM_SAMPLER2], 2); // 更准确的写法应该是GL_TEXTURE2 - GL_TEXTURE0
if(_builtInUniforms[UNIFORM_SAMPLER3] != -1)
setUniformLocationWith1i(_builtInUniforms[UNIFORM_SAMPLER3], 3); // 更准确的写法应该是GL_TEXTURE3 - GL_TEXTURE0
glGetError(); // 这里为什么又不用宏CHECK_GL_ERROR_DEBUG了,太不专业了。
}
四、获取attribute
class CC_DLL GLProgram : public Ref
{
// 从_vertexAttribs缓存中获取变量名称为name的顶点属性的信息。
// 这个缓存是在link之后建立的。并没有发生GL call
VertexAttrib* getVertexAttrib(const std::string &name);
// 通过GL call 获取变量名称为attributeName的顶点属性的location
GLint getAttribLocation(const std::string &attributeName) const;
}
// *************************** 下面是获取cocos内置attribute的例子
auto program = GLProgram::createWithFilenames(......);
program->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_COLOR); // attribute vec4 a_color
program->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_POSITION); // attribute vec4 a_position
program->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_TEX_COORD); // attribute vec2 a_texCoord
program->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_TEX_COORD1); // attribute vec2 a_texCoord1
program->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_TEX_COORD2); // attribute vec2 a_texCoord2
program->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_TEX_COORD3); // attribute vec2 a_texCoord3
program->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_NORMAL); // attribute vec3 a_normal
program->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_BLEND_WEIGHT); // attribute vec4 a_blendWeight
program->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_BLEND_INDEX); // attribute vec4 a_blendIndex
program->getVertexAttrib(GLProgram::ATTRIBUTE_NAME_TANGENT); // attribute vec3 a_tangent
program->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内置uniform
program->getUniformLocation(GLProgram::UNIFORM_NAME_AMBIENT_COLOR); // uniform vec4 CC_AmbientColor
program->getUniformLocation(GLProgram::UNIFORM_NAME_P_MATRIX); // uniform mat4 CC_PMatrix
program->getUniformLocation(GLProgram::UNIFORM_NAME_MULTIVIEW_P_MATRIX); // uniform mat4 CC_MultiViewPMatrix[4]
program->getUniformLocation(GLProgram::UNIFORM_NAME_MV_MATRIX); // uniform mat4 CC_MVMatrix
program->getUniformLocation(GLProgram::UNIFORM_NAME_MVP_MATRIX); // uniform mat4 CC_MVPMatrix
program->getUniformLocation(GLProgram::UNIFORM_NAME_MULTIVIEW_MVP_MATRIX); // uniform mat4 CC_MultiViewMVPMatrix[4]
program->getUniformLocation(GLProgram::UNIFORM_NAME_NORMAL_MATRIX); // uniform mat3 CC_NormalMatrix
program->getUniformLocation(GLProgram::UNIFORM_NAME_TIME); // uniform vec4 CC_Time
program->getUniformLocation(GLProgram::UNIFORM_NAME_SIN_TIME); // uniform vec4 CC_SinTime
program->getUniformLocation(GLProgram::UNIFORM_NAME_COS_TIME); // uniform vec4 CC_CosTime
program->getUniformLocation(GLProgram::UNIFORM_NAME_RANDOM01); // uniform vec4 CC_Random01
program->getUniformLocation(GLProgram::UNIFORM_NAME_SAMPLER0); // uniform sampler2D CC_Texture0
program->getUniformLocation(GLProgram::UNIFORM_NAME_SAMPLER1); // uniform sampler2D CC_Texture1
program->getUniformLocation(GLProgram::UNIFORM_NAME_SAMPLER2); // uniform sampler2D CC_Texture2
program->getUniformLocation(GLProgram::UNIFORM_NAME_SAMPLER3); // uniform sampler2D CC_Texture3
program->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 = i1
void 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[] shit
void setUniformLocationWith2iv( GLint location, GLint* ints, unsigned int numberOfArrays);
// uniform ivec3[] shit
void setUniformLocationWith3iv(GLint location, GLint* ints, unsigned int numberOfArrays);
// uniform ivec4[] shit
void setUniformLocationWith4iv(GLint location, GLint* ints, unsigned int numberOfArrays);
// uniform float shit
void setUniformLocationWith1f(GLint location, GLfloat f1);
// uniform vec2 shit
void setUniformLocationWith2f(GLint location, GLfloat f1, GLfloat f2);
// uniform vec3 shit
void setUniformLocationWith3f(GLint location, GLfloat f1, GLfloat f2, GLfloat f3);
// uniform vec4 shit
void setUniformLocationWith4f(GLint location, GLfloat f1, GLfloat f2, GLfloat f3, GLfloat f4);
// uniform float[] shit
void setUniformLocationWith1fv(GLint location, const GLfloat* floats, unsigned int numberOfArrays);
// uniform vec2[] shit
void setUniformLocationWith2fv(GLint location, const GLfloat* floats, unsigned int numberOfArrays);
// uniform vec3[] shit
void setUniformLocationWith3fv(GLint location, const GLfloat* floats, unsigned int numberOfArrays);
// uniform vec4[] shit
void setUniformLocationWith4fv(GLint location, const GLfloat* floats, unsigned int numberOfArrays);
// uniform mat2[] shit
void setUniformLocationWithMatrix2fv(GLint location, const GLfloat* matrixArray, unsigned int numberOfMatrices);
// uniform mat3[] shit
void setUniformLocationWithMatrix3fv(GLint location, const GLfloat* matrixArray, unsigned int numberOfMatrices);
// uniform mat4[] shit
void setUniformLocationWithMatrix4fv(GLint location, const GLfloat* matrixArray, unsigned int numberOfMatrices);
void setUniformsForBuiltins(const Mat4 &modelView); // 更新内置uniforms的值
void setUniformsForBuiltins(); // modelView是当前栈顶的MV
}