[OpenGL] Cascaded shadow mapping - Render shadows to world?

Started by
26 comments, last by Silverlan 9 years, 6 months ago

Still haven't figured this out. I've went through the Nvidia CSM Tutorial again, which I based my code mostly on, but they are doing pretty much exactly what I am. Their sample program results in similar cascades as my code does, so I'm pretty sure it's the final shader (For the main scene) which is messing things up.

Their shader looks like this:


uniform sampler2D tex; // terrain texture
uniform vec4 far_d; // far distances of
 // every split
varying vec4 vPos; // fragment’s position in 
// view space
uniform sampler2DArrayShadow stex; // depth textures
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; 
} 
void main() 
{ 
    vec4 color_tex = texture2D(tex, gl_TexCoord[0].st); 
    float shadow_coef = shadowCoef(); 
    float fog_coef = clamp(gl_Fog.scale*(gl_Fog.end + vPos.z), 0.0, 1.0); 
    gl_FragColor = mix(gl_Fog.color, (0.9 * shadow_coef * gl_Color * color_tex + 0.1), fog_coef); 
} 

Which is essentially the same as my shader above.

I'm at a complete loss...

Advertisement

Are you sure you properly set uniform values for gl_TextureMatrix[1] and [2] ? I would rather use explicitly declared matrixes for this.

Are you sure you properly set uniform values for gl_TextureMatrix[1] and [2] ? I would rather use explicitly declared matrixes for this.

I'm using my own uniforms, in my case "csmMatrices" represents the "gl_TextureMatrix" that's being used in the Nvidia shader.


// Extract from my vertex shader
layout(std140) uniform ViewProjection
{
	mat4 M; // Model Matrix
	mat4 V; // View Matrix
	mat4 P; // Projection Matrix
	mat4 MVP;
};

layout(location = 0) in vec4 vertPos;

// CSM Test
uniform mat4 csmMatrices[3];
out vec4 csmPos[3];

[...] Inside the main function:
	csmPos[0] = csmMatrices[0] *(M *vertPos);
	csmPos[1] = csmMatrices[1] *(M *vertPos);
	csmPos[2] = csmMatrices[2] *(M *vertPos);

"csmPos" is equivalent to the "shadow_coord" from Nvidias shader, I'm just calculating it on the vertex shader instead of the fragment shader.

I think the issue is here :


The return value from GetShadowCoefficient is literally just multiplied with the diffuse color. I've tried a comparison like so:
[...]
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;
However that only gives me proper results for the first cascade, after that it's just cut off:

Assuming the sampler mode is GL_NEAREST, shadow2DArray returns either 0. ("false") if the comparaison test fails or 1. ("true") if the comparaison test succeed.

If the sampler mode is GL_LINEAR then the 0./1. from neighbour texels are interpolated linearly.

I don't understand the "if(z < shadowCoord.w)" statement since you're comparing a "bool" (the result of a comparison) with a depth value.

I think you should use "return z;" directly.

Assuming the sampler mode is GL_NEAREST, shadow2DArray returns either 0. ("false") if the comparaison test fails or 1. ("true") if the comparaison test succeed.

If the sampler mode is GL_LINEAR then the 0./1. from neighbour texels are interpolated linearly.

I don't understand the "if(z < shadowCoord.w)" statement since you're comparing a "bool" (the result of a comparison) with a depth value.

I think you should use "return z;" directly.

That's what I did before, which essentially had the same results:

ede72cd73d.jpg

The texture parameters for the cascades are:


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_FUNC,GL_LEQUAL);
glReadBuffer(GL_NONE);
glDrawBuffer(GL_NONE);

What is wrong with this picture ?

To have better result with self shadowing you need to use a bias or polygon offset.

What is wrong with this picture ?

To have better result with self shadowing you need to use a bias or polygon offset.

The different 'intensity' of the shadow between the cascades is what I'm trying to get rid of. You can see that the shadows on each cascade are darker than in the previous one.

I suspect there is some z fighting here.
What happens if you add a small offset to shadowcoord.w before sampling ?

I suspect there is some z fighting here.
What happens if you add a small offset to shadowcoord.w before sampling ?

That's... odd. I can change the 'w' component to anything, 1, 0, any value inbetween, negative values - It literally changes nothing, the result is always the same as in the screenshot I posted.

I assume that means something's wrong with the actual shadow map textures?

Did you set GL_TEXTURE_COMPARE_MODE too ? eg

glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE)

This topic is closed to new replies.

Advertisement