Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 10 of 15

Thread: CSM / PSSM - Depth comparison

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Intern Newbie
    Join Date
    Dec 2012
    Posts
    40

    Question CSM / PSSM - Depth comparison

    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:
    Code :
    #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:
    Code :
    #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:
    Code :
    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:
    Code :
    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:
    Code :
    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:
    Code :
    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?

  2. #2
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    4,224
    Quote Originally Posted by Silverlan View Post
    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.
    Why do you say that? Since your walls are very thin, if the light source is directly above, the result looks like it could be correct to me.

    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?
    There's no single golden way to build a shadow coordinate transform matrix. A matrix is just a transform from one coordinate space to another. You can build a transform (matrix) from world-space to the light's clip-space, and then multiply world-space positions by it. Or you can build a transform from camera eye-space to the light's clip-space, and then multiply camera eye-space positions by it. Just be consistent.

    The reason that world-space isn't commonly used as the source coordinate space for shadow coordinate transforms is that quite often the shader doesn't do any operations in world space at all! Sometimes it can't; for instance, if world-space is too big to represent with single-precision floats to the desired spatial accuracy. So often what you do will be to use your MODELVIEW transform to get the positions fed into the shader into eye-space, and then your shadow transform will take it from there into light's clip-space.

  3. #3
    Intern Newbie
    Join Date
    Dec 2012
    Posts
    40
    Quote Originally Posted by Dark Photon View Post
    Why do you say that? Since your walls are very thin, if the light source is directly above, the result looks like it could be correct to me.
    The walls have the same width as the small block near the center of the image.
    If I move the 'origin' of the light source upwards, the artifacts become even more noticable:


    I still get the same effect if I increase the size of one of the blocks:
    http://puu.sh/es4z7/b23f755655.jpg

    In the above case the bounds of the projection matrix didn't quite encompass all objects, but even if I increase the bounds on the y-axis to encompass all of them, some of the artifacts stay:
    http://puu.sh/es4V9/2776317fb8.jpg

    What could be the cause of that?

    Quote Originally Posted by Dark Photon View Post
    There's no single golden way to build a shadow coordinate transform matrix. A matrix is just a transform from one coordinate space to another. You can build a transform (matrix) from world-space to the light's clip-space, and then multiply world-space positions by it. Or you can build a transform from camera eye-space to the light's clip-space, and then multiply camera eye-space positions by it. Just be consistent.

    The reason that world-space isn't commonly used as the source coordinate space for shadow coordinate transforms is that quite often the shader doesn't do any operations in world space at all! Sometimes it can't; for instance, if world-space is too big to represent with single-precision floats to the desired spatial accuracy. So often what you do will be to use your MODELVIEW transform to get the positions fed into the shader into eye-space, and then your shadow transform will take it from there into light's clip-space.
    I've always wondered about that. Thanks, that makes a lot more sense now.

  4. #4
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    4,224
    Quote Originally Posted by Silverlan View Post
    If I move the 'origin' of the light source upwards, the artifacts become even more noticable:
    Oh, I think I understand what you're talking about now. You didn't say what you meant by "there are several shadows that obviously don't belong there". Do you mean the self-shadows on the lower-half of the objects? If you change the light source direction, does the artifact go away?

    If the light source is truly overhead in this case, typically you wouldn't see this shadowing artifact very prominently. The object is shadowing itself slightly due to the light source not being straight up, the box sides not being straight up, floating point imprecision, or something. The reason this wouldn't be very prominent is diffuse has an N*L term, which in this case would be ~cos(90) == 0. So when you shadow the diffuse component, you're attenuating a diffuse of 0, so it doesn't really make any difference. Specular is generally clamped or attenuated in this case too.

  5. #5
    Intern Newbie
    Join Date
    Dec 2012
    Posts
    40
    Quote Originally Posted by Dark Photon View Post
    Oh, I think I understand what you're talking about now. You didn't say what you meant by "there are several shadows that obviously don't belong there". Do you mean the self-shadows on the lower-half of the objects? If you change the light source direction, does the artifact go away?

    If the light source is truly overhead in this case, typically you wouldn't see this shadowing artifact very prominently. The object is shadowing itself slightly due to the light source not being straight up, the box sides not being straight up, floating point imprecision, or something. The reason this wouldn't be very prominent is diffuse has an N*L term, which in this case would be ~cos(90) == 0. So when you shadow the diffuse component, you're attenuating a diffuse of 0, so it doesn't really make any difference. Specular is generally clamped or attenuated in this case too.
    Thank you, that makes sense, I'll have to do some more testing on that.
    However, that doesn't explain this behavior:
    http://youtu.be/1sghFGdwZVQ

    The bounds of the projection matrix go beyond the floor, so it shouldn't disappear like you can see at about 0:05.
    The shadow on the block only appears if I move a fair bit away from it.
    Both of these still look like a depth comparison problem to me?

  6. #6
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    4,224
    What I see in the video is that your shadow frusta are not encompassing all potential casters. Ensure that your shadow caster cull is going back far enough to catch them all. The shadow frusta is what is used to determine your shadow projection transforms. Make sure that your shadow frusta projections encompass the casters. Later on you can experiment with things like capping it to the bounds of the view frustum.

    Also, how your eyepoint model (a person?) is casting shadows on the ground but then not on the block -- that's interesting. Possibly a shadow split difference. You need to think about how you're going to handle this case (where objects cast shadows into multiple splits). Are you casting them into all splits now? It would suggest that perhaps that eyepoint model is being cast into some shadow splits but not others. For starters, suggest you cast all objects than potentially cast shadows into a split, even if it means they're cast into multiple splits.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •