1

I am attempting to implement shadow mapping using opengl, using a directional light.

I have confirmed that the depth texture is correctly rendered, like so: depth texture

And to perform a visual inspection, I also output the world space coordinates, transformed to light perspective:

shadow coords

Which again, seems to be ok.

However, when I sample the depth texture, using:

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

I find that the comparison always fails. If I change uniform sampler2DShadow shadowMap; to uniform sampler2D shadowMap;, and sample the texture directly using texture( shadowMap, coord.xy).r, I find that the sampled value is always zero, by outputting this result to the screen.

I created the depth texture like so:

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);

and my shader code is as follows(vertex):

#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 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 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.xyz/shadowCoords.w);
    float depth = texture( shadowMap, vec3(coord.xy,coord.z+0.05));
    if (  depth < coord.z);
    {
        vis = 0.5;
    }
    return vis;
}
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 shadowCoord = ShadowTransform * pcolour;
    float visibility = computeOcclusion( shadowCoord );
    //float depth = texture(shadowMap, shadowCoord.xy).z;
    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);

}

Can anyone spot where this is going wrong?

Ian Young
  • 1,712
  • 1
  • 16
  • 33

2 Answers2

3

It turned out that my sampling was returning the correct value.

The real issue was a very fine grained shadow acne caused by culling the back faces of the geometry when rendering the depth map, and handling the return value from sampling the depth texture incorrectly.

I changed the sampling function to:

float computeOcclusion(vec4 shadowCoords)
{
    vec3 coord = vec3(shadowCoords.xyz/shadowCoords.w);
    float depth = texture( shadowMap, vec3(coord.xy,coord.z+0.001));
    return depth;
}

And changed my depth rendering gl client code to include:

glCullFace(GL_FRONT); 

Prior to rendering the geometry to the shadowMap.

Once this was done, I got the following result: final render

There are still some peter panning issues, but that's something I can deal with separately.

Ian Young
  • 1,712
  • 1
  • 16
  • 33
1

Problems like this are hard to spot so here are a few things that you need to take a look at:

  1. You are using a samplerShadow which is special in it's own way, you need to set COMPARE_R_TO_TEXTURE and with that you don't need that if statement. Alternatively you can use sampler2D, but you need to do an if statement in the shader, something similar to what you did, but the coord has to be vec2 not vec3

  2. consider using textureProj with vec4 texture coord. because it's much easier to transform world position in light space using a matrix multiplication. It's the same matrix that you use for rendering the shadow map in the first place. In your case it's this value vec4 shadowCoord = ShadowTransform * pcolour;; use shadowCoord directly with textureProj.

Raxvan
  • 6,257
  • 2
  • 25
  • 46
  • 1
    About 2: If you use a `sampler2D` instead of `sampler2DShadow`, you wouldn't be using PCF anymore. – BDL Apr 13 '17 at 10:30
  • Two things worked: removing the if statement and directly using the sampled depth, and calling glCullFace(GL_FRONT) before rendering the depth map. It appears that I had a very fine grain shadow acne problem, which wasn't easy to see. – Ian Young Apr 13 '17 at 11:16
  • Whilst the answer wasn't *exactly* right, it did give me food for thought and point me in the right direction, so thanks. – Ian Young Apr 13 '17 at 11:19
  • @Ian Young can you tell us the solution so we can post this for future reference ? – Raxvan Apr 13 '17 at 11:24
  • @Raxvan Yes, I'll do so in an answer of my own. – Ian Young Apr 13 '17 at 11:44