简介
Uniform是一种从CPU中的应用向GPU中的着色器发送数据的方式,但uniform和顶点属性有些不同。
首先,uniform是全局的(Global)。全局意味着uniform变量必须在每个着色器程序对象中都是独一无二的,而且它可以被着色器程序的任意着色器在任意阶段访问。
第二,无论你把uniform值设置成什么,uniform会一直保存它们的数据,直到它们被重置或更新。
单独统一变量
声明
uniform vec3 color
赋值
//获取指定统一变量的location
int vertexColorLocation = glGetUniformLocation(_program, "test");
//为vec3 的统一变量 赋值
glUniform3f(vertexColorLocation, 0.0f, 1.0f, 0.0f);
赋值函数是根据 统一变量类型的不同而调整的.其中函数名中包含数字(1、2、3、4)表示接受这个数字个用于更改uniform变量的值,i表示32位整形,f表示32位浮点型,ub表示8位无符号byte,ui表示32位无符号整形,v表示接受相应的指针类型(或者就是传入的是数组)。
glUniform1f(GLint locaation,GLFloat x)
表示 float类型
glUniform2f(GLint locaation,GLFloat x,GLFloat y)
表示 二位向量 分量类型为float
glUniform1fv(GLint locaation,GLSize count,const GLfloat* value)
float类型指针
glUniformMatrix4x3(Glint location,GLsizei count,GLboolean transpose,const GLfloat* value)
表示为 4x3矩阵. 参数: transpose 表示是否采用 行优先顺序(GL_TRUE)
UBO
UBO(Uniform Buffer Object)是用来存储着色语言中Uniform类型变量的缓冲区对象,使用UBO可以让uniform变量在不同的着色语言程序中实现共用,也可以在着色语言程序中实现uniform类型变量的设置与更新。
提到UBO就必须要提到着色语言GLSL中的Uniform Blocks,它将众多的Uniform类型的变量集中在一起进行统一的管理,对于需要大量Uniform类型变量的程序可以显著地提高性能。(有点像全局版的VBO)
原理
在显存中创建缓存对象(Buffer),在buffer中存储统一变量数据, 将Buffer与 指定的point绑定, 将统一变量缓冲区的索引 和 point绑定. 这样通过point 将变量 和 缓存 连接.
设置UBO
//统一变量块
layout (std140) uniform colorBlock{
vec4 cc;
};
GLuint blockid,bufferid;
GLint blocksize;
GLint point = 1;
// 统一变量数据
GLfloat blockData[] = {
1.0f,1.0f,1.0f,1.0f
};
//获取统一变量块索引
blockid = glGetUniformBlockIndex(_program, "colorBlock");
//获取统一变量块大小
glGetActiveUniformBlockiv(_program, blockid, GL_UNIFORM_BLOCK_DATA_SIZE, &blocksize);
//将变量索引 和 point 绑定
glUniformBlockBinding(_program, blockid, point);
//创建与绑定缓冲区
glGenBuffers(1, &bufferid);
glBindBuffer(GL_UNIFORM_BUFFER, bufferid);
//向缓冲区中赋值
glBufferData(GL_UNIFORM_BUFFER, blocksize, blockData, GL_DYNAMIC_DRAW);
//将UBO 和 point 绑定
glBindBufferBase(GL_UNIFORM_BUFFER, point, bufferid);
修改UBO
GLfloat uploadData[] = {
0.0f,0.0f,1.0f,1.0f
};
// 绑定当然统一变量块的 buffer
glBindBuffer(GL_UNIFORM_BUFFER, bufferid);
//获取统一变量块 中 指定变量的 偏移量
const GLchar *names[] = {"cc"};
GLuint indices[1];
glGetUniformIndices(_program, 1, names, indices);
GLint offset[1];
glGetActiveUniformsiv(_program, 1, indices, GL_UNIFORM_OFFSET, offset);
glBufferSubData(GL_UNIFORM_BUFFER, offset[0], blocksize, uploadData);
函数补充
1, glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar* const *uniformNames, GLuint* uniformIndices)
该函数用于获取统一变量块中 变量们的索引 参数:
program 程序对象
uniformCount 变量名称数组的元素数量
uniformNames 变量名称数组
uniformIndices 用于接受变量索引的数组
2,glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params)
该函数用于 通过变量索引 查询变量信息. 参数:
program 程序对象
uniformCount 变量数量
uniformIndices 变量索引数组
pname 表示要查询变量的那个属性 GL_UNIFORM_OFFSET(变量偏移量) GL_UNIFORM_SIZE(变量大小) GL_UNIFORM_NAME_LENGTH(变量名长度) GL_UNIFORM_TYPE(变量类型)....
params 接受查询结果的数组
注意
着色语言编译优化
如果你声明了一个uniform却在GLSL代码中没用过,编译器会静默移除这个变量,导致最后编译出的版本中并不会包含它.
UBO限定符
在UBO中,针对不同的限定符 还存在不同的字节补齐的情况.所以获取偏移量,大小最好还是通过查询进行,避免自己计算出现错误.
这是 std140(标准统一变量块布局)限定符的内存分配情况: