GLSL Directional Light

Started by
8 comments, last by sevenfold1 9 years ago
Hello,
I'm trying to setup a basic directional light that matches the fixed pipeline.

However, my GLSL version looks like a point light, with very dark edges.
Ambient is zero, specular is zero, and attenuation is off, so it doesn't interfere.

How can I match the same shading as seen in the fixed version?

fu73mb.jpg



//////////////////////////////////////////

// VERTEX SHADER

varying vec3 N;
varying vec3 L;

void main()
{    
    N = normalize(gl_NormalMatrix * gl_Normal);
    L = normalize(gl_LightSource[0].position.xyz);	// directional light

    gl_Position = ftransform();
}

//////////////////////////////////////////

// FRAGMENT SHADER

varying vec3 N;
varying vec3 L;

void main()
{ 
    N = normalize(N);
    L = normalize(L);

    float lamb = max( dot(N,L), 0.0 );
    
    vec4 diffuseColor = vec4(1,1,1,1);
    gl_FragColor = lamb * diffuseColor;
}
Advertisement

#1: Don’t normalize the light/normal in the vertex shader if you are going to renormalize them in the pixel shader. Think about where each needs to be normalized and only normalize them there.

Normalize the light vector in the vertex shader since it does not change across the face of the triangle.

The normal will not be normalized across the face of the triangle even if you normalize it in the vertex shader, so only normalize it in the pixel shader.

#2: You are using per-pixel shading while they are using vertex shading.

If you want their result (which you shouldn’t), then perform lighting in the vertex shader, not the pixel shader. The pixel shader simply outputs the result as the final color.

L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid


>>perform lighting in the vertex shader, not the pixel shader...


Thanks, that was it!

I didn't realize where I made the calculations made a difference.


>>Don’t normalize the light/normal in the vertex shader if you are going to renormalize them in the pixel shader.

No problem. I read somewhere that these "varying" variables get interpolated when getting passed around, so I have no idea if there are still normalized or not.




///////////////////////////////////////////////////////////////////

// VERTEX SHADER

varying vec4 fragColor;

void main()
{    
    vec3 N = normalize(gl_NormalMatrix * gl_Normal);
    vec3 L = normalize(gl_LightSource[0].position.xyz);	// directional light

    //////////////////////////////////

    float lamb = max( dot(N,L), 0.0 );
    vec4 diffuseColor = vec4(1,1,1,1);
    fragColor = lamb * diffuseColor;

    //////////////////////////////////

    gl_Position = ftransform();
}

///////////////////////////////////////////////////////////////////

// FRAGMENT SHADER

varying vec4 fragColor;

void main()
{ 
    gl_FragColor = fragColor;
}

so I have no idea if there are still normalized or not.

Think about the result of linearly interpolating between 2 points.
Even if the 2 points are normalized at the start, the points between them will only still be normalized if the start and end point are the same.
Interpolate mentally between these 2 normals:
\   /
 \ /
  º
Going directly across from one to the other, you can mentally see that the points on the line segment you draw are not unit-length.

The light direction, on the other hand, doesn’t change, so it is the same as interpolating from one point to the same point. So if that point is normalized it will stay normalized. Hence it can be done once in the vertex shader.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

you should also normalize the normal on the vertex shader otherwise you're giving the normal with a greater length an unwanted weight in interpolation

If the normals are of unit length on input, multiplication with gl_NormalMatrix (which is deprecated) will result in normals of some consistent ratio.
Meaning in most cases all normals will still be 1 length long, but may all be 0.5 long, etc.
In other words, as long as the normals are the same length in input they will be the same length after gl_NormalMatrix.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Thanks, this works great for my purposes, but the only downside to doing calculations in the vertex shader, is that I can't use the texture2D sampler anymore. That must be done in the fragment shader, per pixel.

as L. Spiro said you'd really want to do shading on fragment shader for smooth and per fragment shading I don't really see a reason not to do that. and your shading being different from fixed pipe line doesn't mean you're doing it wrong it means fixed pipe line is doing it wrong

Thanks, this works great for my purposes, but the only downside to doing calculations in the vertex shader, is that I can't use the texture2D sampler anymore. That must be done in the fragment shader, per pixel.

well i dont know modern glsl but what i know is that you can use sampler2D in a vertex shader.

Another thing you can even make a texture projection where texture is a single circle (filled with a color) and project it onto a scene works exactly as directional light


To get this working with texture coords, I have to pass the lighting factor as a vector, like vec4.
Passing it as a single float to the fragment shader always fails. The float is always zero.

Is this a problem with the GLSL version or somewhere else?


///////////////////////////////////////////////////////////////////

// VERTEX SHADER

varying float lamb;
varying vec4 diffuseColor;

void main()
{    
    vec3 N = normalize(gl_NormalMatrix * gl_Normal);
    vec3 L = normalize(gl_LightSource[0].position.xyz);	// directional light

    float lamb = max( dot(N,L), 0.0 );
    diffuseColor = lamb * vec4(1,1,1,1);

    //////////////////////////////////

    gl_TexCoord[0] = gl_MultiTexCoord0;
    gl_Position = ftransform();
}

///////////////////////////////////////////////////////////////////

// FRAGMENT SHADER

uniform sampler2D diffuseMap;
varying float lamb;
varying vec4 diffuseColor;

void main()
{ 
    // fails
    //gl_FragColor = lamb * texture2D(diffuseMap, gl_TexCoord[0].st);

    // works
    gl_FragColor = diffuseColor * texture2D(diffuseMap, gl_TexCoord[0].st);
}

This topic is closed to new replies.

Advertisement