Cascaded shadow mapping - Texture lookup and depth comparison

I’m trying to implement cascaded shadow mapping in my game engine, but I’m somewhat stuck at the last step. For testing purposes I’ve made sure all cascades encompass my entire scene. The result is currently this:

At the top the texture of each cascade is displayed.
As you can see the shadows are rendered properly, however each cascade gets darker the bigger the area for the orthographic projection is. (Shouldn’t it get lighter instead?)

This is how I do the texture lookup for the shadow maps inside the fragment shader:


    layout(std140) uniform CSM
    {
    	vec4 csmFard; // far distances for each cascade
    	mat4 csmVP[4]; // View-Projection Matrix
    	int numCascades; // Number of cascades to use. In this example it's 4.
    };
    
    uniform sampler2DArrayShadow csmTextureArray; // The 4 shadow maps
    
    in vec4 csmPos[4]; // Vertex position in shadow MVP space
    
    float GetShadowCoefficient()
    {
    	int index = numCascades -1;
    	vec4 shadowCoord;
    	for(int i=0;i<numCascades;i++)
    	{
    		if(gl_FragCoord.z < csmFard[i])
    		{
    			shadowCoord = csmPos[i];
    			index = i;
    			break;
    		}
    	}
    	shadowCoord.w = shadowCoord.z;
    	shadowCoord.z = float(index);
    	shadowCoord.x = shadowCoord.x *0.5f +0.5f;
    	shadowCoord.y = shadowCoord.y *0.5f +0.5f;
    	return shadow2DArray(csmTextureArray,shadowCoord).x;
    }

Right now I’m simply using the return value and multiply it with the diffuse color. Since I’m grabbing the depth value directly from the texture, that explains the different coloration of each cascade on the world. So either this is the wrong approach, or my cascade textures are incorrect to begin with.
For that reason I ended up trying it with a depth comparison instead, but only had limited success:


    	[...] // Same code as above
    	shadowCoord.w = shadowCoord.z;
    	shadowCoord.z = float(index);
    	shadowCoord.x = shadowCoord.x *0.5f +0.5f;
    	shadowCoord.y = shadowCoord.y *0.5f +0.5f;
    	float z = shadow2DArray(csmTextureArray,shadowCoord).x;
    	if(z < shadowCoord.w)
    		return 0.25f;
    	return 1.f;
    }

While this resolves the different intensity of each cascade, it only works for the first cascade, all others are blank:

(I colored the cascades because otherwise the transitions wouldn’t be visible in this case)

What am I missing here?

Your second approach is not correct. Shadow samplers return 1 or 0, depending on the result of the compare operation. They will, however, return an averaged value if PCF is enabled by setting the sampling of the texture to LINEAR. You may find easier to debug shadowing by setting it to NEAREST so you ensure the behavior is the 0 or 1 return value.

This brings me to the possible problem: did you activate depth compare on your sampling parameters for your texture? Did you define the compare function? If you didn’t, I’m guessing the shadow sampler is just acting like a normal sampler and giving you the actual value on the texture, which means all you are doing at this point is projective texturing.

If you have, then what you may be seeing in your first image is simply heavy aliasing. I cannot really tell with this low resolution though. The banding that shows the different cascades could be due to the change in precision per cascade, so the aliasing has a different “pattern”, so to speak. You are projecting shadows of the plane on the plane itself. The non linear nature of the standard z buffer makes it a pain when it comes to precision.

I had the compare function set to GL_LEQUAL, but apparantly I forgot to actually enable it. The parameters are now:


glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_COMPARE_MODE,GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_COMPARE_FUNC,GL_LEQUAL);

Not entirely sure what I have to change in the shader. For now this is the result:

[ATTACH=CONFIG]721[/ATTACH] [ATTACH=CONFIG]722[/ATTACH]

Still got some trouble with this, but I’m a step further now. The reason for the different ‘brightness’ of the shadow for each cascade was because I hadn’t specified the compare mode for the textures:

glTexParameterf(GL_TEXTURE_2D_ARRAY,GL_TEXTURE_COMPARE_MODE,GL_COMPARE_REF_TO_TEXTURE);

However the addition of that parameter also resulted in this:
[video=youtube_share;JJN8EsXOPBk]http://youtu.be/JJN8EsXOPBk[/video]

So there’s still something else going wrong…