Sign in to follow this  

Shadowmaps: Is this as good as it gets?

This topic is 4377 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

First some screenshots: screenies I can set my epsilon dynamically while the program runs. Therefore, the epsilon you see this scene rendered with, is the optimal. If it is any smaller, the boxes will selfshadow on the illuminated sides. Im particularly disappointed with the distance from the top of the box to where the box begins to actually shadow itself (if you see the single boxes in the top screenshot). Secondly, Im also disappointed with the quite ugly stripes the shadows make on their own boxes (see lower screenshot). Is this really as good as it gets with shadowmaps? Or is it I who does something wrong? I will provide my shadow-shader here:
float4x4 g_world_view;
float4x4 g_projection;
texture g_texture0;
float4 g_light_ambient;
float3 g_light_directional_direction;
float4 g_light_directional_diffuse;
float3 g_camera_lookat;

texture g_shadow_texture;
float4x4 g_viewtolight_projection;						

float g_shadowweight;

float g_shadowepsilon;

// ----------------------------------------------------------
sampler2D g_texsampler0 =
sampler_state
{
	Texture = <g_texture0>;
	MinFilter = Anisotropic;
	MagFilter = Anisotropic;
	MipFilter = Linear;
};

sampler2D g_shadow_sampler =
sampler_state
{
	Texture = <g_shadow_texture>;
	MinFilter = Point;
	MagFilter = Point;
	MipFilter = Point;
	AddressU = Clamp;
	AddressV = Clamp;
};

// ----------------------------------------------------------
struct VS_OUTPUT_TEX0
{
	float4 position: POSITION;
	float2 texcoord0: TEXCOORD0;
	float4 position_viewspace : TEXCOORD1;
	float3 normal: TEXCOORD2;
	float4 position_lightspace : TEXCOORD3;
};

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

// ----------------------------------------------------------
// returns the factor that the diffuse light contributes with
// ----------------------------------------------------------
float DiffuseFactor(float3 a_normal, float3 a_lightdir)
{
	return max(0.0f, dot(a_normal, a_lightdir));
}

// ----------------------------------------------------------
// Vertex Shader: VertScene
// Desc: Process vertex for scene
// ----------------------------------------------------------
VS_OUTPUT_TEX0 VSTex0(float4 a_position: POSITION, float4 a_normal: NORMAL, float2 a_texcoord0: TEXCOORD0)
{
	VS_OUTPUT_TEX0 l_output;

	l_output.position_viewspace = mul(a_position, g_world_view);
	l_output.position = mul(l_output.position_viewspace, g_projection);
	l_output.normal = mul(a_normal, (float3x3)g_world_view);

	l_output.texcoord0 = a_texcoord0;

	l_output.position_lightspace = mul(l_output.position_viewspace, g_viewtolight_projection);

	return l_output;
}

// ----------------------------------------------------------
// Pixel Shader: PixScene
// Desc: Process pixel (do per-pixel lighting) for enabled scene
// ----------------------------------------------------------
float4 PSTex0(float2 a_texcoord0: TEXCOORD0, float4 a_position_viewspace : TEXCOORD1, float3 a_normal : TEXCOORD2, float4 a_position_lightspace : TEXCOORD3) : COLOR
{
	//transform from RT space to texture space.
	float2 l_shadowtexC = 0.5 * a_position_lightspace.xy / a_position_lightspace.w + float2(0.5, 0.5);
	l_shadowtexC.y = 1.0f - l_shadowtexC.y;

	float l_lightamount = 1.0f;

	// l_shadowtexC.x/y will have values between 0.0 and 1.0, if they are in the texturing area
	// - only then do we have to consider any kind of shadow
	if((!(l_shadowtexC.x < 0.0f || l_shadowtexC.x > 1.0f)) && (!(l_shadowtexC.y < 0.0f || l_shadowtexC.y > 1.0f)))
	{
		l_lightamount = (tex2D(g_shadow_sampler, l_shadowtexC) + g_shadowepsilon < a_position_lightspace.z / a_position_lightspace.w) ? 0.0f : 1.0f;

		if(l_lightamount < 1.0f)
			l_lightamount = g_shadowweight;
	}
	a_normal = normalize(a_normal);

	float4 l_diffuse = g_light_directional_diffuse * DiffuseFactor(a_normal, -g_light_directional_direction.xyz);

	// Light it
	float4 l_finalcolor = (tex2D(g_texsampler0, a_texcoord0) * (l_diffuse + g_light_ambient)) * l_lightamount;	// base color

	return l_finalcolor;
}

