[HLSL] Shadowmapping Problem

Started by
3 comments, last by sybixsus 16 years, 4 months ago
I'm having problems with writing a shadowmapping system. I've included the source to both shaders below. The depth shader renders the depth map to a camera which is positioned and rotated, FOV, etc set up in code. The shadow shader *should* project the depth map onto the level geometry. ( Yes, I know that's not shadowmapping, it's a test to make sure my projection is right and it's not. ) The texture is projected offset from the geometry. Actually moving the geometry gets the shadowmap closer to the correct position, which I hope is indicative of where the problem lies to someone smarter than me. In reality of course, moving the receiving geometry shouldn't make any difference since the camera will move with it. So my guess is that I have a matrix transform ( or several ) incorrect, but I'm damned if I can see anything wrong. In the depth shader, the WorldViewProjection matrix is passed automatically by the engine, so that's definitely right. In the shadow shader, I copy the matrix from the depth shader and set it in the shadow shader. I know there are better ways, but again this is a test, to eliminate errors in calculations. It's an isometric camera. I don't think that is pertinent to the problem, but I'll mention it in case it might be. Don't be afraid to address me as though I were a thick ox with very limited grasp of 3d maths, for that is indeed the case. Depth Shader:

// SHADOWMAPPING SHADER

float4x4 WVPMatrix : WorldViewProjection;

float farPlane; // THE Z DIMENSION OF THE CAMERA FRUSTUM

struct VS_OUTPUT
{
   float4 Position : POSITION0;
   float3 Position2D : TEXCOORD0; 
};

struct VS_INPUT
{
	float4 Position : POSITION0;
};


VS_OUTPUT vs_depth( VS_INPUT Input )
{
	VS_OUTPUT Output;
	
	Output.Position = mul( Input.Position,WVPMatrix );
	Output.Position2D = Output.Position;
	
	return Output;
   
}

float4 ps_depth( VS_OUTPUT Input) : COLOR0
{  
	// WEB
	return Input.Position2D.z/farPlane;  // DIVIDE BY THE FARPLANE TO GET A VALUE BETWEEN 0 AND 1

}

technique DepthMap
{
   pass Pass_0
   {
      VertexShader = compile vs_1_1 vs_depth();
      PixelShader = compile ps_1_1 ps_depth();
   }
}
Shadow Shader:

// SHADOWMAPPING SHADER

float4x4 WVPMatrix : WorldViewProjection;
float4x4 LightWVPMatrix;

float3 lightPos;
float3 lightXDir;
float3 lightYDir;
float3 lightZDir;


// SHADOW MAP AND SAMPLER
Texture ShadowMap : TEXTURE2;
sampler2D ShadowMapSampler = sampler_state
{
	Texture = <ShadowMap>;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
	AddressU = CLAMP;
	AddressV = CLAMP;
};


float farPlane; // THE Z DIMENSION OF THE CAMERA FRUSTUM

struct VS_INPUT
{
	float4 Position : POSITION0;
};

struct VS_OUTPUT
{
   float4 Position : POSITION0;
   float4 Position2D : TEXCOORD0; 
};

VS_OUTPUT vs_shadow( VS_INPUT Input )
{
	VS_OUTPUT Output;
		
	// OLD
	Output.Position = mul(Input.Position,WVPMatrix);
	Output.Position2D = mul(Input.Position,LightWVPMatrix);
	return Output;
   
}

float4 ps_shadow(VS_OUTPUT Output) : COLOR0
{  
	
	float2 ProjectedTexCoords;
	ProjectedTexCoords[0] = Output.Position2D.x/Output.Position2D.w/2.0f +0.5f;
	ProjectedTexCoords[1] = -Output.Position2D.y/Output.Position2D.w/2.0f +0.5f;
	return tex2D(ShadowMapSampler, ProjectedTexCoords);
   
}

technique ShadowMap
{
   pass Pass_0
   {
      VertexShader = compile vs_1_1 vs_shadow();
      PixelShader = compile ps_2_0 ps_shadow();
   }
}

Advertisement
This part right here jumps out at me...

float4 ps_depth( VS_OUTPUT Input) : COLOR0{  	// WEB	return Input.Position2D.z/farPlane;  // DIVIDE BY THE FARPLANE TO GET A VALUE BETWEEN 0 AND 1}


You want to divide the z component by the w component, not by the farPlane. Since you're working with the result of of perspective projection, doing this automatically gives you a depth value of the range 0.0-1.0, scaled to the distance between your near and far clip planes.

Also just curious...why are you using vs_1_1 and ps_1_1?
It's already been suggested to me that I should write to the depth map differently, but there's no point in improving it until it's actually working. I'm writing the depth map out to disk as and when I want to verify that the image is correct and visible, and the image is fine. I can deal with improving the depth writing when it's actually working. Clearly I'm doing something wrong with the projection at the moment, so I need to fix that first.

There's no particular reason I'm compiling to 1.1. Just force of habit to use the lowest version I can get away with I guess. It doesn't work any differently compiled to other version targets anyway.
I'm not sure if this helps any, but I can't think of any more information that I can provide, so here's the LightWVP matrix, which is passed automatically by the engine to the depth shader and then copied by me to the project shader.


[0.200000003, 0.000000000, 0.000000000, 0.000000000]
[0.000000000, 1.19209318e-008,-0.333333403, 0.000000000]
[0.000000000, 0.200000033, 1.98682226e-008, 0.000000000]
[0.339280903, 0.0987815559, 1.00000012, 1.00000000]

That's for an isometric camera with a farplane of 20, facing directly downwards and positioned at 2,4,0.

As I say, the engine does that for me automatically, so it didn't ought to have any problems, but I thought I should probably post it so that you can be sure.
Thank you to anyone who read through and couldn't find the problem. That's because there wasn't one. The 3D engine I use has some shader matrix bugs, and I'll have to work around them.

This topic is closed to new replies.

Advertisement