This is explained at http://ogldev.atspace.co.uk/www/tutorial20/tutorial20.html about halfway down the page.
I would've done a comment, but not enough rep :(
Edit: In order to make up for my bad answer, I have found the pertinent sections of the OpenGL 3.2 specification. I hope this helps.
When using the std140 storage layout, structures will be laid out in buffer
storage with its members stored in monotonically increasing order based on their
location in the declaration. A structure and each structure member have a base
offset and a base alignment, from which an aligned offset is computed by rounding
the base offset up to a multiple of the base alignment. The base offset of the first
member of a structure is taken from the aligned offset of the structure itself. The
base offset of all other structure members is derived by taking the offset of the
last basic machine unit consumed by the previous member and adding one. Each
structure member is stored in memory at its aligned offset. The members of a toplevel uniform block are laid out in buffer storage by treating the uniform block as
a structure with a base offset of zero.
If the member is a structure, the base alignment of the structure is N, where
N is the largest base alignment value of any of its members, and rounded
up to the base alignment of a vec4. The individual members of this substructure are then assigned offsets by applying this set of rules recursively,
where the base offset of the first member of the sub-structure is equal to the
aligned offset of the structure. The structure may have padding at the end;
the base offset of the member following the sub-structure is rounded up to
the next multiple of the base alignment of the structure.
If the member is an array of S structures, the S elements of the array are laid
out in order, according to rule (9) (the last paragraph).
Edit 2: It seems from the specification that arrays of structs are lined up directly next to each other in the buffer. So if you had 2 lights, the buffer data would just be the 20 floats defining that light, followed by the 20 floats defining the next light.
The reason it is that simple is because all of your struct members are the same type. If you had a vec2 in there, you would have to skip 2 floats in the buffer.
Edit 3: Sorry for all of these edits. I tested what I said in edit 2, and it indeed worked. I created a similar structure to yours in my shaders, but I used 3 vec4's for simplicity. I had an interface uniform containing an array of 2 of those structs. In my uniform buffer object I just placed 24 floats (4 floats per vec4 * 3 vec4 per struct * 2 structs) After binding the object I was able to read the correct values in the shader.
std140
layout works? Or what? – Nicol Bolas Feb 26 at 7:18std140
, but rather, how to pass data to a ubo struct - but I see what you mean, usingstd140
I just basically use the same c++ code to transfer the data as long as the layout is the same for the data in c++ and glsl...I think that's right. – Jarrett Feb 27 at 15:55