统一缓冲区对象(Uniform Buffer Object)
以前的使用统一值,实际是默认的块中。
着色器代码如下:
uniform TransformBlock
{
float scale;
vec3 translation;
float rotation[3];
mat4 projection_matrix; // 投影矩阵
} Transform;
Uniform 名为TransformBlock, 实例为Transform
一般使用 glBufferData / glMapBuffer 缓冲区对象进行数据填充。数据存储在缓冲区中有一般有方式二种:
1.共享布局(Shared layout)
- 缓冲区的数据由OpenGL根据运行性能以及着色器访问最佳的方式决定将数据放在缓冲区的位置。
- 当OpenGL在缓冲区中对数据进行排列时,这种排列在共用相同的统一块声明的多个程序和着色器之间相同的。也就是默认布局.
这种方式对程序开发人员来说,需要处理位置偏移量等,比较繁琐,此处略过。
2.标准布局(Standard Layout)
- 缓冲区的数据由OpenGL提供的一组为各种数据指定大小和排列的规则决定将数据放在缓冲区的位置
- 需使用布局限定符 std140
缓冲区的位置定义:在缓冲区占用N个字节的类型都会在这个缓冲区中的一个N个字节的分界处开始。
GLSL如下
layout(std140) uniform TransformBlock
{
float scale;
vec3 translation;
float rotation[3];
mat4 projection_matrix;
} transform;
标准布局实际分二步步骤:
- 统一块分配绑定点
GLuint glGetUniformBlockIndex(GLuint program, const GLChar* uniformBlockName); 返回指定统一块的索引
- 缓冲区绑定到绑定点上,从而匹配统一块.
void glUniformBlockBinding(GLuint program, GLuint unifromBlockIndex, GLuint uniformBlockBinding);
uniformBlockBinding 指统一块绑定点的索引
不同的缓冲区对象绑定不同的统一值
GLSL Shader 代码
layout(std140) uniform Harry
{
float a;
mat4 b;
};
layout(std140) uniform Bob
{
int c;
ivec4 d;
};
layout(std140) uniform Suan
{
mat4 e[10];
};
不同的缓冲区对象绑定不同的统一值
C++的代码:
// 使用glGetUniformBlockIndex 来得到统一块的索引
GLuint harry_index = glGetUniformBlockIndex(program, "Harry");
GLuint bob_index = glGetUniformBlockIndex(program, "Bob");
GLuint susan_index = glGetUniformBlockIndex(program, "Susan");
// 使用统一块的索引为它们分配缓冲区绑定
glUniformBlockBinding(program, harry_index, 1);
glUniformBlockBinding(program, bob_index, 3);
glUniformBlockBinding(program, susan_index, 0);
// 将缓冲区绑定到绑定点
glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer_b);
glBindBufferBase(GL_UNIFORM_BUFFER, 1, buffer_c);
glBindBufferBase(GL_UNIFORM_BUFFER, 3, buffer_a);
可以通过标准的约定,为所有的Program 设定绑定,即使切换program时,仍可使缓冲区绑定。
比如: 有一些相对固定的状态,如投影矩阵,视口大小等参数与Program不太相关的参数,我们可以将这个信息保留绑定到绑定点0上。然后,所有程序都在固定状态绑定设为0, b即使使用glUseProgram切换程序,这些统一值也会保留在缓冲区中备使用。