6
\$\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\$ Commented May 14, 2014 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
    Commented May 14, 2014 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\$ Commented May 14, 2014 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
    Commented May 14, 2014 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
    Commented May 14, 2014 at 12:03

1 Answer 1

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
    Commented May 14, 2014 at 12:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .