最简单的 UBO(Uniform Buffer Object) 【OpenGL】【GLSL】

版权声明:涉猎过的知识都像是不断汇入大海的涓涓细流,你怎么知道是哪条汇入的溪流让海洋成为海洋呢【转载请注明出处】 https://blog.csdn.net/panda1234lee/article/details/71326063


一、引入 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 布局控制


布局控制修饰符
shared Uniform Block 在多个 Shader 程序之间是共享的(默认布局修饰符)
packed 最小化内存的使用,通常禁用 Shader 程序之间的共享
std140 用于 Uniform Blocks 或 Shader Storage Buffer Blocks 的标准布局
std430 用于 Buffer Blocks 的标准布局
row_major 使得 Uniform Blocks 中的矩阵按行主序存储
coloum_major 使得 Uniform Blocks 中的矩阵按列主序存储(默认顺序)


四、关键代码和注释

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);
        }
    }


扫描二维码关注公众号,回复: 3643067 查看本文章

注:其他常用的 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 不同变量的偏移量

得到了各个变量的偏移量之后,就可以在客户端对 Buffer 进行数据填充了


五、效果图









猜你喜欢

转载自blog.csdn.net/panda1234lee/article/details/71326063