Reputation: 11
So I am currently working on trying to create a spotlight in my vertex shader, currently I can produce directional and/or point light by using the Phong lighting model.
Im finding it hard to calculate the correct angles for the spotlight, basically just want a spotlight that comes from 0,0,0 in eye space and looks down the Z co-ord.
I am trying to just make everything (for now) in the cone to be bright white and everything outside it dark
#version 130
uniform mat4 model_view_matrix;
uniform mat4 projection_matrix;
uniform mat3 normal_matrix;
uniform int light_mode;
uniform vec4 light_pos;
uniform vec3 light_ambient;
uniform vec3 light_diffuse;
uniform vec3 light_specular;
uniform vec3 mtl_ambient;
uniform vec3 mtl_diffuse;
uniform vec3 mtl_specular;
uniform float mtl_shininess;
// Spotlight test
const float spotCutOff = 100.00f;
in vec3 position;
in vec3 normal;
in vec2 texCoord;
out vec2 st;
out vec4 litColour;
vec3 phongLight(in vec4 position, in vec3 norm)
{
// s is the direction from the light to the vertex
vec3 s;
if (light_pos.w == 0.0) {
s = normalize(light_pos.xyz);
}
else {
s = normalize(vec3(light_pos - position));
}
// v is the direction from the eye to the vertex
vec3 v = normalize(-position.xyz);
// r is the direction of light reflected from the vertex
vec3 r = reflect(-s, norm);
vec3 ambient = light_ambient * mtl_ambient;
// The diffuse component
float sDotN = max(dot(s,norm), 0.0);
vec3 diffuse = light_diffuse * mtl_diffuse * sDotN;
// Specular component
vec3 spec = vec3(0.0);
if (sDotN > 0.0)
spec = light_specular * mtl_specular * pow(max(dot(r,v), 0.0), mtl_shininess);
return ambient + diffuse + spec;
}
vec3 spotLight(in vec4 position, in vec3 norm)
{
vec3 ambient = vec3(0.2, 0.2, 0.2);
vec3 lightDir = normalize(vec3(light_pos - position));
vec3 spotDir = vec3(0.0, 0.0, -1.0);
float angle = degrees(acos(dot(spotDir, lightDir)));
//angle = max (angle, 0);
if ((angle) < spotCutOff) {
return vec3(1.0, 1.0, 1.0);
}
float dist = sqrt(positon.x * position.x + position.y + position.y + position.z * position.z);
if (dist < 1) {
return vec3(1.0,1.0,0.0);
}
return vec3(0.2, 0.2, 0.2);
}
void main(void)
{
// Convert normal and position to eye coords
vec3 eyeNorm = normalize(normal_matrix * normal);
vec4 eyePos = model_view_matrix * vec4(position, 1.0);
// No lighting effect
if (light_mode == 0)
{
litColour = vec4(1.0, 1.0, 1.0, 1.0);
}
// Directional overhead light
else if (light_mode == 1)
{
litColour = vec4(phongLight(eyePos, eyeNorm), 1.0);
}
// Point light
else if (light_mode == 2)
{
litColour = vec4(phongLight(eyePos, eyeNorm), 1.0);
}
else if (light_mode == 3)
{
litColour = vec4(spotLight(eyePos, eyeNorm), 1.0);
}
//litColour = vec4(normal*1000, 1.0);
gl_Position = projection_matrix * eyePos;
st = texCoord;
}
Upvotes: 1
Views: 511
Reputation: 5068
Your spotlight is defined by a position (ps) and a direction (ds). So for every vertex at position vp you can compute d=vp-ps, normalize that to dn=normalize(d), and then dot(dn,ds) will give you the angle in the spotlight. Just scale it or compare it to a cut off to get a scalar!
Alternatively, and in the long term better, is to think of a spotlight as a camera. Do the same as you do for your camera: A model and view matrix! Transform every vertex into that space, and project it from x,y,z,w to x,y,z. z is the distance which is always useful for lighting and x,y you can use to look up in a texture that has a round shape (or any other).
One thing to mind with both techniques is back projection: Make sure you check that the light only points forward! Check the sign of z or the dot product!
Upvotes: 1