I’m still a bit unsure about the implementation of cascaded shadow mapping.
This is what it looks like at the moment:
At the top left are the 4 cascades - All of them encompass the same area for testing purposes.
This is without GL_COMPARE_REF_TO_TEXTURE, so all I’m doing is a depth lookup into the shadow map and multiplying the result with the diffuse fragment color. (Hence the different shadow intensities)
If I activate the comparison by setting the compare mode to GL_COMPARE_REF_TO_TEXTURE, this is the result:
This works, however, as you can see in the screenshot, there are several shadows that obviously don’t belong there.
Here are my shaders:
Vertex Shader:
#version 330 core
layout(location = 0) in vec4 vertPos;
layout(location = 1) in vec2 vertexUV;
layout(std140) uniform ViewProjection
{
mat4 M;
mat4 V;
mat4 P;
mat4 MVP;
};
out vec4 Position_worldspace;
out vec4 Position_cameraspace;
out vec2 UV;
void main()
{
gl_Position = MVP *vertPos;
Position_worldspace = M *vertPos;
Position_cameraspace = V *M *vertPos;
UV = vertexUV;
}
Fragment Shader:
#version 330 core
layout(std140) uniform CSM
{
vec4 csmFard;
mat4 csmVP[4];
int numCascades;
};
uniform sampler2D diffuseMap;
uniform sampler2DArrayShadow csmTextureArray;
in vec4 Position_worldspace;
in vec4 Position_cameraspace;
in vec2 UV;
out vec4 color;
float GetShadowTerm(sampler2DArrayShadow shadowMap)
{
int index = numCascades -1;
mat4 vp;
for(int i=0;i<numCascades;i++)
{
if(gl_FragCoord.z < csmFard[i])
{
vp = csmVP[i];
index = i;
break;
}
}
vec4 shadowCoord = vp *Position_worldspace;
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(shadowMap,shadowCoord).x;
}
void main()
{
color = texture2D(diffuseMap,UV).rgba;
color.rgb *= GetShadowTerm(shadowMap);
}
This is essentially the same implementation as described in this document.
The only note-worthy difference, as far as I can tell, is in their shadow-map-lookup function:
float shadowCoef()
{
int index = 3;
// find the appropriate depth map to look up in
// based on the depth of this fragment
if(gl_FragCoord.z < far_d.x)
index = 0;
else if(gl_FragCoord.z < far_d.y)
index = 1;
else if(gl_FragCoord.z < far_d.z)
index = 2;
// transform this fragment's position from view space to
// scaled light clip space such that the xy coordinates
// lie in [0;1]. Note that there is no need to divide by w
// for othogonal light sources
vec4 shadow_coord = gl_TextureMatrix[index]*vPos;
// set the current depth to compare with
shadow_coord.w = shadow_coord.z;
// tell glsl in which layer to do the look up
shadow_coord.z = float(index);
// let the hardware do the comparison for us
return shadow2DArray(stex, shadow_coord).x;
}
More specifically, this line in particular:
vec4 shadow_coord = gl_TextureMatrix[index]*vPos;
They’re using the view-space position, where I’m using the world-space position. In my case it only looks “right” with the world-space position, I can only guess that means my shadow matrices are incorrect?
The projection matrix for all cascades is currently calculated like this:
glm::vec3 min(-1024.f,-512.f,-1024.f); // Area, in which all shadow casters are located
glm::vec3 max(1024.f,512.f,1024.f);
glm::mat4 matProj = glm::ortho(min.z,max.z,min.x,max.x,-max.y,-min.y);
As for the view matrix:
glm::vec3 pos = glm::vec3(176.f,432.f,-390.f);
glm::vec3 dir = glm::vec3(0.f,-1.f,0.f);
glm::mat4 matView = glm::lookAt(
pos,
pos +dir,
glm::vec3(1.f,0.f,0.f)
);
‘pos’ being the origin of the light (Which shouldn’t matter(?), since we’re using an orthographic projection), and ‘dir’ is its direction (Straight down).
What am I missing?