5
\$\begingroup\$

I have managed to get uniform blocks to work, but I seem to make something wrong when trying to setup an array of uniform blocks.

Assume this glsl:

layout(std140, binding=1) uniform LightingBlock
{
    vec4 ambient;
    vec4 diffuse;
    vec4 specular;
    vec3 factors;
    float shininess;
} lighting[3];

What's the exact procedure to bind this? What I am doing (and what works for a single block, not an array):

GenBuffer...
BindBuffer...
BindBufferRange(UNIFORM_BUFFER, 1, buffer_id, 0, size_in_bytes)
index = GetProgramResourceIndex(program_id, UNIFORM_BLOCK, "LightingBlock")
UniformBlockBinding(program_id, index, 1);

I read that I should replace the LightningBlock with lighting[0], [1] etc, but this only returns invalid indices. So my current attempt looks like this:

GenBuffer...
BindBuffer...
binding = 1
for(int i = 0; i < 3; ++i)
{
    BindBufferRange(UNIFORM_BUFFER, binding + i, buffer_id, 0, size_in_bytes)
    index = GetProgramResourceIndex(program_id, UNIFORM_BLOCK, "lighting[" + str(i) + "]")
    UniformBlockBinding(program_id, index, binding+i);
}

What am I doing wrong? How to do this correctly?

\$\endgroup\$
7
  • \$\begingroup\$ For one thing, it is improperly aligned. You need to swap shininess and factors. Also, why not use an array of structs rather than 3 separate uniform buffers? \$\endgroup\$ May 14 '14 at 11:35
  • \$\begingroup\$ I do use a single uniform buffer (at least I'm trying to). I need this uniform buffer to map to an array in glsl. In the lower code fragment, I am only calling GenBuffer once. \$\endgroup\$
    – Wilbert
    May 14 '14 at 11:55
  • \$\begingroup\$ What I meant was, why not create a struct with ambient, diffuse, specular, factors, shininess and declare an array of this struct with size 3 in your uniform block. The data structure is correctly aligned to allow this, and it would actually simplify a lot of your code. \$\endgroup\$ May 14 '14 at 11:58
  • \$\begingroup\$ Look at the glsl. That's exactly what I am trying to do. But I fail at mapping this properly to ranges in the uniform buffer - I only ever get the data for the first, and zeroes. \$\endgroup\$
    – Wilbert
    May 14 '14 at 12:02
  • \$\begingroup\$ Although I just saw in a post it might be related to offsets, that my offset is too small. \$\endgroup\$
    – Wilbert
    May 14 '14 at 12:03
3
\$\begingroup\$

As-per comments, an array of 3 structs in a Uniform Block would look like this:

struct Lighting {
  vec4 ambient;
  vec4 diffuse;
  vec4 specular;
  vec3 factors;
  float shininess;
};

layout(std140, binding=1) uniform LightingBlock {
  Lighting lights [3];
};

Now, your uniform buffer would be a contiguous array of data using the same general structure as in GLSL.

This is why alignment is important, for std140, an array of structs must have a size that is a multiple of vec4 in length or GL adds padding. Having you swap factors and shininess originally avoids 3*sizeof (float) worth of alignment padding GL would otherwise have added.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ This solution is great. I since found out that UNIFORM_BLOCK_OFFSET_ALIGNMENT is 256 bytes, which means my originally intended way of doing things would waste even more space, namely 192 bytes for each 64 bytes block. Thanks! \$\endgroup\$
    – Wilbert
    May 14 '14 at 12:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.