Shadow mapping problem

Started by
22 comments, last by bushmanpaul 13 years, 6 months ago
Hello,
I am attempting to implement shadow mapping, but am failing pretty horribly.

For some reason, the shadows are in a completely wrong place, and not even oriented correctly:

http://imgur.com/ROEgP

What could cause this?
Advertisement
Looks like you're using the wrong view matrix when rendering the shadow, or when projecting the shadow-map.

How do you calculate your matrices?
Quote:Original post by Hodgman
Looks like you're using the wrong view matrix when rendering the shadow, or when projecting the shadow-map.

How do you calculate your matrices?


I calculate the view matrix in c++ and pass it to the shader:

D3DXMatrixLookAtLH(&worldToLight,&(light.pos),&(light.dir),&(Vec3(0,1,0)));
that is your lookat, but you need to create your projection matrix too and combine them. Usually, you create an orthographic projection. Good luck..

http://www.d3dcoder.net/d3d10.aspx

For some good information and code on how to do shadow mapping, download part III, unzip it, and check the folder chapter 13. It is about shadow mapping.
Wisdom is knowing when to shut up, so try it.
--Game Development http://nolimitsdesigns.com: Reliable UDP library, Threading library, Math Library, UI Library. Take a look, its all free.
Quote:Original post by smasherprog
that is your lookat, but you need to create your projection matrix too and combine them. Usually, you create an orthographic projection.


Hmm, yes, I have that, too:

D3DXMatrixPerspectiveFovLH(&lightProjection,		D3DXToRadian(90),		(FLOAT)resX / (FLOAT)resY,		NEAR_PLANE,		FAR_PLANE);


Your view matrix is wrong. The LookAt parameter isn't a direction vector, it's a point at which the camera looks. So you want to do this:
D3DXVECTOR3 lookAt = light.pos + light.dir;D3DXMatrixLookAtLH(&worldToLight,&(light.pos),&lookAt,&(Vec3(0,1,0)));





Quote:Original post by MJP
Your view matrix is wrong. The LookAt parameter isn't a direction vector, it's a point at which the camera looks. So you want to do this:
D3DXVECTOR3 lookAt = light.pos + light.dir;D3DXMatrixLookAtLH(&worldToLight,&(light.pos),&lookAt,&(Vec3(0,1,0)));


Wow, good call. But it doesn't change the incorrect shadows...
Is there anything wrong with my shader code?

Here is the code for rendering the shadow map (which looks correct):
/* posView is the pixel in light space, because the view matrix is temporarily using the light as a "camera"*/return float4(IN.posView.z,IN.posView.z,IN.posView.z,1.0);


Here is where I use the shadow map texture:
	float Shadow = 1.0;		if(shadowMapExists)	{				/*convert pixel position in light space to NDC, then to the 		range [0,1]*/		float4 posTex =  mul(IN.posLight,lightProjection);		posTex += float4(1,1,1,0);		posTex *= 0.5;				/*use converted pixel position to index into the texture*/		/*sampled values should be between the near plane and far plane;		[1.0,10000]*/		float D = tex2D(shadowSampler,float2(posTex.x,posTex.y)).z;		/* if the pixel value is smaller than the sampled value, it		means there is something in front of the pixel, in light space; 		the pixel is in shadow*/			if( IN.posLight.z < D )				Shadow -= 1.0;				}
If you're using a perspective projection you need to perform homogeneous divide-by-w before you can use X and Y as a texture coordinate. This brings the coordinates into the [-1, 1] range which you can then convert to [0, 1] range (which you're already doing).

After that, you also need to flip the y coordinate around. After divide-by-w, y is -1 at the bottom and 1 at the top. This is the opposite of texture coordinates, where 0 is the top and -1 is the bottom. Try this:
float4 posTex =  mul(IN.posLight,lightProjection);posTex /= posTex.w;posTex += float4(1,1,1,0);posTex *= 0.5;posTex.y = 1.0f - posTex.y;
Quote:Original post by MJP
If you're using a perspective projection you need to perform homogeneous divide-by-w before you can use X and Y as a texture coordinate. This brings the coordinates into the [-1, 1] range which you can then convert to [0, 1] range (which you're already doing).

After that, you also need to flip the y coordinate around. After divide-by-w, y is -1 at the bottom and 1 at the top. This is the opposite of texture coordinates, where 0 is the top and -1 is the bottom. Try this:
float4 posTex =  mul(IN.posLight,lightProjection);posTex /= posTex.w;posTex += float4(1,1,1,0);posTex *= 0.5;posTex.y = 1.0f - posTex.y;


Cool, I did not know that.

The shadows actually look decent now, but there are a lot of problems with them. The biggest problem are the z-values.

Currently, I use 1/pixelInLightSpace.z for both the shadow map and testing against the shadow map. This is because the biggest differences are now in the [0,1] range. However, it is still non-linear and causes problems.

Some other problems are:
-Small bands of light between an object and its shadow
-Occasional shadow-light stripes
-Weird behavior when the light is far away from the object

Does anybody know any solutions to these problems?

[Edited by - xytor on October 16, 2010 10:57:42 PM]
1.The small bands of light you are seeing is the inaccuracy in float. This is totally normal.

2.This is also a problem with inaccuracy with float, try adding more bias (might make small bands of light bigger).

http://developer.nvidia.com/object/hwshadowmap_paper.html shows you how to solve this.

3.The further the light is away the higher your shadow Map resolution need to be for you to get better results.If I understand you correctly.

Hope this helps.

This topic is closed to new replies.

Advertisement