PDA

View Full Version : Multiple lights with gl_LightSource again



krazanmp
12-04-2005, 06:11 PM
I know that this has been asked MANY times before but there seems to never be any resolution on this topic.

Here goes:
Is there still a bug that won't allow a glsl writer to access the lighting values supplied as state to the opengl engine?? I.e. Is it possible to use the gl_LightSource uniforms directly? Basically I need to be able to access multiple light information like gl_LightSource[i].whatever and be able to iterate over the lights.
The problem I am encountering is that if I call gl_LightSource[i], I get a compile error on the script "array must be redeclared with a size before being indexed with a variable". Ok, now if I use hardcoded values and iterate over them myself (i.e. actually use 0, 1, ... 7 instead of i), for any value other than 0, the rendering freezes completely (i.e. The first frame seems to never render). There was some suggestion that it may be a bug in the Catalyst drivers (almost two years ago) causing this; does anybody know if this is the case?

Before you decide to write "Why don't you write your own lighting uniforms and just set it yourself?", Don't. I am dealing with many shaders; which I don't want to have to set all of the lighing information for all of them, just to use the lighting information I am already supplying (easily) to the OpenGL engine once before evaluating a single shader.

Is there someone at ATI that could comfirm whether this should work on a Radeon 9800 Pro (with Catalyst 5.11 drivers) or not.

// Mike

PsychoLns
12-05-2005, 09:46 AM
How do you iterate? It works just fine here - at least with the first 4 lights.

kingjosh
12-05-2005, 12:07 PM
The suggestion to declare your own uniforms is one of preference. Performance will generally be better, unless you're actually using all 12 elements of the gl_LightSource[i] struct. According to the OpenGL Shading Language Specification, the number of uniforms would be [num_scalars_in_struct] * gl_Max_Lights, if you're using hardware supporting 8 lights, this would look like:

29 * 8 = 232 scalar uniforms

I'm not sure, but this may be too many uniforms it seems a software fallback would be likely on a 9800. This is likely what you're seeing when you size the array and it appears to freeze. If you want it to run in real time on older hardware it may be a good idea to define the elements you're using and send them down yourself.

Granted, it would require more effort on your end but if your intention is real time or interactive shaders this may be your only option.

krazanmp
12-06-2005, 08:05 PM
Ok, I have an old shader that demonstrates the problem. (I know the actual lighting calculations are incorrect, but this was simply at test shader). If I change all the gl_LightSource[i] entries in the PointLight function, to gl_LightSource[0], everything works fine for one light (when I only call it once of course). If I leave the i in each entry, I get "ERROR: LineNumber: [ : array must be redeclared with a size before being indexed with a variable" on each line that uses the array index in PointLight.

This shader should produce 29*2 (lights) + 11*2 (Point light uniforms if unrolled completely) + 20 (in main) + 6 (globally defined) = 106 uniforms for this script to compile.

uniform sampler2D tex0;

varying vec3 Normal, EyeCoordsPosition;

void PointLight( in int i,
in vec3 lEyeCoordsPosition,
in vec3 lEyeCoordsNormal,
inout vec4 lAmbient,
inout vec4 lDiffuse,
inout vec4 lSpecular )
{
float SpecularPowerFactor = 0.0;
vec3 LightVector = normalize( gl_LightSource[i].position.xyz - lEyeCoordsPosition.xyz );

float NormalDotLightVector = max( 0.0, dot( lEyeCoordsNormal, LightVector ) );

if( NormalDotLightVector > 0.0 )
{
vec3 EyeVector = normalize( -lEyeCoordsPosition );
vec3 Reflection = normalize( -reflect( LightVector, lEyeCoordsNormal ) );
SpecularPowerFactor = pow( max( dot( Reflection, EyeVector ), 0.0 ), gl_FrontMaterial.shininess );
}

lAmbient += gl_LightSource[i].ambient;
lDiffuse += gl_LightSource[i].diffuse * NormalDotLightVector;
lSpecular += gl_LightSource[i].specular * SpecularPowerFactor;
}

void main( void )
{
vec4 Ambient = vec4( 0.0, 0.0, 0.0, 1.0 );
vec4 Diffuse = vec4( 0.0, 0.0, 0.0, 1.0 );
vec4 Specular = vec4( 0.0, 0.0, 0.0, 1.0 );

vec4 texture = texture2D( tex0, gl_TexCoord[0].xy );

{
PointLight( 0, EyeCoordsPosition, Normal, Ambient, Diffuse, Specular );
PointLight( 1, EyeCoordsPosition, Normal, Ambient, Diffuse, Specular );
}

vec4 LightContribution = Ambient * texture * gl_FrontMaterial.ambient +
Diffuse * gl_FrontMaterial.diffuse +
Specular * gl_FrontMaterial.specular;

gl_FragColor = LightContribution;
}

I agree, that it would be adventageous to strip everything unnecessary, but as you pointed out it would be more effort to specialize these scripts. Which I could find out that branching/looping is broken entirely for my vid. card. Something I don't currently want to do since I have dozens of scripts already set up in my app and compiled differently. It may eat a couple of days to change the shaders' binding to the game, and modification of the shader code themselves only to end up back here.

Also, I am looking to buy a new card in the near future and am trying to determine whether or not to stay with ATI because I have noticed many posts on this forum of guys having problems with developing on their ATI cards.

I am trying to determine what I could get away with on this hardware for now and whether it is worth it to try a different brand if it is inherently more developer-friendly.

That is why I am asking for you guys' experience with this. Some people say it works, others seem to be having the same problems as I am. If there is someone out there that has this HW and has it working, can they post a SIMPLE fragment shader that can be easily adapted to test with??

Thanks

// Mike

PsychoLns
12-07-2005, 01:40 AM
ok, that shader has problems with the known parser error ("array must be redeclared with a size before being indexed with a variable"). You have to "iterate" using ugly #defines or similar to have real hardcoded constants to the array.
And if you get software mode after that I'll suggerst you remove the if - it looks like one of those that make the ati compiler produce quite lenghty code. Remove the if and use something like:


SpecularPowerFactor = step(NormalDotLightVector, 0.) * pow( max( dot( Reflection, EyeVector ), 0.0 ), gl_FrontMaterial.shininess );