Sign in to follow this  
IMYT

Shadow map problem

Recommended Posts

Hello everyone, I am new to shadow map and recently I and working on the implementation of a simple shadow map algorithm. I get shadows, that is fine, but the problem is that I can only see those shadows when I am inside the light cone. If the camera is moved out of the light cone, all the lit area will be black.

Here is my shader:
[code]
//Caster Shader Programs
extern float4x4 gLightView;
extern float4x4 gLightProj;

struct VS_INPUT_CASTER
{
float3 position : POSITION;
};

struct VS_OUTPUT_CASTER
{
float4 position : POSITION;
float2 depth : TEXCOORD0;
};

VS_OUTPUT_CASTER casterVS(VS_INPUT_CASTER input)
{
VS_OUTPUT_CASTER output;
float4 finalPos = mul(float4(input.position,1.0),gLightView);
finalPos = mul(finalPos,gLightProj);
output.position = finalPos;
output.depth.xy = finalPos.zw;
return output;
}

float4 casterPS(VS_OUTPUT_CASTER input) : COLOR
{
return input.depth.x / input.depth.y;
}

//Receiver Shader Programs

extern float4x4 gCameraView;
extern float4x4 gCameraProj;
extern float4 gLightColor;
extern float4 gLightAmbient;
extern float3 gLightPos;
extern float3 gLightDir;
extern float gCosTheta;
extern texture gShadowTexture;
extern texture gSurfaceTexture;

sampler2D gShadow =
sampler_state
{
Texture = <gShadowTexture>;
MinFilter = Point;
MagFilter = Point;
MipFilter = Point;
AddressU = Clamp;
AddressV = Clamp;
};

sampler2D gSurface =
sampler_state
{
Texture = <gSurfaceTexture>;
};

struct VS_INPUT_RECEIVER
{
float3 position : POSITION;
float3 normal : NORMAL;
float2 texcoord : TEXCOORD;
};

struct VS_OUTPUT_RECEIVER
{
float4 position : POSITION;
float2 texcoord : TEXCOORD0;
float4 worldPos : TEXCOORD1;
float3 worldNormal : TEXCOORD2;
};

VS_OUTPUT_RECEIVER receiverVS(VS_INPUT_RECEIVER input)
{
VS_OUTPUT_RECEIVER output;
float4 finalPos = mul(float4(input.position,1.0),gCameraView);
finalPos = mul(finalPos,gCameraProj);
output.position = finalPos;
output.texcoord = input.texcoord;
output.worldNormal = input.normal;
output.worldPos = float4(input.position,1.0);
return output;
}

float4 receiverPS(VS_OUTPUT_RECEIVER input) : COLOR
{
float4 color = float4(0,0,0,1);
float4 lightSpacePos = mul(input.worldPos,gLightView);
lightSpacePos = mul(lightSpacePos,gLightProj);
lightSpacePos.xyz /= lightSpacePos.w;
lightSpacePos.xy = lightSpacePos.xy*0.5 + float2(0.5,0.5);
lightSpacePos.y = 1.0 - lightSpacePos.y;
float3 lightToPos = input.worldPos.xyz - gLightPos;
lightToPos = normalize(lightToPos);
float cosVal = dot(lightToPos,gLightDir);
float4 texColor = tex2D(gSurface,input.texcoord);
if (cosVal > gCosTheta)
{
float diffuseFactor = -dot(input.worldNormal,gLightDir);
float shadowFactor = (tex2D(gShadow,lightSpacePos.xy)+0.0005 < lightSpacePos.z) ? 0.0 : 1.0;
color += diffuseFactor*float4(gLightColor.x*texColor.x,gLightColor.y*texColor.y,gLightColor.z*texColor.z,1.0);
color *= shadowFactor;
color += float4(gLightAmbient.x*texColor.x,gLightAmbient.y*texColor.y,gLightAmbient.z*texColor.z,1.0);
}
else
{
color += float4(gLightAmbient.x*texColor.x,gLightAmbient.y*texColor.y,gLightAmbient.z*texColor.z,1.0);
}
return color;
}

technique ShadowTech
{
Pass P0
{
vertexShader = compile vs_3_0 casterVS();
pixelShader = compile ps_3_0 casterPS();
}
}

technique SceneTech
{
Pass P0
{
vertexShader = compile vs_3_0 receiverVS();
pixelShader = compile ps_3_0 receiverPS();
}
}[/code]

Can any tell me what is wrong with my code? Thanks.

Share this post


