Shadow map problem

Started by
10 comments, last by IMYT 13 years, 1 month ago
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:

//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();
}
}


Can any tell me what is wrong with my code? Thanks.
Advertisement
Hello? Could anyone please come and help me?
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:

finalPos = mul(input.pos, gLightWVP);

output.position = finalPos;
output.depth.xy = finalPos.zw;

Pixel Shader for this part:

return input.depth.x / input.depth.y;


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


output.worldPos = float4(input.position,1.0);
output.worldNormal = input.normal;


In the pixel shader I calculate the position in the light view(lightSpacePos).

float4 lightSpacePos = mul(input.worldPos,gLightView);
lightSpacePos = mul(lightSpacePos,gLightProj);


and transform the coordinates into texcoord for shadow rendering:


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


The depth information is calculated by following code:

float shadowFactor = (tex2D(gShadow,lightSpacePos.xy)+0.0005 < lightSpacePos.z) ? 0.0 : 1.0;


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.
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
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.

My current blog on programming, linux and stuff - http://gameprogrammerdiary.blogspot.com

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.

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.


Thanks for your suggestions.

I checked the texture coordinates use your method before, it seems that they are in range.
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.
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:

gd3dDevice->Clear(0,0,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,0xffffffff,1.0,0);

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):


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


Could any one tell my how to insert a picture? Otherwise I will only be able to put my screen shots in the attachment.
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?

This topic is closed to new replies.

Advertisement