Shadow Mapping using DirectX

Hi

I have a problem with implementing Shadow Mapping into a project I am working on. I am very much new to shaders and I have been given a Shadow Mapping shader to implement and understand. I have mostly got my head round the concept and the code but I can't figure out why its not working.

As I understand it the main steps to follow are;

1) Render the scene from the POV of the light - this is done in ShadowMap::SetUpDepthRender where the view and projection matrices are passed to the shader.

2) Render all objects in the scene - this creates a shadowmap (depth map) via the shader.

3) Reset the view and projection matrices to that of the camera - done in ShadowMap::SetUpSceneRender.

4) Render the scene objects once more appling the depth map to them via the second pass of the shader.

The problem Im having is that I have a stripe of light running diagonally across the screen. It passes through the point of the spotlight that I am mapping for. I believe this is the shadowmap being applied to the scene however I could be wrong?

Below is the code in the ShadowMap class used for setting the fx file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
LPDIRECT3DSURFACE9 oldDepthSurface = NULL;
LPDIRECT3DSURFACE9 oldRenderTarget = NULL;

ShadowMap::ShadowMap(void)
{
	//Create our Light
	Vector3D lightPosition(20.0f, 2.9f, 10.0f);
	Vector3D lightDirection;
	Vector3DNormalize(&lightDirection,&lightPosition);
	LightingManager::GetInstance()->AddSpotLight("Test",lightPosition, -lightDirection,Vector3D(0,0.5f,0.1f),10.0f,(D3DX_PI * 2) / 2,1.0f,1.0f,1,1,1,1);
}

ShadowMap::~ShadowMap(void)
{
	//release the texture and surface
	m_shadowMap->Release();
	m_shadowMapSurface->Release();
	oldDepthSurface = NULL;
	oldRenderTarget = NULL;
}

void 
ShadowMap::Create()
{
	
	HRESULT hr;
	//create our shadow map texture to the size of SHADOWMAP_SIZE, the texture contains one 32-bit channel within the default memory pool,
	//the texture is stored within m_shadowMap
	hr = m_D3DDevice->CreateTexture(SHADOWMAP_SIZE,SHADOWMAP_SIZE,1,D3DUSAGE_RENDERTARGET,D3DFMT_R32F,D3DPOOL_DEFAULT,&m_shadowMap,NULL);
	//error checking
	if(hr != S_OK)
	{
		ErrorMessage("Did not create shadow map texture");
	}
	
	//create the depth Stencil surface to the size of SHADOWMAP_SIZE to a 24bit depth, and no multisampling,
	//the surface is stored in m_shadowMapSurface;
	hr = m_D3DDevice->CreateDepthStencilSurface(SHADOWMAP_SIZE,SHADOWMAP_SIZE,D3DFMT_D24X8,D3DMULTISAMPLE_NONE,0,TRUE,&m_shadowMapSurface,NULL);

	if(hr != S_OK)
	{
		ErrorMessage("Did not create shadow map surface");
	}

	//calculate the max projection of the scene
	float maxProjection = D3DXVec3LengthSq(&LightingManager::GetInstance()->GetLight("Test")->GetPosition()) ;

	//create the shadow projection matrix
	D3DXMatrixPerspectiveFovLH( &m_shadowMatrix, D3DX_PI / 2, 1, 1.5f, maxProjection);
}

void
ShadowMap::RenderScene(bool renderShadow,const Matrix* view, const Matrix* Proj)
{	
	
	//Set the theta of the light to that of our spot light
	EffectManager::GetInstance()->GetEffect("ShadowMap")->SetFloat("m_CosTheta", cosf((D3DX_PI * 2) / 2));


	//Set our Light Position
	Vector3D lightPos = LightingManager::GetInstance()->GetLight("Test")->GetPosition();
	//Create a Tempory Vector4D Variable 
	Vector4D tempVector4;
	
	//Set the View And Projection matrices within the shader
	EffectManager::GetInstance()->GetEffect("ShadowMap")->SetMatrix("m_View", *view );
	EffectManager::GetInstance()->GetEffect("ShadowMap")->SetMatrix("m_Proj", *Proj);	

	m_view = *view;
	m_proj = *Proj;
	
	//Transform our light vector by our view matrix, place the result in tempVector4
	D3DXVec3Transform( &tempVector4, &lightPos, view);

	//Set our light position within our shader
	EffectManager::GetInstance()->GetEffect("ShadowMap")->SetVector4("m_LightPosition",tempVector4);
	
	//Set our TempVector4 to our light direction
	*(D3DXVECTOR3*)&tempVector4  = LightingManager::GetInstance()->GetLight("Test")->GetDirection();
	//set our tempVector4.w to 0 as this will clear any tesserlation issues
	tempVector4.w =0;
	//transform the value within tempVector4 with our view
	D3DXVec4Transform( &tempVector4, &tempVector4, view);
	//Normalize it
	Vector3DNormalize((D3DXVECTOR3*)&tempVector4,(D3DXVECTOR3*)&tempVector4);
	//And place it within our shader
	EffectManager::GetInstance()->GetEffect("ShadowMap")->SetVector4("m_LightDirection",tempVector4);


	//If we are rendering the Shadow, set our shaders technique to that
	//else we set it to our scene render technique
	if(renderShadow)
	{
		m_D3DDevice->Clear(0,NULL,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(255,0,255),1.0f,0);

		EffectManager::GetInstance()->GetEffect("ShadowMap")->SetTechnique("mTech1");	
	}

	if(!renderShadow)
	{
		EffectManager::GetInstance()->GetEffect("ShadowMap")->SetTechnique("mTech");
	}
}

void
ShadowMap::SetUpDepthRender()
{
	
	//Create a temp Render Target
	//Get the current RenderTarget and place it within our temp Render Target
	m_D3DDevice->GetRenderTarget( 0, &oldRenderTarget );

	//Create a temp ShadowSurface
	LPDIRECT3DSURFACE9 tempShadowSurface;

	//The Texture takes a reference of the surface level of the tempShadowSurface
	if( SUCCEEDED( m_shadowMap->GetSurfaceLevel( 0, &tempShadowSurface ) ) )
	{
		//it is set to target and released
		m_D3DDevice->SetRenderTarget( 0, tempShadowSurface );
		tempShadowSurface->Release() ;
	}

	//Store the current depth surface to the temp variable and set the stencil surface
	//to our member surface
	if( SUCCEEDED( m_D3DDevice->GetDepthStencilSurface( &oldDepthSurface ) ) )
	m_D3DDevice->SetDepthStencilSurface( m_shadowMapSurface );

	RenderScene( true, &LightingManager::GetInstance()->GetLight("Test")->GetView() ,&m_shadowMatrix);
	
}

void
ShadowMap::SetUpSceneRender()
{
	
	//Set the now generated texture to our shader
	EffectManager::GetInstance()->GetEffect("ShadowMap")->GetEffect()->SetTexture(EffectManager::GetInstance()->GetEffect("ShadowMap")->GetHandle("m_ShadowMap")->m_handle,m_shadowMap);

	//if there is an old surface, set it back
	if( oldDepthSurface )
	{
		m_D3DDevice->SetDepthStencilSurface( oldDepthSurface );
		oldDepthSurface->Release();
	}

	//set the render target back to how it was before this process
	m_D3DDevice->SetRenderTarget( 0, oldRenderTarget );
	oldRenderTarget->Release();

	//generate a view to light projection matrix to generate how the shadow will appear
	Matrix viewToLightProj ;
	//set our matrix to our camera view
	viewToLightProj = CameraController::GetInstance()->GetView() ;
	//Inverse it
	MatrixInverse(&viewToLightProj,NULL,&viewToLightProj);
	//Multiply it with out light view matrix
	MatrixMultiply(&viewToLightProj,&viewToLightProj,&LightingManager::GetInstance()->GetLight("Test")->GetView());
	//then our shadow matrix
	MatrixMultiply(&viewToLightProj,&viewToLightProj,&m_shadowMatrix);
	//apply to effect
	EffectManager::GetInstance()->GetEffect("ShadowMap")->SetMatrix("m_VTLP",viewToLightProj);

	//render scene, to render the environment this time
	RenderScene(false, &CameraController::GetInstance()->GetView(),&CameraController::GetInstance()->GetProjection());
	
}


