Jump to content
  • Advertisement
Sign in to follow this  
Thergothon

Shadow maps

This topic is 4436 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying to get a basic shadow map implementation up and running. The depth is rendered correctly from the lights point of view into a D3DFMT_R32F texture. The second pass of the scene is where the problem is. The scene is rendered as if every pixel is lit, so there is obviously something wrong with the depth comparison. I'm fairly sure that the error is in the projected texture matrix because when I change the pixel shader to output the depth read from the shadow map, all the geometry is rendered white. If anybody has any ideas on how to fix this, it would be greatly appreciated. Thanks. Here is the set up code:

void DrawShadowMap() {

	//set up light matrices
	D3DXMATRIX lightView, lightProj;

	D3DXMatrixLookAtLH(&lightView, &D3DXVECTOR3(10.0f, 10.0f, 10.0f),
		&D3DXVECTOR3(0.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 1.0f, 0.0f));

	D3DXMatrixPerspectiveFovLH(&lightProj, 0.5f, 1.0f, 1.0f, 100.0f);

	D3DXMatrixIdentity(&g_world);

	g_lightViewProj = lightView * lightProj;

	//upload matrices
	g_shadow->SetMatrix("lightViewProj", &(g_world * g_lightViewProj));
	g_shadow->CommitChanges();

	//switch render targets
	g_d3dDevice->GetRenderTarget(0, &g_oldSurface);
	g_d3dDevice->GetDepthStencilSurface(&g_oldZBuffer);
	g_d3dDevice->SetRenderTarget(0, g_shadowMapSurface);
	g_d3dDevice->SetDepthStencilSurface(g_shadowMapZBuffer);

	g_d3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);

	g_shadow->BeginPass(0);
	g_teapot->DrawSubset(0);
	g_shadow->EndPass();

	//restore render target
	g_d3dDevice->SetRenderTarget(0, g_oldSurface);
	g_d3dDevice->SetDepthStencilSurface(g_oldZBuffer);


}

//----------------------------------------------------------

void DrawScene() {

	//set up matrices
	D3DXMatrixIdentity(&g_world);

	D3DXMATRIX view, proj;

	D3DXMatrixLookAtLH(&view, &D3DXVECTOR3(5.0f, 5.0f, -5.0f),
		&D3DXVECTOR3(0.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 1.0f, 0.0f));

	D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI/4, 1.33f, 1.0f, 100.0f);

	g_viewProj = view * proj;

	//light projection matrix
	float offset = 0.5f + (0.5f/(float)SHADOWMAP_SIZE);
	D3DXMATRIX textureAdjust(0.5f,    0.0f,  0.0f, 0.0f,
				 0.0f,   -0.5f,  0.0f, 0.0f,
				 0.0f,    0.0f,  0.0f, 0.0f,
				 offset, offset, 0.0f, 1.0f);

	g_lightProjTex = g_world * g_lightViewProj * textureAdjust;

	//upload matrices
	g_shadow->SetMatrix("world", &g_world);
	g_shadow->SetMatrix("viewProj", &g_viewProj);
	g_shadow->SetMatrix("lightProjTex", &g_lightProjTex);

	g_shadow->SetVector("lightPos", &D3DXVECTOR4(10.0f, 10.0f, 10.0f, 0.0f));
	g_shadow->SetVector("diffuse", &D3DXVECTOR4(0.8f, 0.0f, 0.0f, 1.0f));
	g_shadow->SetVector("ambient", &D3DXVECTOR4(0.2f, 0.0f, 0.0f, 1.0f));

	g_shadow->SetTexture("ShadowMap", g_shadowMap);

	g_shadow->CommitChanges();

	//create ground plane
	struct VERTEX {
		float x, y, z;
		float nx, ny, nz;
	};

	VERTEX quad[4] = {
		{20.0f, -10.0f, 20.0f, 0.0f, 1.0f, 0.0f},
		{20.0f, -10.0f, -20.0f, 0.0f, 1.0f, 0.0f},
		{-20.0f, -10.0f, 20.0f, 0.0f, 1.0f, 0.0f},
		{-20.0f, -10.0f, -20.0f, 0.0f, 1.0f, 0.0f}
	};

	g_d3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xff000000, 1.0f, 0);

	g_shadow->BeginPass(1);
	g_teapot->DrawSubset(0);

	g_d3dDevice->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL);
	g_d3dDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(VERTEX));

	g_shadow->EndPass();

}


