SpotLight, attenuation factors and Backfaces

Hi,

I have a SpotLight with angle 40 degrees, SpotExponent 10 and ConstantAttenuation 0.01.

My scene consists of a simple Quad.

I see that not onlt the Front Face of the quad is illuminated, but also the backface, even if I set the

glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);

Shouldn’t it be dark?

You shouldn’t have any two sided lighting in the first place as it is turned off by default.

Ok,

but I set it to false just to be sure…
It seems that if I don’t set the attenuation factor it works fine…

[QUOTE=Devdept2;1240118]I see that not onlt the Front Face of the quad is illuminated, but also the backface, even if I set the

glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);

Shouldn’t it be dark?[/QUOTE]
If memory serves, LIGHT_MODEL_TWO_SIDE just flips the normal for the back side (for polygons where both sides represent the “outside” of the object).

Did you set the material ambient to 0,0,0,0, the material emission to 0,0,0,0. If not, your light-space back faces (on lit geometry) may not be black.

It seems that if I don’t set the attenuation factor it works fine…

The attenuation is not a problem here as it is only relevant if lighting calculattions are actually done.

Attenuation is a factor by which radiance (or luminance depending on your view) is decreasing as the source of light increases distance to the object it illuminates. This is because the solid angle the light source subtends as seen from the object being illuminated becomes smaller.

In physics, the attenuation factor is simply

1 / d^2

where d is the distance between sender and receiver.

In fixed-function OpenGL you have a sum of three factors defined as the sum of

1 / (A_constant + A_linear + A_quadratic)

which is physically completely inaccurate but serves the purpose of fine-controlling the appearance of lit geometry in the rendered image.

To make it physically correct you’d set A_constant and A_linear to 0. However, if you play around with the values a bit, you’ll notice that physical correctness and pleasant visual appearance aren’t necessarily the same. :slight_smile:

This is the illumination from the top

[ATTACH=CONFIG]228[/ATTACH]

and this is the illumination from the bottom:

[ATTACH=CONFIG]229[/ATTACH]

The material ambient is set to 0.01 for both front and back face.
I never set the emission so it should be 0.

So is it wrong to assign the ConstantAttenuation a value between 0 and 1?

That would make the attenuation factor > 1…

First of all, let me correct myself. The factor is actually

1 / (A_constant + A_linear * d + A_quadratic * d^2)

I was reminded when checking the documentation. The factors are actually weights to control the impact of the distance of vertex and light source. A_i can be any non-negative value. So yes, with the right factors you might actually produce higher radiance - or a brighter appearing object. As long as the sum in the denominator isn’t getting < 1 you’ll decrease radiance. Otherwise it will go up - which isn’t the purpose of attenuating. In my opinion the denominator should be clamped to [1, MAX_VALUE].

Also, know that this is not applied to directional light, only positional, i.e. point and spot lights. This makes sense since directional light are conceptually light sources at infinity.

I see that even with ConstantAttenuation = 1, in the back face there is a little illumination of the spot (but very very dim), so if constantAttenuation < 1, it would go to increase that dim illumination giving this illumination even to the back face.

This is more visible with my shader (that computes phong illumination):

top:
[ATTACH=CONFIG]230[/ATTACH]

bottom:
[ATTACH=CONFIG]231[/ATTACH]

But also without the shader and fixed function OpenGL:

top no shader:

[ATTACH=CONFIG]232[/ATTACH]

bottom no shader:
[ATTACH=CONFIG]233[/ATTACH]

So we’re back to the original question: why is there this little illumination on the back face? (that can become very intense in the ConstantAttenuation factor is << 1)

Wait a second. Are you doing lighting using shaders or fixed function? If “no shader” is fixed then the GL behaves correctly. If you mess it up using a shader, please show us the shader code. I’m confused.

Hi,

I showed both cases, with Shader and No Shader (fixed fucntion OpenGL) to show that both cases gives the same result: a little lighting on the backface.

In the case with the Shader the effect is more visible because I’m doing illumination at fragment level instead of vertex level (fixed function).

But if you look at the image “bottom no shader.jpg” you can see the little illumination I’m taking about towards the top right corner of my quad.

This was with ConstantAttenuation 0.1.

The 2 images I posted in my reply #6 use the ConstantAttenuation 0.01 and the illumination on the backface is much more visible, and they are done with fixed function OpenGL.

I wouldn’t expect any illumination on the backface… am I missing something?

Make sure fog is off. Disable distance and angle attenuation effects (i.e. const atten = 1, lin/quad = 0). And verify you’re multiplying by clamped cos term. Specular should also be 0 if N*L < 0. Note that this clamp doesn’t make physical sense but it is nonetheless there in the old FFP lighting equation.

Hi Dark Photon,

In the shader I’m doing this:


