3
\$\begingroup\$

I'm writing a lighting system in OPENGL using GLSL shaders, and I'm pretty happy with the light casting I have so far, but I'm totally stuck on casting shadows. Everything I've found online on this issue involves shadow-mapping in 3D, but I'm working in 2D and I'm not even sure shadow-mapping is the right approach here. So, here's some basic info on what I have so far:

My frag shader does all the lighting work, so I'll just post that one here:

#version 330

struct LightSource {
    vec2 pos;
    float intensity;
    vec3 c;
};
///texture in use
uniform sampler2D tex;

///BOOLEAN -> object has texture?
uniform uint hastex;

///BOOLEAN -> lighting is enabled?
uniform uint islit;

///color of fragment if no texture is applied
uniform vec4 fcolor;

///number of lights in scene
uniform int lightCount;

///MAX 25 lights in scene
uniform LightSource lights[25];

///dimensions of window
uniform vec2 wsize;

in vec2 ftexcoord;

///resulting color of fragment
layout(location = 0) out vec4 color;

void main() {
    vec4 initColor;
    if (hastex)
        initColor = texture(tex, ftexcoord);
    else
        initColor = fcolor;
    if (islit) {
        vec4 begColor;
        begColor.rgba = vec4(0.0, 0.0, 0.0, initColor.a);
        for (int i = 0; i < lightCount; ++i) {
            ///find fragment's coords in world-sapce
            vec2 fc = vec2(gl_FragCoord.x - (wsize.x / 2), gl_FragCoord.y - (wsize.y / 2));
            ///distance from fragment to light source
            float d = sqrt(pow(fc.x - lights[i].pos.x, 2) + pow(fc.y - lights[i].pos.y, 2));
            ///calculate fragment's illumination
            float n = (1 / sqrt(d)) * lights[i].intensity;
            if (n > 1) n = 1;
            vec4 tc;
            tc.rgba = vec4(n * initColor.r * lights[i].c.x, n * initColor.g *   lights[i].c.y, n * initColor.b * lights[i].c.z, 0.0);
            begColor += tc;
        }

        ///dithering
        float rand = gl_FragCoord.x * 353.0 + gl_FragCoord.y * 769.0;
        float noise = fract(rand / 991.0) / 256.0;

        color = begColor + noise;
    } else {
        color = initColor;
    }
}

Here's a screenshot of this

The problem now is that I just can't for the life of me figure out how to implement shadows here. I've tried several things unsuccessfully.

The only idea I had that even half-worked was just to pass in the positions and sizes of all objects in scene to the shader, then just have the shader try drawing a line from the fragment to the light, and test how many coords it passes through are inside objects, and darken based on that. That kinda worked, the problem is that it involves huge nested for loops with complex math and I was getting around 5 fps with that technique.

I also tried doing the looping/math I just mentioned in C++ and passing the shadow value of each coord in world-space into the shader, but looping through all of those to find which one is the same as the current fragment had similar performance issues (likely due to the almost 800,000 pixels in the scene).

I even tried changing this code into more of a ray-casting technique, as explained Here, but I had no idea how to translate the rays into GLSL and use them to determine whether a fragment was in a shadow or not, nor could I find any examples of how this could be achieved.

So, having exhausted all the online sources I can find and running out of ideas myself, I ask here, is there a way to implement shadows into this GLSL code that keeps decent performance? Or is the way I'm going about the lighting so far too flawed to properly implement shadows into?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.