The problem is that not only do I get a shadow where it should be, I also get shading in areas where I do not want it.
The picture below shows where the shadow should be (yellow circle). The shadow map is the second from the left at the top of the picture. The light position is marked in white along with its bounding frustum.
My HLSL shader is as follows:
//=============================================
//---[Includes]--------------------------------
//=============================================
#include "..\include\Constants.fxh"
#include "..\include\Common.fxh"
//=============================================
//---[XNA to HLSL Variables]-------------------
//=============================================
bool CastShadow;
texture DepthMap;
float2 HalfPixel;
float4x4 InvViewProjection;
float3 LightColour;
float3 LightDirection;
float LightIntensity;
float3 LightPosition;
float4x4 LightViewProjection;
texture NormalMap; // Normals (with specular power in the alpha channel)
texture ShadowMap;
//=============================================
//---[Texture Samplers]------------------------
//=============================================
sampler NormalSampler = sampler_state
{
Texture = (NormalMap);
AddressU = CLAMP;
AddressV = CLAMP;
MagFilter = POINT;
MinFilter = POINT;
Mipfilter = POINT;
};
sampler DepthSampler = sampler_state
{
Texture = (DepthMap);
AddressU = CLAMP;
AddressV = CLAMP;
MagFilter = POINT;
MinFilter = POINT;
Mipfilter = POINT;
};
sampler ShadowSampler = sampler_state
{
Texture = (ShadowMap);
AddressU = CLAMP;
AddressV = CLAMP;
MagFilter = POINT;
MinFilter = POINT;
Mipfilter = POINT;
};
//=============================================
//---[Structs]---------------------------------
//=============================================
struct VertexShaderInput
{
float4 Position : POSITION0;
float2 TextureCoordinates : TEXCOORD0;
};
struct VertexShaderOutputToPS
{
float4 Position : POSITION0;
float2 TextureCoordinates : TEXCOORD0;
};
struct PixelShaderOutput
{
float4 Color : COLOR0; // Color
float4 SGR : COLOR1; // [R] Specular, [G] Glow and Reflection values
float4 Tangent : COLOR2; // Normal / Tangent map
float4 Depth : COLOR3; // Depth map
};
//=============================================
//---[Functions]-------------------------------
//=============================================
// [Output]
// return 1 for fully lit
// return 0 for fully occluded pixels
// @param fragDepth = light space depth
// @param tex = texture coordinates
// @param texShadowMap = shadow map texture
// @param dTex_dX, dTex_dY = partial derivative with respect to the screen-space x and y coordinates.
float IsNotInShadow(float fragDepth, float3 tex, float3 dTex_dX, float3 dTex_dY)
{
float2 receiverPlaneDepthBias = ComputeReceiverPlaneDepthBias(dTex_dX, dTex_dY);
//float2 fTexelSize = float2(1.0f / ShadowMapWidth, 1.0f / ShadowMapHeight);
//float2 g_shadowTexelSize = float2(fTexelSize.x, fTexelSize.y / CASCADE_LAYERS);
float texelSize = 1.0f / 1024;
float fractionalSamplingError = dot(float2(texelSize, texelSize / CASCADE_LAYERS), abs(receiverPlaneDepthBias));
// [DirectX 10] - VS 4.0 and PS 4.0 Miminum
// SampleGrad Arguments
// - SamplerState
// - Texture Coordinates
// - DDX
// - DDY
//return g_txShadow.SampleGrad(g_samShadowLinearClamp, tex, dTex_dX.xy, dTex_dY.xy).x > (fragDepth - EPSILON - fractionalSamplingError);
// [DirectX 9]
// ShadowSampler type ('SHADOW_MAP_TYPE') is:
// 'Texture2D' If TEXTURE_ARRAY is NOT defined
// 'Texture2DArray' If TEXTURE_ARRAY is defined
return tex2D(ShadowSampler, tex, dTex_dX.xy, dTex_dY.xy).r > (fragDepth - EPSILON - fractionalSamplingError);
}
//=============================================
//---[Vertex Shaders]--------------------------
//=============================================
VertexShaderOutputToPS VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutputToPS output = (VertexShaderOutputToPS)0;
// 'input.Position.w' should always equal 1
input.Position.w = 1;
output.Position = input.Position;
// [Texel To Pixel Align]
// • Half pixel offset for correct texel centering)
// • Should be done AFTER transformation
output.Position.xy -= HalfPixel;
output.TextureCoordinates = input.TextureCoordinates;
return output;
}
//=============================================
//---[Pixel Shaders]---------------------------
//=============================================
float4 DirectionalLightPS(VertexShaderOutputToPS input) : COLOR0
{
// [Normal]
float3 normalData = tex2D(NormalSampler, input.TextureCoordinates);
// Transform normal from [0, 1] texture coordinate range back into [-1, 1] range
float3 N = normalData.xyz * 2.0f - 1.0f;
N = normalize(N);
// [World Position]
float4 screenPosition;
screenPosition.x = input.TextureCoordinates.x * 2.0f - 1.0f;
screenPosition.y = -(input.TextureCoordinates.y * 2.0f - 1.0f);
screenPosition.z = tex2D(DepthSampler, input.TextureCoordinates).r;
screenPosition.w = 1.0f;
float4 worldPos = mul(screenPosition, InvViewProjection);
worldPos /= worldPos.w;
// ===============================================
// --[Shadow Calculations]------------------------
// ===============================================
// Shadow term (1 = no shadow)
float shadow = 1;
if (CastShadow)
{
// Find screen position as seen by the light
float4 lightScreenPos = mul(worldPos, LightViewProjection);
lightScreenPos /= lightScreenPos.w;
float depth; // Set by GetCascadeIndex
float3 dTex_dX, dTex_dY; // Set by GetCascadeIndex
float3 texShadow = GetCascadeIndex(lightScreenPos.xyz, worldPos.z, depth, dTex_dX, dTex_dY);
// Find shadow term (Range: [0, 1])
shadow = IsNotInShadow(depth, texShadow, dTex_dX, dTex_dY);
}
// ===============================================
// --[Lighting Calculations]----------------------
// ===============================================
/* ===============================================
* --[Diffuse Light]------------------------------
* ===============================================
* I = Di * Dc * N.L
*
* Where:
*
* I = Intensity Of Light
* Di = Diffuse Intensity [float]
* Dc = Diffuse Colour [float3]
* N = Surface Normal [float3]
* L = Direction From Pixel To Light [float3]
*
*/
float Di = LightIntensity;
float3 Dc = LightColour;
float NdotL = max(0, dot(N, -LightDirection)); // -LightDirection = toLight = Vertex to light
float3 DiffuseLight = Di * Dc * NdotL;
/* ===============================================
* --[Final Colour]-------------------------------
* ===============================================
*/
float4 colour = float4(DiffuseLight.rgb, 1);
colour.xyz *= shadow;
return colour;
}
//=============================================
//---[Techniques]------------------------------
//=============================================
technique DirectionalLight
{
pass Pass0
{
VertexShader = compile vs_3_0 VertexShaderFunction();
PixelShader = compile ps_3_0 DirectionalLightPS();
}
}
Currently I know that if I change the near clip values for directional light's projection matrix then the unwanted shadowing is made even worse.
What could be the cause of the extraneous shadowing?