Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

 
Advanced search

1075932 Posts in 44152 Topics- by 36119 Members - Latest Member: Royalhandstudios

December 29, 2014, 04:14:43 PM
TIGSource ForumsDeveloperTechnical (Moderators: Glaiel-Gamer, ThemsAllTook)GLSL variable index for array?
Pages: [1]
Print
Author Topic: GLSL variable index for array?  (Read 1927 times)
Ethan_Hall
Level 0
**


View Profile Email
« on: September 11, 2013, 02:10:44 PM »

Hey all,

So I have an array of 50 light structs in my C++ program, which look like this:

Code:
basic_light
{
  basic_color color;
  2D_point position;
  float radius;
  int active;
};

And I am uploading them to a fragment shader using a Uniform Buffer Object. The Uniform Block Interface looks like this:

Code:
layout(std140) uniform LightArrayBlock
{
  basic_light lightElements[50];
}

With structs on the fragment shader that look like this:

Code:
basic_light
{
  vec4 color;
  vec2 position;
  float radius;
  int active;
};

And I'm using a loop to access all of my lights in the fragment shader:

Code:
for(int i = 0; i < 50; ++i)
{
  //somehow access lightElements[i]
}

So... things are screwing up here. The lights can't be accessed regularly using this loop. However, I noticed that I can access any element just by using a constant:


Code:
//this all works fine
lightElements[13]
lightElements[27]
lightElements[46]

I've seen some stack overflow posts asking about this same problem, but I haven't seen any kind of workaround that doesn't look really sucky. Anyone here know how I might fix this?

Thanks for any comments or advice!
Logged
JakobProgsch
Level 1
*



View Profile Email
« Reply #1 on: September 11, 2013, 03:21:13 PM »

I think this was a hardware dependent thing. Not all hardware is able to dynamically index uniforms... (or use dynamic flow control such as breaks etc.). There is also a chance that a lower array/loop size will work since it can unroll the loop etc. Alternatives are stuff like manually unrolling with lots of ifs or pulling the data from other places such as texture buffers.

Also just to cover all bases in case your "50" in the loop there isn't actually a constant in the shader but another uniform that might be also an issue. For similar reasons (no dynamic branching).
Logged

Ethan_Hall
Level 0
**


View Profile Email
« Reply #2 on: September 12, 2013, 06:35:15 PM »

Also just to cover all bases in case your "50" in the loop there isn't actually a constant in the shader but another uniform that might be also an issue. For similar reasons (no dynamic branching).

That isn't it; the array size is constant.

I did end up lowering the number of lights in the array to 5. Of the 5, only the first three lights work when using a dynamic index. The other two lights only work with a constant index. For reference, here is my fragment shader implementation:

Code:
#version 330

struct light
{
vec4 color;
vec2 position;
float radius;
int active;
};


in vec4 colorIn;
out vec4 outputColor;


layout(std140) uniform LightArrayBlock
{
light lightElement[5];
};

uniform vec4 ambientLightIntensity;

void main(void)
{
outputColor = colorIn * ambientLightIntensity;

for(int i = 0; i < 5; ++i)
{

float xFact = lightElement[i].position.x - gl_FragCoord.x;
float yFact = lightElement[i].position.y - gl_FragCoord.y;

float distance = sqrt((xFact*xFact) + (yFact*yFact));
float attenValue = lightElement[i].radius/( 1 + distance + (0.02*distance*distance) );

//apply the actual color of the light
vec4 attenColor = lightElement[i].color * vec4(attenValue, attenValue,attenValue, 1.0);

//Augment the color, IF the light is active
outputColor += (lightElement[i].active * attenColor);
}

//HACK FOR THE FOURTH LIGHT TO WORK
float xF = lightElement[3].position.x - gl_FragCoord.x;
float yF = lightElement[3].position.y - gl_FragCoord.y;

float d = sqrt((xF*xF) + (yF*yF));
float aValue = lightElement[3].radius/( 1 + d + (0.02*d*d) );

//apply the actual color of the light
vec4 aColor = lightElement[3].color * vec4(aValue, aValue,aValue, 1.0);

//Augment the color, IF the light is active
outputColor += (lightElement[3].active * aColor);
}

Is it really implementation dependent? It seems like, if the first three lights work fine, then the last two not working is some other problem, right? If I couldn't use dynamic indexing, wouldn't all of the lights fail? This is incredibly frustrating...
Logged
Ludophonic
Level 2
**


View Profile WWW
« Reply #3 on: September 12, 2013, 10:42:13 PM »

What's the output from glGetShaderInfoLog post-compile / post-link ?

(I quickly tried to compile the shader you posted myself but it complained that active was a reserved word)
« Last Edit: September 12, 2013, 10:52:48 PM by Ludophonic » Logged
Ethan_Hall
Level 0
**


View Profile Email
« Reply #4 on: September 12, 2013, 11:34:16 PM »

"No errors" for both compiling and linking, though the compilation warned me about appending "f" or "F" to my float values wouldn't work in pre-110 GLSL. I also changed the member of my light struct to be "act" instead of "active", but to no avail. I can only access the 4th and 5th lights using constants.
Logged
Daid
Level 1
*



View Profile
« Reply #5 on: September 13, 2013, 01:36:32 AM »

 Blink Could be a bug in the shader compiler, which I think is located in the 3D card driver. I personally would compile 1 shader for each "option", one for each amount of light sources. I also have an old laptop with an older 3D card, which is good to test for problematic shaders. Also gives you fallback shaders, if 5 lights does not work you can use the 4 lights shader or less.

I am seeing a small bug annoying here:
Code:
float attenValue = lightElement[i].radius/( 1 + distance + (0.02*distance*distance) );
Should be:
Code:
float attenValue = lightElement[i].radius/( 1.0 + distance + (0.02*distance*distance) );

I do not know exactly which drivers require constants as clear floats, but I know for sure this is an issue on a Mac's.
Logged

Ethan_Hall
Level 0
**


View Profile Email
« Reply #6 on: September 13, 2013, 03:19:33 PM »

Blink Could be a bug in the shader compiler, which I think is located in the 3D card driver. I personally would compile 1 shader for each "option", one for each amount of light sources... if 5 lights does not work you can use the 4 lights shader or less.

But that presents another problem: I can get 3 lights to work if I am using an array of size 5. But if I use an array of size 3, only 2 of the lights work using dynamic indexing! I could just use constants to index the array, but I absolutely don't want to resort to that.

I feel like giving up and just using a texture buffer/array/whatever instead of a uniform buffer; why even use the stupid buffer if I can't loop through the data? That's like telling me I can't breathe air!

I really wish it was some asinine thing I'm doing wrong instead of a hardware issue...
Logged
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic