The necessary step after the previous post: Spot Lights.

After tweaking around with point lights, it was the time to experiment with another kind of light: the spot light. I also introduced a 3D model from the Stanford University 3D Scanning Repository to make it a little more interesting.

Here is the fragment shader, which includes slight modifications in the lighting calculation function: spotLight. The vertex shader is exactly the same as the previous post.

#version 330 out vec4 fragmentColor; struct Light { vec4 position; vec4 ambient; vec4 diffuse; vec4 specular; float constant_attenuation; float linear_attenuation; float quadratic_attenuation; vec3 spot_direction; float spot_cutoff; float spot_exponent; }; uniform Lights { Light light[8]; } lights; uniform Material { vec4 ambient; vec4 diffuse; vec4 specular; float shininess; } material; uniform int num_lights; smooth in vec3 vPosition; smooth in vec3 vNormal; vec4 spotLight (int lightID) { float nDotVP; // normal * light direction float nDotR; // normal * light reflection vector float pf; // power factor float spotDot; // cosine of angle between spotlight float spot_att; // spotlight attenuation factor; float attenuation; // computed attenuation factor float d; // distance from surface to light position vec3 VP; // direction from surface to light position vec3 reflection; // direction of maximum highlights // Compute vector from surface to light position VP = vec3 (lights.light[lightID].position) - vPosition; // Compute distance between surface and light position d = length (VP); // Normalize the vector from surface to light position VP = normalize (VP); // Compute attenuation attenuation = 1.f / (lights.light[lightID].constant_attenuation + lights.light[lightID].linear_attenuation * d + lights.light[lightID].quadratic_attenuation * d * d); // See if point on surface is inside cone of illumination spotDot = dot (-VP, normalize (lights.light[lightID].spot_direction)); if (spotDot < lights.light[lightID].spot_cutoff) spot_att = 0.f; else spot_att = pow (spotDot, lights.light[lightID].spot_exponent); // Combine the spot and distance attenuation attenuation *= spot_att; reflection = normalize (reflect (-normalize (VP), normalize (vNormal))); nDotVP = max (0.f, dot (vNormal, VP)); nDotR = max (0.f, dot (normalize (vNormal), reflection)); if (nDotVP == 0.f) pf = 0.f; else pf = pow (nDotR, material.shininess); vec4 ambient = material.ambient * lights.light[lightID].ambient * attenuation; vec4 diffuse = material.diffuse * lights.light[lightID].diffuse * nDotVP * attenuation; vec4 specular = material.specular * lights.light[lightID].specular * pf * attenuation; return ambient + diffuse + specular; } void main(void) { for (int i = 0; i < num_lights; ++i) fragmentColor += spotLight (i); }

And finally some screenshots showing the dragon model and the two spotlights over it:

On the client side of OpenGL how do you buffer Array-Of-Structure Uniforms?

On client side I simply use a std::vector<Light> (Light being the struct to be used in the shader). Then I copy all the client side Light data to the GPU buffer.

Hope it helps! See you!

Why don’t you use a “viewDirection” vector when nDotR is computed ?

i.e. nDotR = max (0.f, dot (normalize (viewDirection), reflection));

nDotR stands for “Normal dot Reflection”. Why would you use the viewDirection?

Beacuse specular highlights depend on the viewer (camera) position.

http://en.wikibooks.org/wiki/GLSL_Programming/GLUT/Specular_Highlights

http://www.arcsynthesis.org/gltut/Illumination/Tut11%20Phong%20Model.html

Well, yes. But, since I’m doing the lighting computations in eye (or camera) space I don’t need the viewDirection vector. I already know the camera is at (0, 0, 0).

I think that even if you doing the lighting computation in eye (or camera) space you still need the viewDirection vector, but in your case viewDirection = normalize(-vPosition). Look at the arcsynthesis tutorial linked above. There the lighting computation is also in camera space.

Yeah, I see. I simplified a little. These are only “demos”, not production code ;)

Thank you for pointing this out.

I have less than a month to create a scene in OpenGL, and sadly since I’m to rely on http://arcsynthesis.org/ which seems to be regarded on the internet as “Learning OpenGL for the mentally deranged” I wanted to ask if you could maybe possibly help me, because I again spend a whole day trying to add lightning to my scene and no matter how many ways I try, it doesn’t work. :(