How to transform directional light to camera space in GLSL
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).
Aaron
Updated on June 04, 2022Comments
-
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 over 14 yearsI 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 over 14 yearsBy transforming the light dir by the inverse model matrix, you should obtain a model-space light.
-
MaR about 14 yearsNormalMatrix 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 over 12 yearsBut 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 over 12 yearsThis 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 thelightColour
that he multiplies by the dot product. -
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 over 7 yearsNote that using glLight calls is now deprecated, unlike passing lighting values as uniforms.