Help with basic lighting in shader


I’m trying to make a shader that works as close as possible to the fixed functionality in terms of lighting, and I’m having some difficulties with that. My problem is that the end result is darker than when I use fixed unctionality, and I don’t understand why.

I used 3DLabs’ ShaderGen to generate a shader for one directional light, since this is what I use in my scene. Since the generated shader does not take the color assigned to the vertex into account, I added the line “color = color * gl_Color;”. This is the vertex shader I end up with:

*  Fixed.vert Fixed Function Equivalent Vertex Shader  *
*   Automatically Generated by 3Dlabs GLSL ShaderGen   *
*                 *
vec4 Ambient;
vec4 Diffuse;
vec4 Specular;

void directionalLight(in int i, in vec3 normal)
   float nDotVP;         // normal . light direction
   float nDotHV;         // normal . light half vector
   float pf;             // power factor

   nDotVP = max(0.0, dot(normal, normalize(vec3 (gl_LightSource[i].position))));
   nDotHV = max(0.0, dot(normal, vec3 (gl_LightSource[i].halfVector)));

   if (nDotVP == 0.0)
       pf = 0.0;
       pf = pow(nDotHV, gl_FrontMaterial.shininess);

   Ambient  += gl_LightSource[i].ambient;
   Diffuse  += gl_LightSource[i].diffuse * nDotVP;
   Specular += gl_LightSource[i].specular * pf;

vec3 fnormal(void)
    //Compute the normal
    vec3 normal = gl_NormalMatrix * gl_Normal;
    normal = normalize(normal);
    return normal;

void flight(in vec3 normal, in vec4 ecPosition, float alphaFade)
    vec4 color;
    vec3 ecPosition3;
    vec3 eye;

    ecPosition3 = (vec3 (ecPosition)) / ecPosition.w;
    eye = vec3 (0.0, 0.0, 1.0);

    // Clear the light intensity accumulators
    Ambient  = vec4 (0.0);
    Diffuse  = vec4 (0.0);
    Specular = vec4 (0.0);

    directionalLight(0, normal);

    color = gl_FrontLightModelProduct.sceneColor +
      Ambient  * gl_FrontMaterial.ambient +
      Diffuse  * gl_FrontMaterial.diffuse;
    color += Specular * gl_FrontMaterial.specular;
    color = color * gl_Color;                                         // This is the line I added
    color = clamp( color, 0.0, 1.0 );
    gl_FrontColor = color;

    gl_FrontColor.a *= alphaFade;

void main (void)
    vec3  transformedNormal;
    float alphaFade = 1.0;

    // Eye-coordinate position of vertex, needed in various calculations
    vec4 ecPosition = gl_ModelViewMatrix * gl_Vertex;

    // Do fixed functionality vertex transform
    gl_Position = ftransform();
    transformedNormal = fnormal();
    flight(transformedNormal, ecPosition, alphaFade);

This is what I get if I use the shader:


and this is when I get if I use NO shader:


What could I be doing wrong?

That’s wrong. In the fixed-function pipeline, if lighting is enabled, then the colour is only used if GL_COLOR_MATERIAL is enabled. In that case, the current colour replaces the material colour(s) as specified by glColorMaterial; it doesn’t modulate them. If lighting is enabled and GL_COLOR_MATERIAL is disabled, the current colour is ignored; the colour generated by the lighting calculations replaces any vertex colour set by glColor (or glColorPointer).

Note that any parameters obtained from the compatibility uniforms (gl_FrontMaterial, gl_FrontLightProduct, etc) aren’t affected by GL_COLOR_MATERIAL (uniforms cannot vary per-vertex); if you want to emulate the behaviour of GL_COLOR_MATERIAL, the shader must use gl_Color in place of the relevant material colour(s).

Also, the alpha component of the colour produced by lighting is taken directly from the alpha component of the diffuse material colour.

I suggest that you start by simplifying the lighting model, both in the shader and the equivalent fixed-function code. Start with just gl_LightModelParameters.ambient, then add one extra lighting term (emission, ambient, diffuse, specular) at a time, ensuring that you resolve any issues with each term before moving onto the next.

Thanks or the very informative answer. I think I understand most of it. :slight_smile:

After some more research and fiddling, I think I got it.

I changed the bit of code from

color = gl_FrontLightModelProduct.sceneColor +
      Ambient  * gl_FrontMaterial.ambient +
      Diffuse  * gl_FrontMaterial.diffuse;
    color += Specular * gl_FrontMaterial.specular;
    color = color * gl_Color;                                         // This is the line I added


color = (gl_Color * gl_LightModel.ambient) +
      Ambient  * gl_Color +
      Diffuse  * gl_Color;
    color += Specular * gl_Color;

and that seems to produce the same result as with fixed-function.

Does this seem correct?

Not entirely.

If you enable GL_COLOR_MATERIAL, you can make the current colour replace either any one of the material colours, or both ambient and diffuse; you can’t make it affect all of them. Accepted parameters for glColorMaterial are GL_EMISSION, GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, and GL_AMBIENT_AND_DIFFUSE. The initial value is GL_AMBIENT_AND_DIFFUSE.

If a material colour tracks the current colour, the accumulated lighting component should be multiplied by gl_Color, otherwise it should be multiplied by the corresponding material component (from gl_FrontMaterial or gl_BackMaterial).

Note that for two-sided lighting, the vertex shader needs to calculate separate front and back colours, because you don’t know which one you’ll need until you get to the fragment shader (a single vertex may be part of multiple triangles, some of which are front-facing and some back-facing).

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.