void ComputeSpotPointParameters( in int i,
                        in vec3 eye,
                        in vec3 ecPosition3,
                        in vec3 normal,
                        out vec3 VP,
                        out float nDotVP, 
                        out float pf,
                        out float attenuation)
{
   
    float nDotHV;
    float d;
    vec3 halfVector;
   
    VP = vec3(gl_LightSource[i].position) - ecPosition3;
    
    d = length(VP);
   
    VP = normalize(VP);
    
    attenuation = 1.0 / (gl_LightSource[i].constantAttenuation +
                        gl_LightSource[i].linearAttenuation * d +
                        gl_LightSource[i].quadraticAttenuation *d * d);
                        
    halfVector = normalize(VP + eye);
    
    nDotVP = max(0.0, dot(normal, VP));
    nDotHV = max(0.0, dot(normal, halfVector));
    
    if (nDotVP == 0.0)
      pf = 0.0;
    else
      pf = pow(nDotHV, gl_FrontMaterial.shininess);
}




void SpotLight(in int i,
               in vec3 eye,
               in vec3 ecPosition3,
               in vec3 normal,
               inout vec4 ambient,
               inout vec4 diffuse,
               inout vec4 specular)
{


    vec3 VP;
    float nDotVP, pf;
    float spotAttenuation;
    float attenuation;
    
    ComputeSpotPointParameters( i,
                                 eye,
                                 ecPosition3,
                                 normal,
                                 VP, nDotVP, pf,
                                 attenuation);
                        
   float spotDot = dot(-VP, normalize(gl_LightSource[i].spotDirection));
   
   if (spotDot < gl_LightSource[i].spotCosCutoff)
      spotAttenuation = 0.0;
   else
      spotAttenuation = pow(spotDot, gl_LightSource[i].spotExponent);
      
   attenuation *= spotAttenuation;
      
   ambient  = gl_LightSource[i].ambient * attenuation;
   diffuse  = gl_LightSource[i].diffuse * nDotVP * attenuation;
   specular = gl_LightSource[i].specular * pf * attenuation;
}




I guess the clamp you refer to is done in these lines:


    nDotVP = max(0.0, dot(normal, VP));
    nDotHV = max(0.0, dot(normal, halfVector));

But I would like to solve the problem with the Fixed Function OpenGL first.
Why do I have the illumination on the backface even without shaders?

Why do I have the illumination on the backface even without shaders?

With your current settings you shouldn’t - at least I didn’t spot the error yet. However, did you verify that the normal points into the right direction, i.e. parallel to -y in world-coordinates?

Yes,

the normal is pointing towards the upper (front) side of the Quad.

Ok, are you properly position the light source when you rotate the scene? Do you orient the normal correctly? Please post your full shader code. For fixed function we can’t really help you unless you post the fixed code.

I found out the following things studying my Shader and playing with it in RenderMonkey:

  1. The illumination on the backface is given by the ambient component of the spotlight:

   ambient  = gl_LightSource[i].ambient * attenuation;

When I’m looking at the backface nDotVP is 0, so if I multiplicate even the ambient factor by nDotVP, like the diffuse does, the backface is no longer illuminated.


   ambient  = gl_LightSource[i].ambient * attenuation * nDotVP;

Is that right, or is it better to just put “attenuation” to 0 if nDotVP is 0?

I guess the same applies for PointLights.

  1. If I clamp the ambient factor to [0,1] I don’t get an over-exposed illumination with small values of the ConstantAttenuation term.

Is that right, or is it better to just put “attenuation” to 0 if nDotVP is 0?

In general, if the diffuse term (nDotVP) is 0 and you have a solid, non-transmitting surface, then there can be no reflection of any light since no photons actually hit the surface your illuminating. However, the ambient term is usually independent of the diffuse and specular terms. The point of light-specific ambient terms is to be able to mix the global ambient color and the light-specific ambient colors for all light sources in the scene. However, if you move the light source further away, also interreflected radiance will decrease, that’s why there is a light-specific attenuation. The global ambient term is never attenuated.

In short: If you don’t want any lighting at all if the diffuse term is zero, simply set the global and light-specific ambient terms to zero (fixed function) or simply don’t use them in your calculation in the shader.

[QUOTE=thokra;1240378]
In short: If you don’t want any lighting at all if the diffuse term is zero, simply set the global and light-specific ambient terms to zero (fixed function) or simply don’t use them in your calculation in the shader.[/QUOTE]

But the fixed function is not setting the ambient terms to zero (as my pictures without the shader showed)…

The default value for global ambient color is (0.2, 0.2, 0.2, 1.0) so I think it’s no wonder why there’s something that’s not black.


float globalAmbient[] = {0.f, 0.f, 0.f, 1.f};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, globalAmbient);

Edit: BTW, I’d strongly advise against implementing a fixed-function lighting solution. Even with GLSL 1.10 you get much more flexibility and don’t have to cope with stuff like the above.