Link to post
Share on other sites
Hello everyone:
I am sorry for posted the complete shader code which may make the problem extremely difficult for you guys to solve. I will try to explain my code a bit.

The code which calculates the shadow map is very simple, I just render the scene from the light's view and record the z-depth value. I format I used for my shadow texture is D3DFMT_R32F.
Vertex Shader for this part:
[code]
finalPos = mul(input.pos, gLightWVP);

output.position = finalPos;
output.depth.xy = finalPos.zw;
[/code]
Pixel Shader for this part:
[code]
return input.depth.x / input.depth.y;
[/code]

When rendering the scene I first pass the position and normal of the vertex into the pixel shader:
[code]

output.worldPos = float4(input.position,1.0);
output.worldNormal = input.normal;
[/code]

In the pixel shader I calculate the position in the light view(lightSpacePos).
[code]
float4 lightSpacePos = mul(input.worldPos,gLightView);
lightSpacePos = mul(lightSpacePos,gLightProj);
[/code]

and transform the coordinates into texcoord for shadow rendering:
[code]

lightSpacePos.xyz /= lightSpacePos.w;
lightSpacePos.xy = lightSpacePos.xy*0.5 + float2(0.5,0.5);
lightSpacePos.y = 1.0 - lightSpacePos.y;
[/code]

The depth information is calculated by following code:
[code]
float shadowFactor = (tex2D(gShadow,lightSpacePos.xy)+0.0005 < lightSpacePos.z) ? 0.0 : 1.0;
[/code]

and this depth information is used in the calculation of output color for the pixel shader.

I my program you can find a variable named "lightToPos", this variable is used for calculating which part of the scene is covered by the light cone and has nothing to do with shadow mapping itself.

If any of you need further explanation of the code please tell me. Thanks.

Share this post


Link to post
Share on other sites
Hi,

I've had a quick scan and I can't see anything wrong with the shadow mapping code. Are gLightPos and gLightDir constant regardless of camera position? The fact that your shadow mapping works when the camera is in the cone makes me think that they are connected. Have you tried running the app through PIX? It's a good tool for solving bugs like this. I'll keep on thinking and post back if I notice anything else.

T

Share this post


Link to post
Share on other sites
Hm... I just went quickly through the code and ... it seems okay - so maybe it is not a bug inside shader code (it is possible).

I'd make sure if your texture really gets rendered inside framebuffer (if you not get any framebuffer issue).
I'd also check if matrices are okay and texture gets projected correctly (it probably doesn't).

I'd check your code, but I'm not able - I work only on linux workstations and it is not possible to use DirectX here. Although your shaders seem okay, so I'd search for issue somewhere else.

Share this post


Link to post
Share on other sites
Like the other posters, I don't see anything wrong with the shader code. I would check that the texture coordinates for the shadow map are in range. Maybe do

bool bInRange = lightSpacePos.x >= 0.0f && lightSpacePos.x <=1.0f && lightSpacePos.y >= 0.0f && lightSpacePos.y <=1.0f
if( !bInRange ) return float4( 1.0f, 0.0f, 0.0f, 1.0f ); // bright red

If you see red, then you have sampled outside the shadow map (and then the results depend on the wrap/clamp/border mode). This should not be the problem, because the lightSpacePos should be the same, whether the camera is inside or outside the light cone. But it still seems like a good test to run.

Share this post


Link to post
Share on other sites
[quote name='davidleonardcook' timestamp='1298665988' post='4779092']
Like the other posters, I don't see anything wrong with the shader code. I would check that the texture coordinates for the shadow map are in range. Maybe do

bool bInRange = lightSpacePos.x >= 0.0f && lightSpacePos.x <=1.0f && lightSpacePos.y >= 0.0f && lightSpacePos.y <=1.0f
if( !bInRange ) return float4( 1.0f, 0.0f, 0.0f, 1.0f ); // bright red

If you see red, then you have sampled outside the shadow map (and then the results depend on the wrap/clamp/border mode). This should not be the problem, because the lightSpacePos should be the same, whether the camera is inside or outside the light cone. But it still seems like a good test to run.
[/quote]

Thanks for your suggestions.

I checked the texture coordinates use your method before, it seems that they are in range.

Share this post


Link to post
Share on other sites
It seems to me that some depths value stored in the shadow map will become 0 when the camera moves out of the light cone. I don't know why the shadow map rendering is influenced by the camera position. I did not use any camera space transform when rendering the shadow map.

Share this post


Link to post
Share on other sites
Hello everyone:

I find a very strange behavior of my code. I did three things:

