2
\$\begingroup\$

I'm attempting to implement Shadow mapping in opengl/GLSL and have encountered a problem with sampling the shadow map itself.

I have confirmed that the shadow map is correctly rendered:

Depth render

However, when I attempt to sample it in my shader, the output is always zero (or appears to be zero).

My vertex shader:

#version 430
// Some drivers require the following
precision highp float;
layout (location = 0)in vec3 MSVertex;
layout (location = 4)in vec2 MSTexCoord;

out xferBlock
{
    vec3 VSVertex;
    vec2 VSTexCoord;
} outdata;

void main()
{
    outdata.VSVertex = MSVertex;
    outdata.VSTexCoord = MSTexCoord;
    gl_Position = vec4(MSVertex,1.0);
}

And my fragment shader:

#version 430 core
// Some drivers require the following
precision highp float;

layout (location = 0) uniform sampler2D positionMap;
layout (location = 1) uniform sampler2D normalMap;
layout (location = 2) uniform sampler2D colourMap;
layout (location = 3) uniform sampler2D specularMap;
layout (location = 4) uniform sampler2D glowMap;
layout (location = 5) uniform sampler2DShadow shadowMap;

struct DirLightData
{
    vec4 colour;
    float intensity;
    vec4 direction;
};
uniform mat4 ShadowTransform;
uniform DirLightData dirLight;
out vec4 colour;
uniform vec3 WSCamPos;
in xferBlock
{
    vec3 VSVertex;
    vec2 VSTexCoord;
} indata;

vec3 computeLight(vec3 Ldirection, vec3 Vdirection, vec3 Lcolour, vec3 normal, float Lintensity, float specular)
{
    vec3 diffCol = Lcolour * max(0.0,dot(normalize(normal),-Ldirection));
    vec3 reflectVec = normalize(reflect(Ldirection,normal));
    float specFactor = max(dot(reflectVec,Vdirection),0);
    float specPow = pow(specFactor,specular*255.0);
    vec3 specCol = Lcolour * specPow;
    return (diffCol+specCol)*Lintensity;;
}
float computeOcclusion(vec4 shadowCoords)
{
    float vis = 1.0;
    vec3 coord = vec3(shadowCoords.xy,shadowCoords.z/shadowCoords.w);
    float depth = texture( shadowMap, coord);
    if (  depth < coord.z );
    {
        vis = 0.5;
    }
    return depth;
}
void main()
{
    vec4 pcolour = texture(positionMap, indata.VSTexCoord).rgba;
    vec4 ncolour = texture(normalMap, indata.VSTexCoord).rgba;
    vec4 dcolour = texture(colourMap, indata.VSTexCoord).rgba;
    vec4 scolour = texture(specularMap, indata.VSTexCoord).rgba;
    vec4 gcolour = texture(glowMap, indata.VSTexCoord).rgba;
    vec4 shadowCoord = ShadowTransform * pcolour;
    float visibility = computeOcclusion( shadowCoord );
    vec3 vToEye = WSCamPos - pcolour.xyz;
    vToEye = normalize(vToEye);
    vec3 outColour = vec3(0.0,0.0,0.0);

    outColour = computeLight(dirLight.direction.xyz,vToEye,dirLight.colour.rgb,ncolour.rgb,dirLight.intensity,scolour.r);
    colour = vec4(visibility*(dcolour.rgb*outColour),1.0);

}

I have confirmed that the lighting, sans shadow map, works just fine. I've also tried defining the shadow map as a regeular sampler2D, and using float depth = texture( shadowMap, coord.xy);, with the same results.

After some additional research, I found that:

    vec3 coord = vec3(shadowCoords.xy,shadowCoords.z/shadowCoords.w);
    float depth = texture( shadowMap, coord);

is actually a depth comparison, of the world space coordinates, transformed to the light's perspective, which (if I understand it correctly) returns 1.0 or 0.0, indicating if the fragment passes or fails the depth comparison.

In this case, the fragment always fails the comparison.

To get a better idea, I output the z component of the transformed world space coordinates:

shadow coords

As you can see, it looks like there are some minor discrepencies in the z value.

I'm not sure how to fix this. Perhaps it is related to how I created the depth attachment?

glGenFramebuffers(1, &m_FBOName);
glBindFramebuffer(GL_FRAMEBUFFER, m_FBOName);

// Depth texture. Slower than a depth buffer, but you can sample it later in your shader
glGenTextures(1, &m_DepthTexture);
glBindTexture(GL_TEXTURE_2D, m_DepthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_DepthTexture, 0);
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

The issue was that I had to change the occlusion function in my shader to:

float computeOcclusion(vec4 shadowCoords)
{

    vec3 coord = vec3(shadowCoords.xy,shadowCoords.z/shadowCoords.w);
    float depth = texture( shadowMap, coord);
    return depth;
}

And, I had to add glCullFace(GL_FRONT) to the client code, right before I started rendering to the depth texture, as without it, small accuracy discrepancies like the one's in the image caused everything to be in shadow.

\$\endgroup\$
1
  • \$\begingroup\$ Don't forget to mark this answer as accepted when you get the chance :) \$\endgroup\$
    – Vaillancourt
    Apr 13, 2017 at 15:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .