最简单的 UBO(Uniform Buffer Object) 【OpenGL】【GLSL】
来源:互联网 发布:java开发平台结构图 编辑:程序博客网 时间:2024/06/10 22:55
一、引入 Uniform Buffer Object / Uniform Block 的 原因
1) 如果程序涉及了多个 Shader 程序,而且它们使用同一个Uniform变量,那么你就需要为每个 Shader 程序单独管理它们。当一个程序被链接时,OpenGL 会自动生成 Uniform 的位置,因此对于不同的 Shader 程序,同一个 Uniform 变量的位置可能是不一样的。而 Uniform Blocks 就是为了方便我们管理 Shader 之间共享的 Uniform 变量。
通过一个 Uniform Block 对象,我们可以创建一个缓冲区用于存储所有的 Uniform 变量,然后把这个缓冲区绑定到 Uniform bBock 上。这样,当我们需要改变使用的 Shader 程序时,只需要再重新把 Uniform Block 绑定到新的 Shader 程序就可以了。【摘自《【OpenGL】向Shader中传递数据》】
2)有多个相同的 Uniform 变量,需要统一管理
二、UBO 的优点
优化了 Uniform 变量的访问,使得 Uniform 变量在多个 Shader 程序之间共享成为可能
三、Uniform Block 布局控制
四、关键代码和注释
void startup() { GLuint vs, fs; static const char * vs_source[] = { "#version 410 core \n" " \n" "layout (location = 0) in int alien_index; \n" " \n" "out VS_OUT \n" "{ \n" " flat int alien; \n" " vec2 tc; \n" "} vs_out; \n" " \n" "struct droplet_t \n" "{ \n" " float x_offset; \n" " float y_offset; \n" " float orientation; \n" " float unused; \n" "}; \n" " \n" "layout (std140) uniform droplets \n"// Uniform Blocks: 方便我们统一管理uniform变量 "{ \n" " droplet_t droplet[256]; \n" "}; \n" " \n" "void main(void) \n" "{ \n" " const vec2[4] position = vec2[4](vec2(-0.5, -0.5), \n" " vec2( 0.5, -0.5), \n" " vec2(-0.5, 0.5), \n" " vec2( 0.5, 0.5)); \n" " vs_out.tc = position[gl_VertexID].xy + vec2(0.5); \n" " float co = cos(droplet[alien_index].orientation); \n" " float so = sin(droplet[alien_index].orientation); \n" " mat2 rot = mat2(vec2(co, so), \n" " vec2(-so, co)); \n" " vec2 pos = 0.25 * rot * position[gl_VertexID]; \n" " gl_Position = vec4(pos.x + droplet[alien_index].x_offset, \n" " pos.y + droplet[alien_index].y_offset, \n" " 0.5, 1.0); \n" " vs_out.alien = alien_index % 64; \n" "} \n" }; static const char * fs_source[] = { "#version 410 core \n" " \n" "layout (location = 0) out vec4 color; \n" " \n" "in VS_OUT \n" "{ \n" " flat int alien; \n" " vec2 tc; \n" "} fs_in; \n" " \n" "uniform sampler2DArray tex_aliens; \n" " \n" "void main(void) \n" "{ \n" " color = texture(tex_aliens, vec3(fs_in.tc, float(fs_in.alien))); \n" "} \n" }; char buffer[1024]; vs = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vs, 1, vs_source, NULL); glCompileShader(vs); glGetShaderInfoLog(vs, 1024, NULL, buffer); fs = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fs, 1, fs_source, NULL); glCompileShader(fs); glGetShaderInfoLog(vs, 1024, NULL, buffer); render_prog = glCreateProgram(); glAttachShader(render_prog, vs); glAttachShader(render_prog, fs); glLinkProgram(render_prog); glDeleteShader(vs); glDeleteShader(fs);// 创建并绑定 VAO,负责状态的保存 glGenVertexArrays(1, &render_vao); glBindVertexArray(render_vao); tex_alien_array = sb7::ktx::file::load("media/textures/aliens.ktx");// KTX 格式贴图 glBindTexture(GL_TEXTURE_2D_ARRAY, tex_alien_array); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);// 创建 UBO(Uniform Buffer Object) glGenBuffers(1, &rain_buffer); glBindBuffer(GL_UNIFORM_BUFFER, rain_buffer); glBufferData(GL_UNIFORM_BUFFER, 256 * sizeof(vmath::vec4), NULL, GL_DYNAMIC_DRAW); // 用于绘制,数据会频繁改动// 初始化位置和运动属性 for (int i = 0; i < 256; i++) { droplet_x_offset[i] = random_float() * 2.0f - 1.0f; droplet_rot_speed[i] = (random_float() + 0.5f) * ((i & 1) ? -3.0f : 3.0f); droplet_fall_speed[i] = random_float() + 0.2f; } glBindVertexArray(render_vao); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } void render(double currentTime) { static const GLfloat black[] = { 0.0f, 0.0f, 0.0f, 0.0f }; float t = (float)currentTime; glViewport(0, 0, info.windowWidth, info.windowHeight); glClearBufferfv(GL_COLOR, 0, black); glUseProgram(render_prog);// 绑定 UBO glBindBufferBase(GL_UNIFORM_BUFFER, 0, rain_buffer);// 映射 uniform blocks -- droplets (将GPU显存空间映射到CPU内存空间) vmath::vec4 * droplet = (vmath::vec4 *)glMapBufferRange(GL_UNIFORM_BUFFER, 0, 256 * sizeof(vmath::vec4), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); for (int i = 0; i < 256; i++) { droplet[i][0] = droplet_x_offset[i]; droplet[i][1] = 2.0f - fmodf((t + float(i)) * droplet_fall_speed[i], 4.31f); droplet[i][2] = t * droplet_rot_speed[i]; droplet[i][3] = 0.0f; }// 关闭映射 glUnmapBuffer(GL_UNIFORM_BUFFER); int alien_index; for (alien_index = 0; alien_index < 256; alien_index++) { glVertexAttribI1i(0, alien_index);// 传入顶点属性 —— alien_index glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } }
注:其他常用的 API
1) glGetUniformBlockIndex:得到 Uniform Block 变量的索引
2) glGetActiveUniformsiv:当指定 GL_UNIFORM_BLOCK_DATA_SIZE 参数时,可以查询 Block 空间的大小,便于我们为存储 Uniform Block 的缓冲区的数据分配空间
3) glGetUniformIndices:接受一个 Uniform Block 内变量名字的数组(第三个参数),然后返回这些变量在数据里的索引(第四个参数)
4) glGetActiveUniformsiv:当指定 GL_UNIFORM_OFFSET 参数时,通过 Uniform Block 内变量的索引得到 Block 不同变量的偏移量
五、效果图
- 最简单的 UBO(Uniform Buffer Object) 【OpenGL】【GLSL】
- OpenGL GLSL uniform variable
- Uniform Buffer Object
- Uniform Buffer Objects (UBO) using the std140 layout specification
- OpenGL学习: uniform blocks(UBO)在着色器中的使用
- 最简单的曲面细分着色器(Tesselation Shader)【OpenGL】【GLSL】
- 最简单的几何着色器(Geometry Shader)【OpenGL】【GLSL】
- 《OpenGL ES 2.0 Programming Guide》第8章 “最简单的Vertex Buffer Object”示例代码【C语言版】
- GLSL最简单的范例
- [OpenGL] 高级着色器应用之 统一缓冲区对象(Uniform Buffer Object)
- OpenGL深入探索——OpenGL/GLSL数据传递小记(3.x) 【包含UBO详解】
- GLSL(3)-在opengl中初始化Uniform Block 的流程-小结
- OpenGL Frame Buffer Object
- OpenGL Buffer Object
- OpenGL Frame Buffer Object
- vs2008中使用最简单的glsl
- OpenGL中RBO与Texture,UBO与SSBO的异同
- OpenGL Frame Buffer Object 101
- Java字符串format-用户号补齐格式化应用
- TCP UDP协议网络通讯
- 如何打jar包和运行jar包
- 【BZOJ4876】 [Zjoi2017]线段树
- Boost.Aiso教程 2
- 最简单的 UBO(Uniform Buffer Object) 【OpenGL】【GLSL】
- Mybatis 关联映射
- Hibernate_映射_关联关系_多对多映射1
- SpringMVC个人零碎总结
- Android Framework: Binder(1)-Android IPC
- bzoj 1692 [Usaco2007 Dec]队列变换
- springfox整合SpringMVC
- strcpy,strcat,strstr,strcmp,memmove的实现
- windows XP,2003,7,2008有效,无需更改他人administrator密码进入方法: