Point light/spotlight attenuation in glsl 1.3+?

I’ve been working OpenGL’s Superbible (5th Edition) point light examples.

I found them missing the constant, linear and quadratic attenuation values integrated into the old lighting model, so I went and wrote a point light shader with attenuation values based on Point Light Attenuation this ogre guide.

The results have been completely bizarre. What can be done to get a sensible light attenuation on the new glsl? Is there a glsl table for attenuation constants?

Sample vertex and fragment programs:
Vertex program:

 //point light per pixel vertex program 
    #version 130
    // Incoming per vertex... position and normal
    in vec4 vVertex;
    in vec3 vNormal;
    uniform mat4   mvpMatrix;
    uniform mat4   mvMatrix;
    uniform mat3   normalMatrix;
    uniform vec3   vLightPosition;
    // Color to fragment program
    smooth out vec3 vVaryingNormal;
    smooth out vec3 vVaryingLightDir;
    out float dist;
    out float constantAttenuation;
    out	float linearAttenuation;
    out	float quadraticAttenuation; 
    void main(void) 
        // Get surface normal in eye coordinates
        vVaryingNormal = normalMatrix * vNormal;
        // Get vertex position in eye coordinates
        vec4 vPosition4 = mvMatrix * vVertex;
        vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
    	//get distance to light source
    	 //write proper attenuation values
    	if (dist<7.0){
    	else if (dist<13.0){
    	else if (dist<20.0){
    	if (dist<32.0){
    	if (dist<50.0){
    	if (dist<65.0){
    	if (dist<100.0){
        // Get vector to light source
        vVaryingLightDir = normalize(vLightPosition - vPosition3);
        // Don't forget to transform the geometry!
        gl_Position = mvpMatrix * vVertex;

Fragment program:

//point light per pixel fragment program 
    #version 130
    out vec4 vFragColor;
    uniform vec4    ambientColor;
    uniform vec4    diffuseColor;   
    uniform vec4    specularColor;
    smooth in vec3 vVaryingNormal;
    smooth in vec3 vVaryingLightDir;
    in float dist;
    in float constantAttenuation;
    in float linearAttenuation;
    in float quadraticAttenuation; 
    void main(void){ 
    	float att;
    	att = 1.0 / constantAttenuation + linearAttenuation*dist +quadraticAttenuation*dist*dist;
        // Dot product gives us diffuse intensity
        float diff = max(0.0, dot(normalize(vVaryingNormal), normalize(vVaryingLightDir)));
        // Multiply intensity by diffuse color, force alpha to 1.0
        vFragColor = att*(diff * diffuseColor +ambientColor); // attenuation affects the diffuse component
        // Specular Light
        vec3 vReflection = normalize(reflect(-normalize(vVaryingLightDir), normalize(vVaryingNormal)));
    	float spec = max(0.0, dot(normalize(vVaryingNormal), vReflection));
        if(diff != 0) {
            float fSpec = pow(spec, 128.0);
            vFragColor.rgb += (att*vec3 (fSpec, fSpec, fSpec)); // attenuation affects the specular component

The results have been completely bizarre.

That’s because you misunderstood the Ogre document.

The “range” represents the maximum distance of effect for the light. That is, the distance at which you no longer want that light to affect objects.

This is a property of the light, just like it’s intensity (ie: color). Your code has a hard-coded light intensity (namely, 1.0. Since you don’t multiply the dot(N, L) by a color, you effectively have lights with unit intensity). The range is not something that should be output from a vertex shader.

Furthermore, you’ve misunderstood what the table means. The table is saying that, “If you want a light to have an effective range of X, here are the attenuation parameters that give this effect.” The attenuation parameters are, like the light intensity and effective range, properties of the light. Not output values from the vertex shader. They should be uniforms.

That is, you pick one set of values from the table, based on the effective range you want.


    	att = 1.0 / constantAttenuation + linearAttenuation*dist +quadraticAttenuation*dist*dist;

You need more parentheses here. It’s 1.0 divided by all of those things, not just “constantAttenuation”.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.