1. I checked the shadow texture coordinate, it seems to me that they are between 0 and 1, so the texture coordinates should be correct.
2. I checked tex(gShadow,lightSpacePos.xy), in some part of the scene (inside the light cone) this value is 0, and this zero value cause the lit area to be incorrectly rendered.
3. I use a white texture as my shadow map, however tex(gShadow,lightSpacePos.xy) will still be zero for some part of the scene. I do not understand how can I get a black sample in a white texture?

In my c++ code I use:
[code]
gd3dDevice->Clear(0,0,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,0xffffffff,1.0,0);
[/code]
to make my shadow texture completely white and do not perform any further rendering on the texture. I thought this shadow map will give me a scene without any shadows, but when I ran the program I got a strange black area in my shadow area(shown in the attachment).

PS: I put the following code in my shader to help mu check the value of tex2D(gShadow,lightSpacePos.xy):
[code]

float val = tex2D(gShadow,lightSpacePos.xy);
if (val < 0.000001)
color = float4(0,0,0,0);
[/code]

Could any one tell my how to insert a picture? Otherwise I will only be able to put my screen shots in the attachment.

Share this post


Link to post
Share on other sites
Hi guys:

I have solved the problem, thanks for everyone's help, you people are really very nice.
In short I delete all the Filter code and it works correctly now.

But, anyone knows why?

Share this post


Link to post
Share on other sites
Hi IMYT,

If I understood correctly, the problem you are facing is a common shadow mapping problem.
When you create the shadow map you use a Orthographic matrix right? D3DXMATRIX * D3DXMatrixOrthoLH(inout D3DXMATRIX *pOut, in FLOAT w, in FLOAT h, in FLOAT zn, in FLOAT zf ); So the w and h parameters define the "amount of world" that will be stored in the shadow map. You have either two options you increase the width and height of you projection matrix so that more information will be stored. One problem of increasing the size of the projection matrix is that you also have to increase the size of you shadow map or you will suffer from aliasing.
Or you try a different techinque called "Cascaded Shadow Maps" (just google it or read the article about it you have on the DirectX SDK.
If you have a small scene just increase the size of the projection matrix and the shadow map, on the other hand, if you have a large outdoor scene you definitely should try Cascaded Shadow Maps.

[quote name='IMYT' timestamp='1298701628' post='4779237']
Hi guys:

I have solved the problem, thanks for everyone's help, you people are really very nice.
In short I delete all the Filter code and it works correctly now.

But, anyone knows why?
[/quote]

Which lines did you exactly deleted?

Share this post


Link to post
Share on other sites
[quote name='TiagoCosta' timestamp='1298803448' post='4779608']
Hi IMYT,

If I understood correctly, the problem you are facing is a common shadow mapping problem.
When you create the shadow map you use a Orthographic matrix right? D3DXMATRIX * D3DXMatrixOrthoLH(inout D3DXMATRIX *pOut, in FLOAT w, in FLOAT h, in FLOAT zn, in FLOAT zf ); So the w and h parameters define the "amount of world" that will be stored in the shadow map. You have either two options you increase the width and height of you projection matrix so that more information will be stored. One problem of increasing the size of the projection matrix is that you also have to increase the size of you shadow map or you will suffer from aliasing.
Or you try a different techinque called "Cascaded Shadow Maps" (just google it or read the article about it you have on the DirectX SDK.
If you have a small scene just increase the size of the projection matrix and the shadow map, on the other hand, if you have a large outdoor scene you definitely should try Cascaded Shadow Maps.

[quote name='IMYT' timestamp='1298701628' post='4779237']
Hi guys:

I have solved the problem, thanks for everyone's help, you people are really very nice.
In short I delete all the Filter code and it works correctly now.

But, anyone knows why?
[/quote]

Which lines did you exactly deleted?

[/quote]

Hi:

Thanks for your reply.

I deleted:
[color=#1C2837][size=2][color=#660066]MinFilter[/color][color=#000000] [/color][color=#666600]=[/color][color=#000000] [/color][color=#660066]Point[/color][color=#666600];[/color][color=#000000]
[/color][color=#660066]MagFilter[/color][color=#000000] [/color][color=#666600]=[/color][color=#000000] [/color][color=#660066]Point[/color][color=#666600];[/color][color=#000000]
[/color][color=#660066]MipFilter[/color][color=#000000] [/color][color=#666600]=[/color][color=#000000] [/color][color=#660066]Point[/color][color=#666600];[/color][/size][/color]


Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this