Shadow Map Self Shadow Problem

Started by
5 comments, last by PSS 15 years, 1 month ago
I have two problems, which may be related. Problem 1: When projecting a shadow map on the terrain, object shadows seem to be properly casted, though the terrain is self shadowing. Problem 2: Objects are ALWAYS in shadow, though the exact same calculations as the terrain are being applied. I've messed around ALOT with depth bias, and I'm convinced that bias is not where the issue lies. I've also tried culling and not culling the front faces, though the effects are even less accurate. I've also tried using 'CLAMP' instead of 'BORDER', though it doesn't fix the issue and it adds a 'stretching' problem. This is the code to project the shadow map:

sampler2D vSamSMaps[1] =
{
	sampler_state
	{
		Texture = <gvShadowTexture>;
		MinFilter = POINT;
		MagFilter = POINT;
		MipFilter = POINT;
		AddressU = BORDER;
		AddressV = BORDER;
	}
};

/**
@brief	Calculate the single source shadows for the light source provided
@param	fvLVPPos, the position of the pixel in light's view projection * world matrix
@param	fvLIndex, the light's index*/
float CalcShadows( float4 fvLVPPos, int fvLIndex )
{
	//Project the texture coords and scale/offset to [0, 1].
	float4 tvProjTex = fvLVPPos;
	tvProjTex.xy /= tvProjTex.w;            
	tvProjTex.x =  0.5f * tvProjTex.x + 0.5f; 
	tvProjTex.y = -0.5f * tvProjTex.y + 0.5f;
	
	// Compute pixel depth for shadowing.
	float tvDepth = tvProjTex.z / tvProjTex.w;
 
	// Transform to texel space ( NOTE: SMAP_SIZE HARDCODED TO 1024 FOR NOW ) 
        float2 tvTexelpos = SMAP_SIZE * tvProjTex.xy;
        
        // Determine the lerp amounts.           
        float2 tvLerps = frac( tvTexelpos );
    
        // 2x2 percentage closest filter.
        float dx = 1.0f / SMAP_SIZE;
	float s0 = step(tvDepth, tex2D(vSamSMaps[fvLIndex], tvProjTex.xy).r + SHADOW_EPSILON);
	float s1 = step(tvDepth, tex2D(vSamSMaps[fvLIndex], tvProjTex.xy + float2(dx, 0.0f)).r + SHADOW_EPSILON);
	float s2 = step(tvDepth, tex2D(vSamSMaps[fvLIndex], tvProjTex.xy + float2(0.0f, dx)).r + SHADOW_EPSILON);
	float s3 = step(tvDepth, tex2D(vSamSMaps[fvLIndex], tvProjTex.xy + float2(dx, dx)).r + SHADOW_EPSILON);
	
	return lerp( lerp( s0, s1, tvLerps.x ), 
				 lerp( s2, s3, tvLerps.x ), 
				 tvLerps.y );
}


Advertisement
Has anyone had a similar problem? What was the solution?
I'm really just looking for a hint, or a guess. I'm all out of ideas and my searches keep returning the same results.

The projected texture parameter (float4 fvLVPPos) passed into the function is:

vertex shader's 'in' position, multiplied by the world matrix * light's view matrix * light's projection matrix

//Projected texture is position in worldViewProjection of the lightfloat4x4 tvMatLightWVP = mul( vMatLightVP, gvMatWorld );Output.ProjTex = mul( float4( Input.Position, 1.0f ), tvMatLightWVP );
Do you have the same problem if you throw out your PCF and simply return the result of the shadow test?

What happens if you add more bias?

What are your light frustum's near- and far plane?

Wild guess: Maybe your light's far z is too large and you therefore lack precision.

[Edited by - DraganO on March 18, 2009 2:48:01 AM]
Thank you for the reply,

When I throw out PCF, the results are the same, only lower quality shadows for the trees and buildings.

When I add more bias, the good shadows disappear before the bad self shading goes away. Meaning the trees no longer cast shadows, but the ground under the trees still do (though the ground should be lit).


I changed the 'step' to the Microsoft sample's code:
return (tex2D(vSamSMaps[fvLIndex], tvProjTex.xy).r + SHADOW_EPSILON &lt; tvDepth) ? 0.0f : 1.0f

and when playing with the bias, I ended up with the following:



Note: This is without pcf, no culling.
Notice that some of the shadows are correct, though some are inverted, and others are plain wrong.

My light's near clip is 1.0, and far is 5000.0. I played around with this (lowering to 1000, 500, 100), but it didn't seem to have any effect.
Quote:Original post by PSS

The projected texture parameter (float4 fvLVPPos) passed into the function is:

vertex shader's 'in' position, multiplied by the world matrix * light's view matrix * light's projection matrix

//Projected texture is position in worldViewProjection of the lightfloat4x4 tvMatLightWVP = mul( vMatLightVP, gvMatWorld );Output.ProjTex = mul( float4( Input.Position, 1.0f ), tvMatLightWVP );



Why are you multiplying the World and ViewProj matrices in column fashion (right to left)? Shouldn't it be mul(World, ViewProj)?
Quote:Original post by glaeken

Why are you multiplying the World and ViewProj matrices in column fashion (right to left)? Shouldn't it be mul(World, ViewProj)?


That was a mistake, thank you for finding it. It has improved the conditions of problem #2, though after much tweaking of the bias and culling, problem #1 is still an issue.

Other than the bias, culling and clipping planes, is there anything else I should be tweaking?

This is what it looks like now (notice that the trees and buildings are looking much closer to the desired result):



Thanks for the help so far


Well now, I'm even more confused. After messing around with a lot of this, I decided I would disable shadow mapping the terrain (so only objects would be stored in the depth map), this is the result:



3 problems:
1) the tree shadows should not be projected on the hill (the hill is closer to the light source than the trees)

2) white is black, black is white

3) The objects will be selfshadowed, before the shadows project properly (related to 1, I believe), regardless of the bias

I don't understand what's happening here, is the depth map inverted? (I'm using D3DFMT_R32F). Any hints?


Note: The code has not changed from the above, except for bias changes and not saving terrain depths. I'm using the shadow map DX sample, provided by the Directx August 2008 SDK as a guide

This topic is closed to new replies.

Advertisement