1
\$\begingroup\$

I'm trying to pass a point light from an array to a CalcLight function in a fragment shader. It works when I hard code in the value, but not when I use a loop. Here's the code:

#define TOTAL_LIGHTS 2
struct PLight
{
    vec4 pos;

    vec4 diff;
    vec4 spec;
    vec4 amb;

    float con;
    float lin;
    float quad;
};

layout(std140) uniform Light
{
    PLight pLights[TOTAL_LIGHTS];
}light;

vec3 CalcPoint(in PLight p) 
{
    ...
}

When I pass in the light from main using hard coded values it works fine.

void main()
{
    ...
    pointLight += CalcPoint(light.pLights[0]);
    pointLight += CalcPoint(light.pLights[1]);
    ...
}

But, when trying to use a loop, the first light works fine but not the second.

for(int i = 0; i < TOTAL_LIGHTS; i++)
    pointLight += CalcPoint(light.pLights[i]);

Any thoughts as to why the loop isn't working?

\$\endgroup\$
4
  • \$\begingroup\$ Have you tried it on different systems with cards from different vendors? Perhaps there's a bug in one of the vendors' compilers? \$\endgroup\$ Aug 15 '15 at 15:54
  • \$\begingroup\$ I've tried this on two different systems; similar problems on both. On the first, it works as said above when using hard coded values. On the second system, it breaks both when you try to loop through the lights, and it breaks when just adding the second light with a hard coded value. i.e. pointLight += ...[0]; works fine, but when I add pointLight += ...[1] I get nothing. But, using just pointLight += ...[1] it works fine as well. \$\endgroup\$ Aug 15 '15 at 17:25
  • 1
    \$\begingroup\$ How does it not work? Do you get a shader compilation error? Does your program run, but just doesn't behave as expected? \$\endgroup\$
    – aslg
    Aug 15 '15 at 17:25
  • \$\begingroup\$ Sorry for not being specific enough. The shader compiles fine, the program runs fine. The meshes that are rendered with other shaders still show up. But, every mesh rendered with the above lighting shader turns black when I try to add the second point light to my calculations. \$\endgroup\$ Aug 15 '15 at 17:52
2
\$\begingroup\$

That structure is not aligned correctly, which may be the source of your problem.

To form an array using std140 out of PLight, you need to pad it with an extra float at the end. Otherwise, PLight pLights[TOTAL_LIGHTS] is misaligned and you will fetch the wrong memory from pLights [1] -- everything will be off by 1 scalar component on the second light in this array of structures.

Consider this instead:

struct PLight
{
    vec4 pos;

    vec4 diff;
    vec4 spec;
    vec4 amb;

    float con;
    float lin;
    float quad;
    float padding;
};

The entire array size needs to be padded out to a multiple of the base-alignment for std140. Your base-alignment in this case is vec4 (4N). So that means to satisfy this alignment you need to add a float to the end. GLSL will do this for you automatically, and this float padding element is something you need to take care of when you declare this structure in code outside of the shader.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks for the reply Andon. The struct my code above is from my fragment shader. On the C++ side, I do have the padding you mention. Also, I've tried adding in the padding in the fragment shader too. I don't think this is an alignment problem because it works when accessing the array with constants. I think the problem is with dynamically indexing the array positions. \$\endgroup\$ Aug 17 '15 at 2:11
  • \$\begingroup\$ @mgoetschius: Ah, gotcha. The thing is, that's a const-index-expression It's not dynamic at all, the compiler could easily unroll this because the number of iterations is known at compile-time. \$\endgroup\$ Aug 17 '15 at 2:31
0
\$\begingroup\$

Non-constant indexing into uniform array can be tricky and depends on GLSL version. I think that what you are doing should be within spec (even for GLES 2.0), but it still might be problem. See for example what GLES 2.0 GLSL 1.0 spec says about indexing uniform array in fragmen shader:

Apendix A section 5

In the vertex shader, support for all forms of array indexing is mandated. In the fragment shader, support for indexing is only mandated for constant-index-expressions.

and

constant-index-expressions are a superset of constant-expressions. Constant-index-expressions can include loop indices as defined in Appendix A section 4.

On desktop it should be better, but still could cause problem, as you have to have specified const. array size (which you did).

I know this is not much helpful in solving problem, but may give some clue to what might be going on.

\$\endgroup\$

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.