Jump to content

Shadowmap shader doesn't seem to work correctly


Iavra
 Share

Recommended Posts

First, i know that 2.2.9 is pretty outdated, but it's what i have to work with.

I'm currently trying to achieve 2d lighting by using this tutorial: https://github.com/mattdesl/lwjgl-basics/wiki/2D-Pixel-Perfect-Shadows

Rendering the occlusion map is trivial and i can theoretically create the 1D shadowmap, but it seems to ignore pixels, that are too far away from the center. This is my fragment shader:

new PIXI.AbstractFilter([
    '#define PI 3.14', 
                
    'precision mediump float;',
    'varying vec2 vTextureCoord;',
    'uniform sampler2D uSampler;',
                
    'const float h = 400.0;',
                
    'void main(void) {', 
    '    if((vTextureCoord.y * h) > 1.0) {',
    '        gl_FragColor = vec4(0.0);', 
    '        return;', 
    '    }', 
    '    float distance = 1.0;', 
    '    for(float y = 0.0; y < h; y += 1.0) {',
    '        float dst = y / h;', 
    '        vec2 norm = vec2(vTextureCoord.x, dst) * 2.0 - 1.0;',
    '        float theta = PI + norm.x * PI;',
    '        float r = (1.0 + norm.y) * 0.5;',
    '        vec2 coord = vec2(-r * sin(theta), -r * cos(theta)) / 2.0 + 0.5;',
    '        if(texture2D(uSampler, coord).a > 0.0) {', 
    '            distance = dst;', 
    '            break;', 
    '        }',                 
    '    }',
    '    gl_FragColor = vec4(vec3(distance), 1.0);',
    '}'
]);

I'm currently hardcoding the height of the occlusion map, because i can't use uniforms as loop boundaries.

I have to admit, my math isn't good enough to completely understand, what's going on in the transformation, but it seems to work as long as the occluder is near enough to the light. I tried increasing the occlusion map by adding empty space, but it didn't help.

Has someone attempted something like this and can point me in the right direction? Sure, i could try to create the 1D map on CPU, but that's going to be really slow, when i have to include moving objects and need to recalculate often.

Link to comment
Share on other sites

I made some progress. I've discarded the 1D shadowmap (for now), since i couldn't get it to work and instead opted to wrap the occlusion map, extend all visible pixels downwards and unwrap it again. For this i'm using these shaders:

#define PI 3.14'

precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D uSampler;

const float h = 400.0;

void main(void) {
    for(float y = 0.0; y < h; y += 1.0) {
        if(y / h > vTextureCoord.y) { break; }
        vec2 norm = vec2(vTextureCoord.x, y / h) * 2.0 - 1.0;
        float theta = PI + norm.x * PI;
        float r = (1.0 + norm.y) * 0.5;
        vec2 coords = vec2(-r * sin(theta), -r * cos(theta)) / 2.0 + 0.5;
        if(texture2D(uSampler, coords).a > 0.0) {
            gl_FragColor = vec4(1.0);
            return;
        }
    }
    gl_FragColor = vec4(0.0);
}
#define PI 3.14

precision mediump float;
varying vec2 vTextureCoord;
uniform sampler2D uSampler;

void main(void) {
    vec2 norm = vTextureCoord * 2.0 - 1.0;
    float theta = PI + atan(norm.x, norm.y);
    float r = length(norm);
    vec2 coords = vec2(theta / (2.0 * PI), r);
    gl_FragColor = texture2D(uSampler, coords);
}

The result can then be used as a mask for the light sprite to cut away everything, that lies in shadow. A small blur (or variable blur depending on the distance from the light) might be needed first, both for anti-aliasing and to create smooth shadows.

I'm still hardcoding the texture height. Currently, i see 2 alternatives: Either recreate the shader everytime the size of the light changes or set the loop boundary to a high number (maximum light size) and break out of it early, once the size (given as a uniform) has been reached.

Since those are shaders, i can only use one of them at a time and have to use a RenderTexture in between to store the result. I would like to use them as filters, instead, so i can just define 2 passes, but i haven't been able to correctly convert them, since filters seem to use a different coordinate system or something like that. I haven't been able to figure out, what i have to do.

Link to comment
Share on other sites

I'm using the exact same method to generate light maps. Using pixi v3 for it though.

My setup differs a bit though. I have a need for large amount of static lights, so what I do is generate 1x256 occlusion maps for all the lights once. Then render all lights to one large texture (2048x2048) and use it in post processing filter with normal map and diffuse map to generate final image.

My current solution for fixed length occlusion check is to have the occluders pretty large, so that when light ray overshoots the occluder I still know that occlusion has been hit and then I can traverse back to the point where occlusion should happen really.

Managed to get the shaders to run pretty fast by creating a custom container for the lights. Basically a copy of ParticleContainer with some additional attributes added. That way I can use same shader for multiple lights and render them in batches.

I also have few moving lights and they are given separately to the post processing filter. I map the position for moving lights like this:

 

vec2 uv = vTextureCoord.xy;
uv = coordinate/resolution + viewResolution/resolution*uv;
vec2 lightPos = lightCoordinate/resolution:
vec2 lightSize = resolution / lightResolution;
vec2 lightUv = (uv - lightPos) * lightSize;
vec4 light = texture2D(lightTexture, lightUv);

Coordinate is the world position.
ViewResolution is the size of the canvas.
lightCoordinate is the position of the light (in relation to world).
lightResolution is the resolution of single light.
resolution is the resolution of the whole scene (in my case 2048x2048).

Link to comment
Share on other sites

I have currently given up on the project, since PIXI 2.2.9 filters seem to be bugged when receiving additional textures as uniforms. Both textures are the same size, yet i can't see to select the exact same pixel in both. The predefined AlphaMaskFilter also doesn't work. Also, in this version i can't use sprites as masks, so the last step (creating the light) is currently impossible for me.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...