hi,
our engine is using deferred shading atm and i am implementing variance shadow maps. At the moment i do the following:
-> render depth map
-> blur depth map
-> set to the shader
-> apply light calculations
somehow the scene is not shadowing and i have no clue why. I have broken down the shader to only output the chevby's calculations, but they always result in 'lit' as it appears. I was wondering if you guys had any clue of what might go wrong. I removed the blur part for now since that only makes more possible error spots.
the shader for depth map:
//Our shader's global variables. We have 2 different output structures,
//one for the DepthMap technique, and one for the Scene technique,
//this is because they both require different values (HLSL requires that all
//values of an output structure be set).
struct VS_INPUT
{
float4 Position : POSITION;
float2 TexCoords : TEXCOORD0;
};
struct DEPTH_VS_OUTPUT
{
float4 Position : POSITION;
float4 WorldPosition : TEXCOORD1;
};
struct SCENE_VS_OUTPUT
{
float4 Position : POSITION;
float2 TexCoords : TEXCOORD0;
float4 WorldPosition : TEXCOORD1;
// ShadowProjection is similar to Position, except its the position
// from the light's view, not the camera. We need both to be able to project
// our shadow map.
float4 ShadowProjection : TEXCOORD2;
};
shared float4x4 viewProjection;
shared float4x4 view;
float4x4 world;
// The position of our light
shared float3 cameraPosition;
// The far clip distance of our light's view matrix.
//We use this value to normalise our distances
//(so that they fit into the 0.0 - 1.0 colour range in HLSL)
float farClip = 1000;
//Depth Map Pass
//==============
//This part of the shader is used to render the scene from the view of our spot light.
//It's just like a normal shader, except instead of colouring the models with a texture,
//it gives the pixels a colour based on their distance from the light.
DEPTH_VS_OUTPUT Depth_VS (VS_INPUT Input)
{
DEPTH_VS_OUTPUT Output;
// Our standard WVP multiply, using the light's
//View and Projection matrices
Output.Position = mul(float4(Input.Position.xyz, 1.0f), mul(world, viewProjection));
// We also keep a copy of our position that is only
//multiplied by the world matrix. This is
// because we do not want the camera's angle/position to
//affect our distance calculations
Output.WorldPosition = mul(float4(Input.Position.xyz, 1.0f), world);
//Output.WorldPosition /= Output.WorldPosition.w;
return Output;
}
float4 Depth_PS (DEPTH_VS_OUTPUT Input) : COLOR0
{
// Get the distance from this pixel to the light,
//we divide by the far clip of the light so that it
//will fit into the 0.0-1.0 range of pixel shader colours
float depth = length(cameraPosition - Input.WorldPosition) / farClip;
return float4(depth, depth*depth, 0, 0);
}
technique DepthMap
{
pass P0
{
VertexShader = compile vs_2_0 Depth_VS();
PixelShader = compile ps_2_0 Depth_PS();
}
}
where farclip = the range of the spotlight and the texture is R32G32B32A32.
spotlight shader:
float4x4 world;
shared float4x4 view;
shared float4x4 projection;
float4x4 lightViewProjection;
//color of the light
float3 diffuseColor;
//position of the camera, for specular light
shared float3 cameraPosition;
//this is used to compute the world-position
shared float4x4 invertViewProjection;
//this is the position of the light
float3 lightPosition;
//how far does this light reach
float lightRadius;
float3 lightDirection;
float lightIntensity;
float lightDecayExponent;
float lightAngleCosine;
// diffuse color, and specularIntensity in the alpha channel
texture colorMap : ColorMap;
// normals, and specularPower in the alpha channel
texture normalMap : NormalMap;
//depth
texture depthMap : DepthTexture;
texture shadowMap : ShadowMap;
Texture shadowMapMask : ShadowMapMask;
sampler colorSampler = sampler_state
{
Texture = (colorMap);
AddressU = CLAMP;
AddressV = CLAMP;
MagFilter = LINEAR;
MinFilter = LINEAR;
Mipfilter = LINEAR;
};
sampler depthSampler = sampler_state
{
Texture = (depthMap);
AddressU = CLAMP;
AddressV = CLAMP;
MagFilter = POINT;
MinFilter = POINT;
Mipfilter = POINT;
};
sampler normalSampler = sampler_state
{
Texture = (normalMap);
AddressU = CLAMP;
AddressV = CLAMP;
MagFilter = POINT;
MinFilter = POINT;
Mipfilter = POINT;
};
sampler shadowSampler = sampler_state
{
Texture = <shadowMap>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = CLAMP;
AddressV = CLAMP;
};
sampler maskSampler = sampler_state
{
Texture = <shadowMapMask>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = CLAMP;
AddressV = CLAMP;
};
struct VertexShaderInput
{
float3 Position : POSITION0;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float4 ScreenPosition : TEXCOORD0;
};
float g_VSMMinVariance = 0.000001; // Minimum variance for VSM
float ChebyshevUpperBound(float2 Moments, float Mean, float g_MinVariance)
{
// One-tailed inequality valid if Mean > Moments.x
float p = (Mean <= Moments.x);
// Compute variance.
float Variance = Moments.y - (Moments.x*Moments.x);
Variance = max(Variance, g_MinVariance);
//Compute probabilistic upper bound
float d = Moments.x - Mean;
float p_max = Variance / (Variance + d * d);
//return Mean * p;
//return p_max;
return max(p, p_max);
};
float ShadowContribution(float2 LightTexCoord, float DistanceToLight)
{
// Read the moments from the variance shadow map.
//float2 Moments = texShadow.Sample(ShadowSampler, LightTexCoord).xy;
float2 moments = tex2D(shadowSampler, LightTexCoord).xy;
// Compute the Chebyshev upper bound.
return ChebyshevUpperBound(moments, DistanceToLight, g_VSMMinVariance);
};
float linstep(float min, float max, float v)
{
return clamp((v - min) / (max - min), 0, 1);
};
float ReduceLightBleeding(float p_max, float Amount)
{
// Remove the [0, Amount] tail and linearly rescale (Amount, 1].
return linstep(Amount, 1, p_max);
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
//processing geometry coordinates
float4 worldPosition = mul(float4(input.Position,1), world);
float4 viewPosition = mul(worldPosition, view);
output.Position = mul(viewPosition, projection);
//output.Normal = mul(input.Normal, World);
output.ScreenPosition = output.Position;
return output;
}
float2 halfPixel : HalfPixel;
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
//obtain screen position
input.ScreenPosition.xy /= input.ScreenPosition.w;
//obtain textureCoordinates corresponding to the current pixel
//the screen coordinates are in [-1,1]*[1,-1]
//the texture coordinates need to be in [0,1]*[0,1]
float2 texCoord = 0.5f * (float2(input.ScreenPosition.x,-input.ScreenPosition.y) + 1);
//allign texels to pixels
texCoord -=halfPixel;
//read depth
float depthVal = tex2D(depthSampler,texCoord).r;
//compute screen-space position
float4 position;
position.xy = input.ScreenPosition.xy;
position.z = depthVal;
position.w = 1.0f;
//transform to world space
position = mul(position, invertViewProjection);
position /= position.w;
//surface-to-light vector
float3 lightVector = lightPosition - position;
//compute attenuation based on distance - linear attenuation
float attenuation = saturate(1.0f - length(lightVector)/lightRadius);
//normalize light vector
lightVector = normalize(lightVector);
float SdL = dot(lightDirection, -lightVector);
if(SdL > lightAngleCosine)
{
float2 projectedTexCoords;
float4 ShadowProjection = mul(position, lightViewProjection);
projectedTexCoords[0] = (ShadowProjection.x /
ShadowProjection.w / 2.0f) + 0.5f;
projectedTexCoords[1] = (-ShadowProjection.y /
ShadowProjection.w / 2.0f) + 0.5f;
//////// for shadow
float len = length(lightPosition - position) / lightRadius;
float shadow = ShadowContribution(projectedTexCoords, len);
float spotIntensity = pow(SdL, lightDecayExponent);
//get normal data from the normalMap
float4 normalData = tex2D(normalSampler,texCoord);
//tranform normal back into [-1,1] range
float3 normal = 2.0f * normalData.xyz - 1.0f;
//get specular power
float specularPower = normalData.a * 255;
//get specular intensity from the colorMap
float specularIntensity = tex2D(colorSampler, texCoord).a;
//compute diffuse light
float NdL = max(0,dot(normal,lightVector));
float3 diffuseLight = NdL * diffuseColor.rgb;
//reflection vector
float3 reflectionVector = normalize(reflect(-lightVector, normal));
//camera-to-surface vector
float3 directionToCamera = normalize(cameraPosition - position);
//compute specular light
float specularLight = specularIntensity * pow( saturate(dot(reflectionVector, directionToCamera)), specularPower);
attenuation *= spotIntensity;
//take into account attenuation and lightIntensity.
//return (lightIntensity * float4(diffuseLight.rgb,specularLight) * attenuation) * shadow;
return shadow; // * float4(diffuseLight.rgb, specularLight) * attenuation * lightIntensity;
}
return float4(0,0,0,0);
}
technique Technique1
{
pass Pass1
{
VertexShader = compile vs_2_0 VertexShaderFunction();
PixelShader = compile ps_2_a PixelShaderFunction();
}
}
";
where radius = the same as the farclip in depth map rendering and the shadowSampler is the blurred depth map.
does anyone have any clue? the shader codes are partly from GPU Gems 3 and an xna article on ziggyware.com