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:

About these ads