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?
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.
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With