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
\$\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\$
  • \$\begingroup\$ Don't forget to mark this answer as accepted when you get the chance :) \$\endgroup\$ – Vaillancourt Apr 13 '17 at 15:39

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.