How to transform directional light to camera space in GLSL

11,401

Solution 1

You have a common problem, often seen in GLSL tutorials online. You are passing your lighting values via uniform. Why don't you use the glLight calls, like with fixed function rendering, and pull the values from gl_LightSource[n]. The difference is that openGL will automatically translate everything in view space.

void main()
{
    // remember: directional lights are GL_POSITION with w = 0
    vec3 lightDir = vec3(gl_LightSource[0].position); 
    float ambient = gl_LightSource[0].ambient;
    vec3 lightColour = vec3(gl_LightSource[0].diffuse);


    gl_Position = ftransform();

    vec3 eyeNormal = normalize(gl_NormalMatrix * gl_Normal);
    float intensity = max(ambient, dot(eyeNormal, normalize(-lightDir));

    gl_FrontColor = gl_Color * vec4(lightColour, 1.0) * intensity;
}

A always great resource on the subject: http://www.lighthouse3d.com/opengl/glsl/index.php?lights

And always useful is the GLSL Cheat Cheat: http://www.cs.brown.edu/courses/cs123/resources/glslQuickRef.pdf

Solution 2

You must decide in which space you will do the lighting. If you want to follow "standard" OpenGL then it is view space. Your light vector must then be rotated by rotation part of the view matrix before passing to a shader (imho simplest solution).

You can also apply lights in other spaces (tangent, object, world or even screen space - for deffered shading) but that's different topic. Also note that for advanced use you will need to forget OpenGL and do everything with your own matrices and shaders (no default lighting/transformation stuff).

Share:
11,401
Aaron
Author by

Aaron

Updated on June 04, 2022

Comments

  • Aaron
    Aaron almost 2 years

    I have the following GLSL code for lighting:

    uniform vec3 lightDir; // Parallel light
    uniform float ambient;
    uniform vec3 lightColour;
    
    void main()
    {
         gl_Position = ftransform();
    
         vec3 eyeNormal = normalize(gl_NormalMatrix * gl_Normal);
         float intensity = max(ambient, dot(eyeNormal, normalize(-lightDir));
    
         gl_FrontColor = gl_Color * vec4(lightColour, 1.0) * intensity;
    }
    

    The light vector is specified in world space. I set the camera orientation and position using gluLookAt. Since OpenGL assumes the light vector is in camera space, the light moves with the camera instead of staying in a fixed orientation.

    I tried activating the shader and setting the light vector both before and after I call gluLookAt, but I get the same effect. What exactly do I have to do to properly transform the light vector?

  • Aaron
    Aaron over 14 years
    I tried multiplying lightDir by gl_NormalMatrix in the shader and there was no effect. I also tried multiplying by gl_ModelViewMatrix, like this: vec3 lightEyeDir = normalize(vec3(gl_ModelViewMatrix * vec4(-lightDir, 1.0))); Doing this knocked out the diffuse contribution completely. For transforming the light vector in program code, what transformation would I do exactly?
  • Tryum
    Tryum over 14 years
    By transforming the light dir by the inverse model matrix, you should obtain a model-space light.
  • MaR
    MaR about 14 years
    NormalMatrix is just rotation part of ModelView matrix(no translation & scale). Multiplying the light with it means also applying model rotation (and you don't want that).
  • Christian Rau
    Christian Rau over 12 years
    But in this case you don't need to negate the light direction, I think, as the value in the position field should already be the vector TO the light (in theory a position at infinity).
  • Christian Rau
    Christian Rau over 12 years
    This is wrong. Now you assume the lightDir to be in model space. And the ambient term is a cheat term, that always gives light even if there is no directional light, so it should definitely not be multiplied by the dot product, but added (or only used when there is not enough light, like he did). What you probably mean is the light's innate intensity, that in his case is represented by the lightColour that he multiplies by the dot product.
  • Christian Rau
    Christian Rau over 12 years
    @Tyrum But only if the lightDir was in eye space. But that is his problem, as he want's it to be in world space. As there is no model matrix, only a modelview matrix.
  • Stefan Monov
    Stefan Monov over 7 years
    Note that using glLight calls is now deprecated, unlike passing lighting values as uniforms.