// ----------------------------------------------------------
// Technique: RenderScene
// Desc: Renders scene objects
// ----------------------------------------------------------
technique SimpleTexture
{
	pass p0
	{
		VertexShader = compile vs_2_0 VSTex0();
		PixelShader = compile ps_2_0 PSTex0();
	}
}






Share this post


Link to post
Share on other sites
Short answer: try using orthogonal shadow maps (as opposite to projective shadow maps).

Reason:
Linear distribution of z values. In projective SM, depth values are "more thightly packed" when far away from the camera. Thus a constant epsilon will be offseting more the far objects, and less (to nearly nothing) the near objects.

Of course, it brings some problems of its own, as it's unable to cover nice frustum-shaped areas (at least not without some matrix-voodoo tweaking).


As for the blocky-thingy - that the sad thing about the SM.
The least you can do is to sample 4 times for four neighbour pixels, compare, and perform some kind of linear interpolation of the results (but not depths, but results of comparison). DX SDK Shadow Map sample has the implementation.

Also, you might want to look at this thread:
Need help to convert DX sample "Shadowmap" so it uses directional light.

Cheers.
~def

Share this post


Link to post
Share on other sites
Actually, most of those problems are because you're not using the shadow maps correctly.

Shadow maps affect the lighting equation. Thus, they must be part of the lighting calculation, just like N dot L. The lighting equation becomes something like "outLight = ambientLight + shadowMap * (diffuseLight * N dot L)". It's clear that you're not doing this in your screen shots: instead, you're using the shadow maps as a "darkening factor" after the lighting is already computed.

The reason this problem is obvious is because the ugly stripes all show up on the already dark-shaded sides of the cubes. If you did the lighting correctly, it wouldn't matter if the shadows aliased with the dark sides of the cubes or not.

Share this post


Link to post
Share on other sites
Deffer:
I already use orthogonal lights. Im not sure if its visible from the screenshots, since the area is quite small, but all the shadows are parallel.

By the way, the link you sent, was a thread started by me, hehe.

I built my shader over the DX-sample, so I will try to put back in the sampling of neighbours (I removed it in a learning phase, where I wanted to keep the code simple for comprehensibility).

hplus0603:
Wierd name you have there :)

[I deleted some comments here, as they are totally irrelevant now - they were quite confused - see Edit comment]



Edit:
I went back and tore my shader apart. It seems my only problem was in my lighting calculation.
As hplus0603 pointed out, I did not factor my lightamount into the equation, but instead added it afterwards.

Thanx alot hplus0603!!

I altered:
float4 l_diffuse = g_light_directional_diffuse * DiffuseFactor(a_normal, -g_light_directional_direction.xyz);
float4 l_finalcolor = (tex2D(g_texsampler0, a_texcoord0) * (l_diffuse + g_light_ambient)) * l_lightamount; // base color


To:
float4 l_diffuse = g_light_directional_diffuse * (DiffuseFactor(a_normal, -g_light_directional_direction.xyz) * l_lightamount + g_light_ambient);
float4 l_finalcolor = tex2D(g_texsampler0, a_texcoord0) * l_diffuse;


Result is perfect shadows :)
(I already implemented the multisampling for softer shadows, but I just wanted to show how it looks with the implementation shown in the above example).
screeny

[Edited by - Mercenarey on December 18, 2005 4:37:05 AM]

Share this post


Link to post
Share on other sites

This topic is 4377 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this