PDA

View Full Version : [GLSL] Stationary spotlight

printf
05-17-2012, 12:55 PM
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)
}

BionicBytes
05-18-2012, 01:52 AM
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)?

BionicBytes
05-18-2012, 01:54 AM
And one more thing. For the uniform lightPositionOC, you have set w =1.0 havent you?

printf
05-18-2012, 05:48 AM
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)?
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?

printf
05-18-2012, 05:51 AM
And one more thing. For the uniform lightPositionOC, you have set w =1.0 havent you?

Yes, I have.

BionicBytes
05-18-2012, 08:35 AM
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.

printf
05-18-2012, 01:43 PM
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)
}

printf
05-19-2012, 05:43 AM
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)
}