openglgraphicsglsl2dlighting

How do I add fading at the edges of my lighting?


I am currently using a simple 2D lighting algorithm to create a 2D spotlight. Here is an example of how it looks like currently:

However, I would like to add in a gradual fading at the edges (top and bottom) so that it would look something like this:

enter image description here

My current lighting algorithm:

vec4 calculateLight(Light light)
{
    
    vec2 fragDirection = fragmentPosition.xy - light.position.xy;
    float aspectRatio = resolution.x / resolution.y; //amt of width / height
    if (aspectRatio > 1.0)
    {
        fragDirection.x *= aspectRatio;
    }
    else
    {
        fragDirection.x /= aspectRatio;
    }
    

    
    float lightDistance = length(fragDirection);
    if (length(fragDirection / light.radius) >= 1.0)
            return vec4(0, 0, 0, 1); //outside of radius make it black
    
    if (dot(normalize(fragDirection), normalize(light.spotDir.xy)) < cos(light.spotAngle/2))
            return vec4(0, 0, 0, 1); //outside of radius make it black
    
    return light.intensity * (1 - length(fragDirection / light.radius)) * light.colour;
}

Solution

  • Try this as a start point:

    Vertex:

    #version 400 core
    
    in vec2 position;
    out vec2 pos;
    
    void main(void)
        {
        pos=position;
        gl_Position = vec4(position.xy,0.0,1.0);
        }
    

    Fragment:

    #version 400 core
    
    in vec2 pos;
    out vec3 out_Color;
    
    // light
    const float deg=0.01745329251994329576923690768489;
    uniform vec2 lpos=vec2(-0.5,0.0); // positon
    uniform vec2 ldir=vec2(+1.0,0.0); // directon (unit vector)
    uniform float lr1=1.0;            // soft radius
    uniform float lr0=0.9;            // hard radius
    uniform float la1=cos(25.0*deg);  // soft half angle
    uniform float la0=cos(20.0*deg);  // hard half angle
    
    void main(void)
        {
        float a,c,r;
        vec3 col;
        vec2 d;
        col=vec3(1.0,1.0,1.0);
        d=pos-lpos;
        r=length(d);
        d=normalize(d);
        c=0.0;
        // light side strength (angle)
        a=abs(max(0.0,dot(ldir,d)));
             if (a>=la0) c=1.0;                 // hard light
        else if (a>=la1) c=(a-la1)/(la0-la1);   // soft light
        else discard;                           // no light
        // light forward strength (radius)
             if (r<=lr0);                       // hard light
        else if (r<=lr1) c*=(r-lr1)/(lr0-lr1);  // soft light
        else discard;                           // no light
        out_Color = col*c;
        }
    

    it uses linear attenuation of line in both sides (angle) and forward (radius) just change the light uniforms to the Light structure you using ...

    Here preview:

    preview

    Now you can play with different types of attenaution just change the linear interpolation to quadratic,exponential or whatever... btw I multiplied the light intensities c from angle and radius together you might change that to min or max instead to achieve different edge connections

    After playing with the constants and equations a bit:

    Fragment:

    #version 400 core
    
    in vec2 pos;
    out vec3 out_Color;
    
    // light
    const float deg=0.01745329251994329576923690768489;
    uniform vec2 lpos=vec2(-0.5,+0.0);// positon
    uniform vec2 ldir=vec2(+0.7,-0.7);// directon (unit vector)
    uniform float lr1=1.00;           // soft radius
    uniform float lr0=0.25;           // hard radius
    uniform float la1=cos(30.0*deg);  // soft half angle
    uniform float la0=cos(15.0*deg);  // hard half angle
    
    void main(void)
        {
        float a,r,c0,c1;
        vec3 col;
        vec2 d;
        col=vec3(1.0,1.0,1.0);
        d=pos-lpos;
        r=length(d);
        d=normalize(d);
        // light side strength (angle)
        a=abs(max(0.0,dot(ldir,d)));
             if (a>=la0) c0=1.0;                // hard light
        else if (a>=la1) c0=(a-la1)/(la0-la1);  // soft light
        else discard;                           // no light
        // light forward strength (radius)
             if (r<=lr0) c1=1.0;                // hard light
        else if (r<=lr1) c1=(r-lr1)/(lr0-lr1);  // soft light
        else discard;                           // no light
        a=c0*c1;
        out_Color = col*pow(a,2.5);
        }
    

    preview