I am also including my Render call from SceneManager to show how the objects are rendered to screen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
void 
SceneManager::Render()
{
		//Use the shadow manager to set up the depth read

		ShadowManager::GetInstance()->SetUpForShadowMapDepthRead();
		//UINT numPasses = 0;

		UINT numPass1 = 0;
		EffectManager::GetInstance()->GetEffect("ShadowMap")->GetEffect()->Begin(&numPass1,0);
		EffectManager::GetInstance()->GetEffect("ShadowMap")->GetEffect()->BeginPass(0);
		EffectManager::GetInstance()->GetEffect("ShadowMap")->SetActive(true);

		// Run any renders to have shadows here
		for(int i=0; i < m_ObjectList.GetNumEntries(); i++)
		{
			m_ObjectList[i]->Render();

		}
		for(int i=0; i < m_FloorList.GetNumEntries(); i++)
		{
			if(m_FloorList[i]->GetLevel() >= 0)
			{
				m_FloorList[i]->Render();
			}
		}
		for(int i=0; i < m_WallList.GetNumEntries(); i++)
		{
			if(m_WallList[i]->GetLevel() >= 0)
			{
				m_WallList[i]->Render();
			}
		}
		
		//end the shader
		EffectManager::GetInstance()->GetEffect("ShadowMap")->SetActive(false);
		EffectManager::GetInstance()->GetEffect("ShadowMap")->GetEffect()->EndPass();
		EffectManager::GetInstance()->GetEffect("ShadowMap")->GetEffect()->End();

		//now set up the scene render
		ShadowManager::GetInstance()->SetUpForShadowMapRenderToScene();

		//RecursiveRender(m_firstEvent, RenderEvent::Skinned);

		//begin shadow effect
		EffectManager::GetInstance()->GetEffect("ShadowMap")->GetEffect()->Begin(&numPass1,0);
		EffectManager::GetInstance()->GetEffect("ShadowMap")->GetEffect()->BeginPass(0);
		EffectManager::GetInstance()->GetEffect("ShadowMap")->SetActive(true);
		
		//Render the environment
		for(int i=0; i < m_ObjectList.GetNumEntries(); i++)
		{
			m_ObjectList[i]->Render();

		}
		for(int i=0; i < m_FloorList.GetNumEntries(); i++)
		{
			if(m_FloorList[i]->GetLevel() >= 0)
			{
				m_FloorList[i]->Render();
			}
		}
		for(int i=0; i < m_WallList.GetNumEntries(); i++)
		{
			if(m_WallList[i]->GetLevel() >= 0)
			{
				m_WallList[i]->Render();
			}
		}
		
		//end the shader
		EffectManager::GetInstance()->GetEffect("ShadowMap")->SetActive(false);
		EffectManager::GetInstance()->GetEffect("ShadowMap")->GetEffect()->EndPass();
		EffectManager::GetInstance()->GetEffect("ShadowMap")->GetEffect()->End();


And here is an example of how each render call in the object looks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void
Object::Render()
{
	if(m_active)
	{
		Matrix tempWorld = m_world;
		//tempWorld = tempWorld * *ShadowManager::GetInstance()->GetShadowMap()->GetCurrentView() * *ShadowManager::GetInstance()->GetShadowMap()->GetCurrentProj();
		EffectManager::GetInstance()->GetEffect("ShadowMap")->SetMatrix("m_World",tempWorld);
		EffectManager::GetInstance()->GetEffect("ShadowMap")->GetEffect()->CommitChanges();
		

		CameraController::GetInstance()->SetWorld(m_world);
		m_model->Render();
		CameraController::GetInstance()->ResetWorld();
	}
}


And the shader itself

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/////////////////////////////////////////////////////////
//Shadow Mapping Shader
//
//This Shader Contains 2 effects, one to generate a 
//shadow map, the other to render the scene applying the
//shadow map to the pixel colour of the environment.
////////////////////////////////////////////////////////

//define image size and error range
#define SMAP_SIZE 2048
#define EPSILON 0.00005f

//Global Variables

//World
uniform extern float4x4 gWorld;
//View
uniform extern float4x4 gView;
//Projection
uniform extern float4x4 gProjection;
//View to Light
uniform extern float4x4 gViewToLightProjection;
//material Colour
uniform extern float4 gMaterial;
//Base Texture
uniform extern texture gTexture;
//Shadow Texture
uniform extern texture gShadowMap;
//Light Position
uniform extern float4 gLightPosition;
//Light Direction
uniform extern float4 gLightDirection;
//Colours
uniform extern float4 gLightDiffuse = float4 (1,1,1,1);
uniform extern float4 gLightAmbient =  float4(0.1f,0.1f,0.3f,1.0f);
//Range
uniform extern float gCosTheta;

//Texture Sampler for base map
sampler2D TexS = sampler_state
{
	Texture = <gTexture>;
	MinFilter = Point;
	MagFilter = LINEAR;
	MipFilter = LINEAR;
};

//Texture Sampler for Shadow Map
sampler2D TexShadow = sampler_state
{
    Texture = <gShadowMap>;
    MinFilter = Point;
    MagFilter = Point;
    MipFilter = Point;
    AddressU = Clamp;
    AddressV = Clamp;
};

//Shadow Input Structure
struct VS_ShadowInput
{
	float4 Position : POSITION;
	float3 Normal : NORMAL;
};

//Shadow Output Structure
struct VS_ShadowOutput
{
	float4 Position : POSITION;
	float2 TexCoord : TEXCOORD0;
};

//Scene Input Structure
struct VS_SceneInput
{
	float4 Position : POSITION;
	float3 Normal : NORMAL;
	float2 Texcoord : TEXCOORD0;
};


//The Scene Shader
//This renders the environment applying the shadow map
//within the calculations, 
//
//Yhe Vertex Shader positions the object and returns normal and light information
//ScenePosition and SceneNormal are transformed values within the projection matrix
void vs_scene(VS_SceneInput input,
	out float4 Position : POSITION,
	out float2 Texcoord : TEXCOORD0,
	out float4 ScreenPosition : TEXCOORD1,
	out float3 ScreenNormal : TEXCOORD2,
	out float4 LightPosition : TEXCOORD3)
{
	
	//calulate position by multiplying with the world and view matrix
	ScreenPosition = mul(input.Position,gWorld);
	ScreenPosition = mul(ScreenPosition,gView);
	//Compute the out position by multiplying with the projection matrix
	Position = mul(ScreenPosition,gProjection);
	
	//Compute the normal in the same way
	ScreenNormal = mul(input.Normal,(float3x3)gWorld);
	ScreenNormal = mul(ScreenNormal,(float3x3)gView);
	
	//Set Texcoord
	Texcoord = input.Texcoord;
	
	//Get Light position using the ScreenPosition and gViewToLightProjection
	LightPosition = mul(ScreenPosition, gViewToLightProjection);
	
	
}

//The Scene Pixel Shader Input Structure
struct PS_SceneInput
{
	float2 Texcoord : TEXCOORD0;
	float4 ScreenPosition : TEXCOORD1;
	float3 ScreenNormal : TEXCOORD2;
	float4 LightPosition : TEXCOORD3;
};

//Pixel Shader, this computes the pixel colour of the object using the shadow map
//as guide for calculating the pixel colour
float4 ps_scene(PS_SceneInput input): COLOR0
{

	float4 diffuse;
	
	//Get a normalised light position by subtracting the light position from the screen position, then normalising
	float3 Light = normalize(float3 (input.ScreenPosition - gLightPosition.xyz));
	
	//if the dot product result of the light position and direction is greater than the range,
	//this is apart of the shadow
	if(dot(Light,gLightDirection) > gCosTheta)
	{
		//Get the position on the shadow texture, by transforming render targer space to texture space
		float2 ShadowTex = 0.5f * input.LightPosition.xy / input.LightPosition.w + float2(0.5f,0.5f);
		ShadowTex.y = 1.0f - ShadowTex.y;
		
		//transform to texel space
		float2 texelpos = SMAP_SIZE * ShadowTex;
		
		float2 lerps = frac(texelpos);

		//Do Shadow Checks
		float sourceval[4];
		//for each, read the shadow map texture for its value
		sourceval[0] = (tex2D(TexShadow,ShadowTex) + EPSILON < input.LightPosition.z / input.LightPosition.w) ? 0.5f: 1.0f;
		sourceval[1] = (tex2D(TexShadow,ShadowTex + float2(1.0f/SMAP_SIZE, 0))  + EPSILON <  input.LightPosition.z / input.LightPosition.w) ? 0.5f: 1.0f;
		sourceval[2] = (tex2D(TexShadow,ShadowTex + float2(0 , 1.0f/SMAP_SIZE)) + EPSILON < input.LightPosition.z / input.LightPosition.w) ? 0.5f: 1.0f;
		sourceval[3] = (tex2D(TexShadow,ShadowTex + float2(1.0f/SMAP_SIZE , 1.0f/SMAP_SIZE)) + EPSILON < input.LightPosition.z / input.LightPosition.w) ? 0.5f: 1.0f;
		
		//then lerp between the values to calculate the currect light amout
		float LightAmount = lerp(lerp(sourceval[0],sourceval[1] ,lerps.x),lerp(sourceval[2],sourceval[3] ,lerps.x),lerps.y);
		
		//set our diffuse value to is
		diffuse = (saturate(dot(-Light, normalize(input.ScreenNormal))) * LightAmount * (1 - gLightAmbient) + gLightAmbient ) ;
		
	}
	
	else
	{
		//set to normal light colours
		diffuse = gLightAmbient;
	}
	
	//return base map colour with diffuse applied
	return tex2D( TexS, input.Texcoord ) * diffuse;
}


//The Shadow Shader
//This Calulates the depth of the scene 
void vs_shadow(	VS_ShadowInput input,
			out float4 Position : POSITION,
			out float2 Depth : TEXCOORD0)
{
	//Transform the world
	Position = mul(input.Position,gWorld);
	Position = mul(Position,gView);
	Position = mul(Position,gProjection);
	
	//Get the depth of the world by getting the positions z and w values
	Depth = Position.zw;
}

//The Shadows Pixel Shader
//Returns the Depth of the environment as a colour
void ps_shadow(	float2 Depth : TEXCOORD0,
			out float4 Color : COLOR )
{
	Color = (Depth.x / Depth.y) ;
}

//The Scene Technique
technique RenderScene
{
	pass p0
	{
		VertexShader = compile vs_2_0 vs_scene();
		PixelShader = compile ps_2_0 ps_scene();
	}
}

//The Shadow Technique
technique RenderShadow
{
	pass p0
	{
		VertexShader = compile vs_2_0 vs_shadow();
		PixelShader = compile ps_2_0 ps_shadow();
	}
}


Any suggestions on what might be going wrong are greatly appreciated

Thanks
Topic archived. No new replies allowed.