GLSL ray-tracing to debug point lights

without comments

While debugging, sometimes wouldn’t it be nice see where the point lights in your scene are? Wouldn’t it be nice to do this via a shader modification rather than by adding new geometry to the scene? Sure, it would.

Here’s a quick, rough post on getting an effect like the blue/orange sphere around the point lights below…

Display some debugging spheres around lights displayed using GLSL code (no added geometry!)

GLSL Code

It’s pretty easy to add such functionality by adding a ray-tracing sphere intersection test to the fragment shader. The below code is a bit of a hack with hard-coded values, but this is a debugging technique so I’m okay with that. In the fragment shader’s inner loop on the lights add something like the below:

for (int i = 0; i < unifLightCount; ++i)
{
    ...
 
    // 
    // BEGIN Point light debug!
    //
    vec3 U2 = unifLightPosition[i].xyz;
    vec3 V2 = normalize(fragVertexEc);
    float dotUV2 = dot(U2,V2);
    if (dotUV2 > 0)
    {
        float D2 = dot(U2,U2) - dotUV2 * dotUV2;
        if (D2 < 20)
        {
            c = mix(c, unifLightColor[i], (1 - D2 * D2 / 400));
            c = mix(vec3(1,1,1) - c, c, (1 - D2 / 20));
        }
    }
    //
    // END point light debug
    //
}

What’s happening in the above?

  • U2 is the unnormalized vector from the eye (i.e. 0,0,0) to the light in eye coordinates
  • V2 is the normalized vector from the eye to the fragment (i.e. the ray, if this were ray-tracing)
  • dotUV2 is the cos(a) of the angle between those vectors
  • If dotUV2 is negative, then the angle > 90 degrees, meaning a intersection with a sphere centered about the light is not possible (assuming we’re not inside the sphere)
  • D2 is then the distance squared of the ray to the sphere / light center (via some trigonometry that’s what it simplifies to)
  • Next we check against and arbitrary/this-looks-good radius value (i.e. 20, in this case) for how large we want the debug sphere to be
  • Lastly we mix in some color for the light, in this case putting in a mix of the light color itself bordered by the usual color inverted (c = vec3(1,1,1) would be a much simpler alternative)

What else is interesting about this?

This is doing a bit of sphere ray-tracing in GLSL that can be used in a lot of ways. For example, light atmospheric effects: how about doing a look-up adding light color, modulated by distance from the light, and multiplying by an animated noise texture to simulate smoke?  Distance from a point can be used for plenty of effects.

Update: Glow Effect

From the debugging code described above (and adding the couple lines of code to load Morrowind light models as well), it was not very difficult to add a glow effect around lights:

Before - no glow effect

After - atmospheric glow effect on lights

The code is not that different from the debugging trick describe above. The main difference is to reject the effect if the fragment is in front of the radius (i.e. the equivalent of a z-test):

    // 
    // Light glow effect
    //
    vec3 U2 = unifLightPosition[i].xyz;
    vec3 V2 = normalize(fragVertexEc);
    float dotUV2 = dot(U2,V2);
    if (dotUV2 > 0)
    {
        float D2 = dot(U2,U2) - dotUV2 * dotUV2;
        float R = 120;
        float T = D2 / (R*R);
        if (T < 1 && length(fragVertexEc) > length(U2) - R)
            c += unifLightColor[i] * .5 * pow(1 - T,6); 
    }

Written by arthur

July 15th, 2011 at 10:24 am

 

Leave a Reply