1
votes

I´m trying to implement a Uniform Block.

This is how the block looks like in my fragment shader:

struct Light {
    uint LightType;
    vec3 Direction;
    float SpotBlur;
    vec3 AmbientColor;
    float LinearAttenuation;
    vec3 DiffuseColor;
    float QuadraticAttenuation;
    vec3 SpecularColor;
    float CubicAttenuation;
    vec3 Position;
    float SpotCutoff;
};

layout(std140) uniform LightBlock
{
    Light values;
} lights[32];

As you can see, I defined an array of the Light struct with a fixed size of 32. I can upload the data without any problems but now comes what I dont understand. If the "lights" array has a relatively small size (something around 6) all of my shader uniforms are found. but when increasing the "lights" size then it begins to kinda override my uniforms. For example it could not find my "modelViewProjection" matrix from the vertex shader anymore (returned -1 as the uniform location).

1
I'm not sure what you are trying to achieve, but if you want to back the LightBlock with a uniform buffer, shouldn't the [32] belong to values instead of lights? At the moment you define 32 blocks, not a block with 32 entries.BDL
@bitQuake: Please stop using vec3 in interface blocks. Your layout in particular is really bad, since after every float/int, there is 12 bytes of padding (vec3 is aligned to 16 bytes).Nicol Bolas

1 Answers

1
votes

The Problem

OpenGL limits the size of uniform arrays by MAX_VERTEX_UNIFORM_COMPONENTS_ARB. From what I have seen, this is usually set to 2048 or 4096, thus a 512 or 1024 byte limit respectively. (It is dependent up on the graphics hardware)
One Light object currently uses 84 Bytes of data.
The issue is when you create an array of 32 of these objects that uses up 2688 Bytes of data.
The reason a size of 6 works is because 84*6 is 504 which is < 512.

The Fix

Unfortunately, from my research, it appears that this limit is imposed by hardware and there is no way to change it unless you switch to a graphics card that has a different limit (or possibly change the OpenGL implementation by creating a custom graphics driver). The simplest way to fix your issue is to decrease the size of your lights array or decrease the size of your light object (or a combination of both).

Edit: Thank you BDL For the excellent suggestion of using UBOs or SSBOs. He is correct that these will allow you to pass larger uniforms. I have also edited my answer to reflect the true definition of MAX_VERTEX_UNIFORM_COMPONENTS.

@bitQUAKE came up with a workaround that uses a different size limit:
Check in the comments below for his solution. Here is a relevant discussion on the topic.