upload struct array to uniform block array?

Hi,

ok to make it short this is what I want to do:

  1. I have an array of structs on client side (c++):
struct LightSource
{
  float Position[3];
  float Ambient[4];
  float Diffuse[4];
  float Specular[4];
};

LightSource LightSources[12];
  1. I want to upload this array as fast as possible
    to a similar uniform array structure in the shader.

What is the best way to do this? Will these uniform buffer
objects do the trick? Something like this:

layout(std140) uniform LightSourceBlock
{
  vec3 Position;
  vec4 Ambient;
  vec4 Diffuse;
  vec4 Specular;
} LightSources[12];

So that I can use glBufferData to upload the whole
stuff with a single API call? What about the byte alignment/
padding of the client struct. I guess there are some things
that could go wrong?

Or should I use separate uniform arrays for the light source
components and then call glUniformXfv for each array?

Your opinions are really welcome!
If you think UBOs can do this job maybe you could also
share some code snippets for the use with array (I already
know the code examples for uploading a single uniform block).

Thank you! :slight_smile:

Uniform block arrays is an OpenGL 4.0 feature… I don’t see why it could not be a OpenGL 3.X feature but well… that’s how it is right now.

You need to query the index of each array element and then set each index to the buffer using glUniformBlockBinding… it’s quite cucumbersome but that’s how it is :stuck_out_tongue:


UniformArray[i] = glGetUniformBlockIndex(ProgramName, stringarray("Array", i));
glUniformBlockBinding(ProgramName, UniformArray[i], BUFFER_ARRAY_BINDING);
glBindBufferBase(GL_UNIFORM_BUFFER, BUFFER_ARRAY_BINDING, BufferName);

I’m pretty sure you can do this in your shader:

struct LightSource
{
  vec3 Position;
  vec4 Ambient;
  vec4 Diffuse;
  vec4 Specular;
};

layout(std140) uniform LightSourceBlock
{
  LightSource LightSources[12];
};

… and then just upload the entire array as a single UBO bound to LightSourceBlock.

Keep in mind that you will probably need to pad the “Position” field of your C++ struct to 4 floats when using std140. Also keep in mind that your compiler is free to layout (and pad) the struct as it pleases, so be careful about just assuming the layout matches std140. It may not.

Ok thank you guys I’ll experiment a
little bit and try wien’s example :slight_smile:

Or maybe I just use glUniformXfv…

Just tried to query the block index with a simple float
member but get UniformBlockIndex == GL_INVALID_INDEX.

GLuint UniformBlockIndex = glGetUniformBlockIndex(m_handle, "LightSourceBlock");
#version 150 core
#extension GL_ARB_uniform_buffer_object : enable

layout(std140) uniform LightSourceBlock
{
  float test;
};

out vec4 out_Color;

void main(void)
{
  out_Color = vec4(1.0, 0.0, 0.0, 1.0);
}

Have I missed something? :confused: Shader compiled, linked
and validated without errors. Just the index query failed.
I tried to query the index after activating the shader
via glUseProgram(m_handle) and also tried it directly
after linking. In both cases no luck =/

Ok the reason for GL_INVALID_INDEX was that LightSourceBlock
was not used in any operation in the sample shader thus the
uniform was removed during compilation/optimization.