Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple GLSL uniform buffers

Tags:

c++

opengl

glsl

I am having a problem when using multiple uniform buffers.

Here is my GLSL code:

layout(std140) uniform MaterialInfo {
    vec3 Ka;
    vec3 Ks;    
    vec3 Kd;
};


layout(std140) uniform LightInfo {
    vec3 La;
    vec3 Ls;
    vec3 Ld;
};

And this is how I create and fill my buffers:

    blockIndex = glGetUniformBlockIndex(program, "MaterialInfo");
    if (blockIndex == -1) {
        fprintf(stderr, "Could not bind uniform block\n");
    }
    glGenBuffers(1, &materialUbo);
    glBindBuffer(GL_UNIFORM_BUFFER, materialUbo);
    glBufferData(GL_UNIFORM_BUFFER, sizeof(MaterialBlock), &mesh->material, GL_DYNAMIC_DRAW);
    glBindBufferBase(GL_UNIFORM_BUFFER, blockIndex, materialUbo);


    blockIndex = glGetUniformBlockIndex(program, "LightInfo");
    if (blockIndex == -1) {
        fprintf(stderr, "Could not bind uniform block\n");
    }
    glGenBuffers(1, &lightUbo);
    glBindBuffer(GL_UNIFORM_BUFFER, lightUbo);
    glBufferData(GL_UNIFORM_BUFFER, sizeof(LightBlock), &light->lightBlock, GL_DYNAMIC_DRAW);
    glBindBufferBase(GL_UNIFORM_BUFFER, blockIndex, lightUbo);

When the structures are defines as following:

struct LightBlock { 
    glm::vec4 La;
    glm::vec4 Ld;
    glm::vec4 Ls;
};

struct MaterialBlock {
    glm::vec4 Ka;
    glm::vec4 Ks;
    glm::vec4 Kd;
};

This code works fine if I only use one uniform buffer. That is the MaterialInfo. If I include the second buffer for lightInfo I get a crash when I get to glDrawElements() later in the rendering.

Is there a problem using multiple uniform buffers like this? Can I make it into 1 UBO?

like image 358
toeplitz Avatar asked Oct 05 '12 12:10

toeplitz


2 Answers

glGetUniformBlockIndex doesn't work that way. It retrieves a number that identifies that particular uniform block. It is not a uniform buffer binding index to be passed to glBindBufferRange/Base.

UBO binding works a lot like texture binding. You tell the program what slot to look in. With textures, you get the uniform location to the texture, then set the value of that uniform to the texture unit index. With UBOs, you get the block index for the block, the set the binding value of that block index to the uniform buffer binding point where it will look.

So you should take the index from glGetUniformBlockIndex and use glUniformBlockBinding to assign to it a buffer binding point. Then bind your buffer to the binding point you assigned to the uniform block.

like image 63
Nicol Bolas Avatar answered Sep 19 '22 17:09

Nicol Bolas


Just to expand on Nicol's answer. Most of the samples conflate assignment and usage, and they hard code the usage slot so that there's only one buffer supported, it's really confusing, just lost a day to it myself.

Setup on shader initialization:

    m_ubo_transform_block_index = glGetUniformBlockIndex(m_gl_program_object, "transform_uniforms");
    if (m_ubo_transform_block_index != -1)
    {
        glUniformBlockBinding(m_gl_program_object, m_ubo_transform_block_index, UBO_TRANSFORM_INDEX);
    }

UBO_TRANSFORM_INDEX is a slot just like a texture unit might be.

Usage at draw time:

        if(m_ubo_transform_block_index != -1)
        {
            glBindBufferBase(GL_UNIFORM_BUFFER, UBO_TRANSFORM_INDEX, uniform_buffer->m_uniform_transform_buffer_object);
        }
like image 25
Gedalia Avatar answered Sep 19 '22 17:09

Gedalia