shadowMap.fx
//camera matrices
float4x4 world;
float4x4 viewProj;

//light matrix
float4x4 lightViewProj;

//light projected texture adjustment matrix
float4x4 lightProjTex; 

//colours for diffuse lighting
float4 ambient;
float4 diffuse;

//position of diffuse point light
float3 lightPos;

//------------ Shadow map texture sampler --------------------

texture ShadowMap;
sampler ShadowMapSampler = sampler_state {
    Texture = <ShadowMap>;
    MinFilter = LINEAR;
    MagFilter = LINEAR;
    MipFilter = NONE;
    AddressU = CLAMP;
    AddressV = CLAMP;
    AddressW = CLAMP;
};

//------------ Shadow map creation shaders -------------------

struct createIn {
    float3 pos: POSITION;
};

struct createOut {
    float4 pos: POSITION;
    float depth: TEXCOORD0;
};

void CreateShadowMapVS(in createIn input, out createOut output) {
    //transform position into light space
    output.pos = mul(float4(input.pos, 1.0), lightViewProj);

    //perspective divide pos.z to get depth
    output.depth = output.pos.z/output.pos.w;
}

float4 CreateShadowMapPS(in float depth: TEXCOORD0) : COLOR {
    return depth;
}  

//------------ Scene render with shadow map ------------------

struct vsIn {
    float3 pos: POSITION;
    float3 norm: NORMAL;
};

struct vsOut {
    float4 final: POSITION;

    float3 pos: TEXCOORD0;
    float3 norm: TEXCOORD1;

    float4 uv: TEXCOORD2;
    float  depth: TEXCOORD3;
};

void VS(in vsIn input, out vsOut output) {

    //transform vertex to world and save for pixel shader
    output.final = mul(float4(input.pos, 1.0), world);
    output.pos = output.final.xyz;    
    
    //transform vertex to screen space
    output.final = mul(output.final, viewProj);

    //transform normal ino world space, ignoring translation
    output.norm = normalize(mul(input.norm, (float3x3) world));

    //get shadow map uv coordinates for this vertex
    output.uv = mul(input.pos, lightProjTex);
    
    //get depth of vertex from light source
    float4 pos = mul(input.pos, lightViewProj);
    output.depth = pos.z/pos.w - 0.001;

}

struct psIn {
    float3 pos: TEXCOORD0;
    float3 norm: TEXCOORD1;

    float4 uv: TEXCOORD2;
    float  depth: TEXCOORD3;
};

float4 PS(in psIn input) : COLOR {
   
    //get shadow map sample for depth comparison
    float depth = tex2Dproj(ShadowMapSampler, input.uv).x;

    //set ambient colour here as diffuse lighting may be skipped
    float4 colour = ambient;

    //test whether this pixel is lit or not
    if(input.depth - depth > 0.0) {
        //renormalize 
        input.norm = normalize(input.norm);

        //get vector to the light source
        float3 l = normalize(lightPos - input.pos);

        //get amount of light at surface
        float d = saturate(dot(input.norm, l));

        //add diffuse component to colour
        colour += diffuse*d;
    }

    return colour;

}

//----------------- techniques ----------------------------------

technique Shader {

    pass P0 {
        VertexShader = compile vs_1_1 CreateShadowMapVS();
        PixelShader = compile ps_2_0 CreateShadowMapPS();
    }

    pass P1 {
        Sampler[0] = (ShadowMapSampler);
        VertexShader = compile vs_2_0 VS();
        PixelShader = compile ps_2_0 PS();
    }

}

Share this post


Link to post
Share on other sites
Advertisement
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!