Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenGL: How to make light to be independent of rotation?

I have a diffuse lighting shader which seems to work when the object is not rotating. However, when I apply rotation transform, the light also seems to rotate along with the object. It's like the object and the light stay still but the camera is the one that moves around the object.

Here's my vertex shader code:

#version 110

uniform mat4 projectionMatrix;
uniform mat4 modelviewMatrix;
uniform vec3 lightSource;

attribute vec3 vertex;
attribute vec3 normal;

varying vec2 texcoord;

void main() {
    gl_Position = projectionMatrix * modelviewMatrix * vec4( vertex, 1.0 );

    vec3 N = gl_NormalMatrix * normalize( normal );
    vec4 V = modelviewMatrix * vec4( vertex, 1.0 );
    vec3 L = normalize( lightSource - V.xyz );

    float NdotL = max( 0.0, dot( N, L ) );

    gl_FrontColor = vec4( gl_Color.xyz * NdotL, 1.0 );

    gl_TexCoord[0] = gl_MultiTexCoord0;
}

and here's the code that does the rotation:

scene.LoadIdentity();
scene.Translate( 0.0f, -5.0f, -20.0f );
scene.Rotate( angle, 0.0f, 1.0f, 0.0f );
object->Draw();

I sent the eye-space light position through a glUniform3f, inside the object->Draw() function. The light position is static, and defined as:

glm::vec4 lightPos( light.x, light.y, light.z, 1.0 );
glm::vec4 lightEyePos = modelviewMatrix * lightPos;
glUniform3f( uniforms.lightSource, lightEyePos.x, lightEyePos.y, lightEyePos.z );

What's wrong with this approach?

Edit: The glm::lookAt code

Scene scene;
scene.LoadMatrix( projection );
scene.SetMatrixMode( Scene::Modelview );
scene.LoadIdentity();
scene.SetViewMatrix( glm::lookAt( glm::vec3( 0.0f, 0.0f, 0.0f ), glm::vec3( 0.0f, -5.0f, -20.0f ), glm::vec3( 0.0f, 1.0f, 0.0f ) ) );

The SetViewMatrix code:

void Scene::SetViewMatrix( const glm::mat4 &matrix ) {
    viewMatrix = matrix;
    TransformMatrix( matrix );
}

Then I just changed the modelviewMatrix I used to the viewMatrix:

glm::vec4 lightPos( light.x, light.y, light.z, 1.0 );
glm::vec4 lightEyePos = viewMatrix * lightPos;
glUniform3f( uniforms.lightSource, lightEyePos.x, lightEyePos.y, lightEyePos.z );
like image 386
Jacky Boen Avatar asked Jun 05 '12 21:06

Jacky Boen


1 Answers

Statement 1: The light position is static.

Statement 2: lightEyePos = modelviewMatrix * lightPos;

These two claims are inconsistent. If your light position is supposed to be static, you shouldn't be applying a rotated model matrix to it.

If your lightPos is defined in world coordinates, then you should multiply it with the viewMatrix not the modelviewMatrix. The modelviewMatrix contains the model matrix, which contains the model's rotation (you don't want to apply this to a fixed light source).

like image 178
Tim Avatar answered Nov 15 '22 08:11

Tim