Issues with Shadow Mapping in GLSL

Howdy all, I’ve been trying to implement shadow mapping in GLSL for a few days now and I’m tantalisingly close.

I believe I have an issue transforming world space positions into my light’s view space.

The shadow appears to work perfectly for a quarter of the scene through the world y axis, but the other 270 degrees are borked up.

If I rotate my point light around the scene, the quadrant oposite my lights works, rotating with it and projecting the correct shadows.

Here’s a video better explaining my problem.

https://www.youtube.com/watch?v=4VOTmmHHbhw&feature=youtu.be

You might post some details about how you are building your world-space-to-light-space transform, including how you are determining the bounds of your world-space and light-space frusta.

That we apparently see shadows “striping” across the scene suggests to me that possibly your shadow frusta doesn’t encompass the world-space bounds of your scene, so there we may be seeing texture border behavior. What do you have your GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T on your shadow map set to? GL_CLAMP_TO_EDGE? Just for grins try changing them to REPEAT. This isn’t going to fix anything, but does it stop your shadows from “striping” across the scene. Alternatively, what if in the shader you treat shadow map tex coordinates outside of (0…1,0…1) as “no shadow”. That should allow you to more easily see where in your scene your shadow map is projecting to, given your world-to-light-space transform. Alternatively, color your scene by the shadow map texcoords, with areas outside the shadow map bounds being black or grey.

-Could you elaborate on what you mean by the shadow map tex coords?

My instinct was to clamp/repeat the clamping, but it doesn’t appear to be making any visible difference whatsoever -



 glm::mat4 lightProjection, lightView;
 glm::mat4 lightSpaceMatrix;
 GLfloat near_plane = 1.0;
 GLfloat far_plane = 8.5f;
 lightProjection = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane);

 lightView = glm::lookAt(lightPos, glm::vec3(0.0f), glm::vec3(0.0, 1.0, 0.0));

 lightSpaceMatrix = lightProjection * lightView; //light mvp


This is my set up for constructing the world to lightspace matrix.

Shadow_Frag



#version 330 core
out vec4 FragColor;

in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;

uniform mat4 MV;

uniform mat4 lightSpaceMatrix;

uniform sampler2D colourTex;
uniform sampler2D shadowTex;
uniform sampler2D positionTex;

uniform vec3 lightPos;
uniform vec3 viewPos;

float ShadowCalculation()
{

    //view space position
    vec4 wpos = vec4(texture(positionTex, TexCoords).rgb,1.0);

    FragColor = wpos;//just for visualizing the "light space coords"

    //NDC-space (not a problem with ortho projections)
    vec3 projCoords = wpos.xyz / wpos.w;

    // Transform to [0,1] range
    projCoords = projCoords * .5 + .5;

    // Get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
    float closestDepth = texture(shadowTex, projCoords.xy).r;

    //       return vec3(texture(shadowTex, closestDepth).r);
    // Get depth of current fragment from light's perspective
    float currentDepth = projCoords.z;


    // Check whether current frag pos is in shadow
    vec3 lightDir = normalize(lightPos - FragPos);

    float bias = max(0.05 * (1.0 - dot(Normal, lightDir)), 0.005);
    //float bias = .01;

    float shadow = 0.0;
    vec2 texelSize = 1.0 / textureSize(shadowTex, 0);
    for(int x = -1; x <= 1; ++x)
    {
        for(int y = -1; y <= 1; ++y)
        {
            float pcfDepth = texture(shadowTex, projCoords.xy + vec2(x, y) * texelSize).r;
            shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
        }
    }
    shadow /= 9.0;

   // keep the shadow at 0.0 when outside the far_plane region of the light's frustum.
    if(projCoords.z > 1.0)
        shadow = 0.0;

    return shadow;
}

void main()
{

    float shadow = ShadowCalculation();
    FragColor = vec4(texture(colourTex, TexCoords).rgb * (1-(shadow)),1.0);
    //FragColor = lightSpaceMatrix*vec4(1);
}
}

Shadow_Vert


layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoords;
layout (location = 2) in vec3 normal;


out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoords;

uniform mat4 P;
uniform mat4 V;
uniform mat4 M;
uniform mat3 N; // This is the inverse transpose of the mv matrix

uniform mat4 MV;
uniform mat4 MVP;

void main()
{
    gl_Position = MVP * vec4(position, 1.0);;

    Normal = normalize(N * normal);

    TexCoords = texCoords;
}

and when writing my position to lightspace to my sampler texture I perform the output:


    // Compute the position of the vertex
    gl_Position = MVP * vec4(VertexPosition,1.0);

Appologies for the large code dump.

I would be trustful of my shader however I’m doing the lightspace transformation on the vertex shader where I grab my positions from instead of the shadow vertex shader - this might be a mistake.

The texture coordinates you use to lookup into the shadow map with. The first occurrance in your fragment shader is: projCoords.xy

Until you have basic shadow mapping working, I’d comment out all that multi-sampling the shadow map stuff (PCF) you’ve got going on in your frag shader. Just sample it once, and then display the result of that on-screen. You can get fancy later.

Also, don’t have much time right now, but just scanning your shader I don’t see any reasonable logic to transform the input position from WORLD or CAMERA-EYE space to LIGHT-CLIP space to perform the shadow lookup. Unless I’m missing it, you need to add that.