4

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 just can't get it work. I asume it has something to do with the transformation from world into eye coordinates.

Vertex Shader:

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(vertex.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(angle > radians(spotCutoff))
       gl_FrontColor = vec4(1,1,0,1); // lit (yellow)
   else
       gl_FrontColor = vec4(0,0,0,1); // unlit(black)   
}

Fragment Shader:

void main(void)
{
   gl_FragColor = gl_Color;
}

Edit:
Tim is right. This

if(angle > radians(spotCutoff))

should be:

if(acos(angle) < radians(spotCutoff))

New question:
The light seems not to stay at a fixed position in the scene, instead it seems to move relative to my camera as the cone gets smaller or bigger when I move forward or backward.

Basti
  • 373
  • 2
  • 6
  • 12
  • Where are your `#version` directives? – genpfault May 17 '12 at 03:11
  • instead of setting gl_FrontColor I would just pass a color value to the fragment shader as a `varying`. Then again, when I write against GLSL 1.20, it's usually just for backwards compatibility from GLSL 3.30+ shaders and I do things in the same way. I still think it's related to gl_FrontColor though, look at this other question :http://stackoverflow.com/questions/6430154/what-is-the-relationship-between-gl-color-and-gl-frontcolor-in-both-vertex-and-f – Robert Rouhani May 17 '12 at 03:26

4 Answers4

5

(Let spotDirection be vector A, and lightDirection be vector B)

You are assigning;

angle = dot(A,B)

Shouldn't the formula be:

cos(angle) = dot(A,B)

or

angle = arccos(dot(A,B))

http://en.wikipedia.org/wiki/Dot_product#Geometric_interpretation

Tim
  • 35,413
  • 11
  • 95
  • 121
  • Thank you for your effort! Could you please help me with my second question? – Basti May 19 '12 at 00:27
  • 2
    @Basti For future reference, you should consider posting a separate question if you have another question. This question is marked solved and will likely draw very little attention to the edit at the bottom of your post. Having said that, I don't have enough information to know the answer. If you're really defining your lightposition in object coordinates, and not moving the object, then I would not expect to see a change in the lighting, so there's probably something wrong that's not being shown above. Try making a new post with links to images describing your problem. – Tim May 19 '12 at 00:49
1

in my old shader I used that code:

float spotEffect = dot(normalize(gl_LightSource[0].spotDirection.xyz), 
                       normalize(-light));
if (spotEffect < gl_LightSource[0].spotCosCutoff) 
{
    spotEffect = smoothstep(gl_LightSource[0].spotCosCutoff-0.002,     
                            gl_LightSource[0].spotCosCutoff, spotEffect);
}
else spotEffect = 1.0;

instead of sending Angles to the shader it is better to send Cos of those Angles

fen
  • 9,835
  • 5
  • 34
  • 57
1

To answer your new question, here is a link to a similar question: GLSL point light shader moving with camera. The solution is to remove gl_NormalMatrix and gl_ModelViewMatrix.

spotDirection  = normalize(spotDirectionOC * gl_NormalMatrix);

Would become:

spotDirection  = normalize(spotDirectionOC);
Community
  • 1
  • 1
Stefnotch
  • 511
  • 2
  • 13
  • 26
0

https://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/graphics/shader.vert?r=1639

if (spotEffect >= cos(radians(uLightOuterCone[index])))

and

//vec3 NSpotDir  = (uViewMatrix * vec4(uLightDirection[index],0)).xyz; //must do outside or become flashlight follow
    vec3 NSpotDir = normalize(uLightDirection[index]);
lennon310
  • 12,503
  • 11
  • 43
  • 61