OpenGL统一变量 Uniform Variables
在OpenGL着色器编程中,uniform变量是一种特殊的全局变量,它们的作用是在图形渲染管线的不同阶段(如顶点着色器、片段着色器等)共享常量数据。uniform变量的值由CPU端的应用程序设置,并且在整个渲染调用过程中保持不变,这意味着所有在这个渲染批次中的顶点或片段都将使用同一组uniform变量的值。
特性与用途:
声明与类型: 在GLSL(OpenGL Shading Language)中,uniform变量通过关键字uniform进行声明,并指定其数据类型,例如矩阵、向量、标量或者结构体。例如:
uniform mat4 modelMatrix; // 用于存储模型变换矩阵
uniform vec3 lightPosition; // 存储光源位置
uniform float time; // 表示当前时间
生命周期与作用域:
生命周期:uniform变量的生命周期跨越整个渲染帧,在这一帧内它的值是恒定的。
作用域:一个uniform变量在被链接在一起的所有着色器阶段中都是可见的,如果顶点着色器和片段着色器都引用了同一个uniform变量,则它们将访问到相同的值。
赋值与更新: 应用程序需要使用OpenGL API函数来为uniform变量分配内存地址并设置其值。这些函数包括glGetUniformLocation获取uniform变量在着色器中的位置标识符,然后使用glUniform*系列函数(如glUniform1f, glUniform3fv, glUniformMatrix4fv等)来传递实际的数据。
性能优化:
当uniform变量数量较多时,可以利用Uniform Buffer Objects (UBOs)进行优化。UBOs允许将多个uniform变量打包到连续的缓冲区中,一次性上传至GPU,从而减少API调用开销。
另外,由于uniform变量的值对所有渲染的对象都相同,因此对于那些不随每个顶点变化而是影响整个场景的参数(如投影矩阵、视图矩阵、光照参数、纹理采样器状态等),uniform是最合适的传输方式。
限制: OpenGL对uniform变量的数量和大小有限制,这取决于硬件支持。超出限制会导致无法创建更多的uniform变量或无法设置更大的uniform数组。现代OpenGL版本和扩展通常提供了更大容量和更灵活的方式来管理uniform和其他常量数据。
总结来说,uniform变量在OpenGL中扮演着非常重要的角色,它允许应用程序灵活地控制着色器的行为而不必修改和重新编译着色器代码,使得开发者能够实时调整渲染效果,比如变换、光照条件等。
活动(Active)的 uniform
在OpenGL着色器编程中,当提到“活动的uniform”时,它是指那些在当前链接的着色器程序中被实际使用的uniform变量。每个uniform变量在GLSL(OpenGL着色语言)源代码中都有一个声明,但在编译并链接成最终着色器程序后,并非所有声明的uniform都会被认为是“活跃”的。
活跃的uniform是指在任何片段着色器、顶点着色器或其他类型的着色器阶段中有用到的uniform变量,这些变量的值可以由应用程序在运行时通过API函数设置,并传递给GPU以便在渲染过程中使用。例如,如果一个光照模型中的某个参数是通过uniform变量传入的,而这个参数在实际的着色计算中发挥了作用,那么这个uniform就是活跃的。
glGetActiveUniform函数就是为了查询这些在链接后的着色器程序中确实起作用的uniform变量的详细信息,包括其名称、类型、大小和数组元素的数量等。只有这些活跃的uniform需要应用程序关注并进行相应的数据上传。
int glGetUniformLocation( uint program, const char *name );
void glGetActiveUniformName( uint program, uint uniformIndex, sizei bufSize, sizei *length, char *uniformName );
void glGetUniformIndices( uint program, sizei uniformCount, const char * const *uniformNames, uint *uniformIndices );
void glGetActiveUniform( uint program, uint index, sizei bufSize, sizei *length, int *size, enum *type, char *name );
void glGetActiveUniformsiv( uint program, sizei uniformCount, const uint *uniformIndices, enum pname, int *params );
uint glGetUniformBlockIndex( uint program, const char *uniformBlockName );
void glGetActiveUniformBlockName( uint program, uint uniformBlockIndex, sizei bufSize, sizei length, char *uniformBlockName );
void glGetActiveUniformBlockiv( uint program, uint uniformBlockIndex, enum pname, int *params );
void glGetActiveAtomicCounterBufferiv( uint program, uint bufferIndex, enum pname, int *params );
获取uniform变量的位置标识符
int glGetUniformLocation( uint program, const char *name );
// is equivalent to
glGetProgramResourceLocation(program, UNIFORM, name);
如果没有找到匹配的uniform返回-1。
获取程序中活动uniform变量的名称
void glGetActiveUniformName( uint program, uint uniformIndex, sizei bufSize, sizei *length, char *uniformName );
// is equivalent to
glGetProgramResourceName(program, UNIFORM, uniformIndex, bufSize, length, uniformName);
参数说明:
program:一个有效的OpenGL着色器程序对象ID。
uniformIndex:要查询的uniform变量的索引,这个索引是从0开始,按照在着色器程序中定义的顺序排列的。
bufSize:传递给uniformName缓冲区的大小(以字符计),包括结束符\0的空间。
length:可选指针,用于接收实际写入uniformName缓冲区的字符数,不包括结束符。
uniformName:指向一个足够大的缓冲区,用来存储返回的uniform变量名。
获取着色器程序中活动 uniform 变量名称的最大长度 glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
用于获取着色器程序中指定uniform变量的统一索引(Uniform Indices)
void glGetUniformIndices( uint program, sizei uniformCount, const char * const *uniformNames, uint *uniformIndices );
// is equivalent (assuming no errors are generated) to:
for (int i = 0; i < uniformCount; i++) {
uniformIndices[i] = glGetProgramResourceIndex(program, UNIFORM, uniformNames[i]);
}
参数说明:
program:要查询的着色器程序对象的标识符。
uniformCount:要查询的uniform变量名称数组的长度。
uniformNames:一个字符串数组,包含要查询的uniform变量的名称。
uniformIndices:用于存储uniform变量索引的数组。
如果某个 uniform 变量名称不存在于着色器程序中,相应的索引将被设置为 GL_INVALID_INDEX。
这些索引可以用于后续调用如glGetActiveUniformsiv、glGetUniformIndices和glUniformBlockBinding等函数。在现代OpenGL编程中,特别是在使用 Uniform Buffer Objects (UBOs) 或 Shader Storage Buffers (SSBOs) 时,索引对于间接访问 uniform 变量非常有用。
查询活跃uniform的各种属性
void glGetActiveUniform( uint program, uint index, sizei bufSize, sizei *length, int *size, enum *type, char *name );
// is equivalent (assuming no errors are generated) to:
const enum props[] = {
ARRAY_SIZE, TYPE };
glGetProgramResourceName(program, UNIFORM, index, bufSize, length, name);
glGetProgramResourceiv(program, UNIFORM, index, 1, &props[0], 1, NULL, size);
glGetProgramResourceiv(program, UNIFORM, index, 1, &props[1], 1, NULL, (int *)type);
参数说明:
program 着色器程序对象的标识符。
index 活跃uniform变量的索引,在 0 到 glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &count) - 1 之间。
bufSize 参数指定了存储 uniform 名称的缓冲区大小。
length 参数返回实际的 uniform 名称的长度(不包括终止 null 字符)。
size 参数返回 uniform 数组中的元素数量(如果不是数组,则为 1)。
type 参数返回 uniform 变量的数据类型。
name 参数是一个指向存储 uniform 名称的缓冲区的指针。
GLuint program; // 要查询的着色器程序对象的标识符
GLint count;
glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &count); // 获取活动 uniform 变量数量
for (GLuint i = 0; i < count; ++i) {
GLsizei length;
GLint size;
GLenum type;
GLchar name[256]; // 假设 uniform 变量名称不超过 255 个字符
// 可以用这个查最大长度 GL_ACTIVE_UNIFORM_MAX_LENGTH
glGetActiveUniform(program, i, 256, &length, &size, &type, name); // 获取 uniform 变量信息
std::cout << "Uniform #" << i << ": " << name << ", Size: " << size << ", Type: " << type << std::endl;
}
获取一组特定的活动 uniform 变量的信息
void glGetActiveUniformsiv( uint program, sizei uniformCount, const uint *uniformIndices, enum pname, int