[GLSL] Stationary spotlight

Hello,
I need help with a simple spotlight shader. All vertices inside the cone should be colored yellow, all vertices outside the cone should be colored black.
I want the spotlight to stay at a fixed position in the scene, but I just can’t get it work (the spotlight seems to move relative to my camera) :(.

``````
uniform vec4  lightPositionOC ; // in object coordinates
uniform vec3  spotDirectionOC; // in object coordinates
uniform float spotCutoff;           // in degrees

void main(void)
{
vec3 lightPosition;
vec3 spotDirection;
vec3 lightDirection;
float angle;

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

// Transforms light position and direction into eye coordinates
lightPosition  = (lightPositionOC * gl_ModelViewMatrix).xyz;
spotDirection  = normalize(spotDirectionOC * gl_NormalMatrix);

// Calculates the light vector (vector from light position to vertex)
vec4 vertex = gl_ModelViewMatrix * gl_Vertex;
lightDirection = normalize(lightPosition.xyz -vertex.xyz);

// Calculates the angle between the spot light direction vector and the light vector
angle = dot(normalize(spotDirection),
normalize(lightDirection));
angle = max(angle,0);

// Test whether vertex is located in the cone
if(acos (angle) < radians(spotCutoff))
gl_FrontColor = vec4(1,1,0,1); // lit (yellow)
else
gl_FrontColor = vec4(0,0,0,1); // unlit(black)
}

``````

Why are you using the normal matrix to calc eye-space spot light direction vector?

``````spotDirection  = normalize(spotDirectionOC * gl_NormalMatrix);
``````

Also, what’s in the gl_ModelView matrix? Is it guaranteed to only contain the camera (gluLookat) and not any model transformations (glScalef, glTranslatef, glRotatef)?

And one more thing. For the uniform lightPositionOC, you have set w =1.0 havent you?

[QUOTE=BionicBytes;1237667]Why are you using the normal matrix to calc eye-space spot light direction vector?

``````spotDirection  = normalize(spotDirectionOC * gl_NormalMatrix);
``````

Also, what’s in the gl_ModelView matrix? Is it guaranteed to only contain the camera (gluLookat) and not any model transformations (glScalef, glTranslatef, glRotatef)?[/QUOTE]
I used the normal matrix because the spot direction is a normal and I used gl_ModelView because I thought it also contains the model transformations.

So what do I have to do to get it work?

Yes, I have.

I used the normal matrix because the spot direction is a normal and I used gl_ModelView because I thought it also contains the model transformations.

The spot direction needs to be transformed into eye space as that’s the coordinate system used by your lighting equation. Therefore you need to multiply the spot Direction by the camera matrix.
The gl_ModelView matrix should only contain the camera transform! It should not be containing any modeling transforms. The problem here is that OpenGL combines the two. Therefore you’ll find things a LOT easier if you roll your own matricies - a camera matrix and a separate model matrix per object you wish to draw. Therefore all lighting positions,directions,etc should be multiplied by JUST the camera matrix.

BionicBytes, many thanks for your efforts, but
now I’m using a view matrix but the light is still not staying at a fixed position.

Here’s the new code:

``````
uniform mat4  matView;         // view matrix
uniform vec4  lightPositionOC ; // in object coordinates
uniform vec3  spotDirectionOC;  // in object coordinates
uniform float spotCutoff;       // in degrees

void main(void)
{
vec3 lightPosition;
vec3 spotDirection;
vec3 lightDirection;
float angle;

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

// Transforms light position and direction into eye coordinates
lightPosition  = (lightPositionOC * gl_ModelViewMatrix).xyz;
spotDirection  = vec3( vec4(spotDirectionOC,1) * matView);
spotDirection = normalize(spotDirection);

// Calculates the light vector (vector from light position to vertex)
vec4 vertex = gl_ModelViewMatrix * gl_Vertex;
lightDirection = normalize(lightPosition.xyz -vertex.xyz);

// Calculates the angle between the spot light direction vector and the light vector
angle = dot(normalize(spotDirection),
normalize(lightDirection));
angle = max(angle,0);

// Test whether vertex is located in the cone
if(acos (angle) < radians(spotCutoff))
gl_FrontColor = vec4(1,1,0,1); // lit (yellow)
else
gl_FrontColor = vec4(0,0,0,1); // unlit(black)
}

``````

I got it working!
My error was that I mixed up the coordinate spaces.
Here is the working code hoping that it will help others:

In Wold Space

``````
uniform vec4  lightPositionOC;   // in object coordinates
uniform vec3  spotDirectionOC;  // in object coordinates
uniform float  spotCutoff;           // in degrees

void main(void)
{
vec3 lightPosition;
vec3 spotDirection;
vec3 lightDirection;
float angle;

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

// Transforms light position and direction into eye coordinates
lightPosition   =  lightPositionOC;
spotDirection  = spotDirectionOC;

spotDirection = normalize(spotDirection);

// Calculates the light vector (vector from light position to vertex)
vec4 vertex = gl_ModelViewMatrix * gl_Vertex;
lightDirection = normalize( (gl_Vertex * matWorld).xyz - lightPosition.xyz);

// Calculates the angle between the spot light direction vector and the light vector
angle = dot( normalize(spotDirection),
normalize(lightDirection));
angle = max(angle,0);

// Test whether vertex is located in the cone
if(acos (angle) > radians(spotCutoff))
gl_FrontColor = vec4(0,0,0,1); // unlit(black)
else
gl_FrontColor = vec4(1,1,0,1); // lit (yellow)
}

``````

In View space

``````
uniform mat4 matView;             // view matrix
uniform vec4  lightPositionOC;   // in object coordinates
uniform vec3  spotDirectionOC;  // in object coordinates
uniform float  spotCutoff;           // in degrees

vec4  lightPositionOC = vec4(0,400,0,1);   // in object coordinates
vec3  spotDirectionOC = vec3(0,-1,0);   // in object coordinates
float spotCutoff    = 1;  // in degrees

void main(void)
{
vec3 lightPosition;
vec3 spotDirection;
vec3 lightDirection;
float angle;

gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

// Transforms light position and direction into eye coordinates
lightPosition  = (lightPositionOC * matView).xyz;
spotDirection  = vec3(vec4(spotDirectionOC,1) * matView);

spotDirection = normalize(spotDirection);

// Calculates the light vector (vector from light position to vertex)
vec4 vertex = gl_ModelViewMatrix * gl_Vertex;
lightDirection = normalize( (gl_Vertex * matView).xyz - lightPosition.xyz);

// Calculates the angle between the spot light direction vector and the light vector
angle = dot( normalize(spotDirection),
normalize(lightDirection));
angle = max(angle,0);

// Test whether vertex is located in the cone
if(acos (angle) > radians(spotCutoff))
gl_FrontColor = vec4(0,0,0,1); // unlit(black)
else
gl_FrontColor = vec4(1,1,0,1); // lit (yellow)
}

``````