Silverlan

01-11-2015, 06:07 AM

I'm still a bit unsure about the implementation of cascaded shadow mapping.

This is what it looks like at the moment:

https://puu.sh/emP0l/e405322704.jpg (https://puu.sh/emP09/368c46074e.jpg)

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:

https://puu.sh/emP0R/5bbce28fd2.jpg (https://puu.sh/emP0N/9f3c8652ce.jpg)

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 (http://developer.download.nvidia.com/SDK/10.5/opengl/src/cascaded_shadow_maps/doc/cascaded_shadow_maps.pdf).

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?

This is what it looks like at the moment:

https://puu.sh/emP0l/e405322704.jpg (https://puu.sh/emP09/368c46074e.jpg)

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:

https://puu.sh/emP0R/5bbce28fd2.jpg (https://puu.sh/emP0N/9f3c8652ce.jpg)

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 (http://developer.download.nvidia.com/SDK/10.5/opengl/src/cascaded_shadow_maps/doc/cascaded_shadow_maps.pdf).

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?