PDA

View Full Version : Trouble Implementing Gradient Shadow Map


jbizzler
24-Mar-2007, 20:04
Now that I finally got DX10 to let me write to my shadow map after using it in a render pass, I need to eliminate the the surface acne. I have Shader X5, and it talks about Gradient Shadow Maps, but mostly refers to the chapter in Shader X4, which I do not have. Here's my pixel shader wihout any gradient:

float4 PS(PS_In input) : SV_TARGET
{
float amb = 0.4f;
float diff = 0;
float spec = 0;

float2 sampleCoord = 0.5f * input.LightPos.xy / input.LightPos.w + float2(0.5, 0.5);
sampleCoord.y = 1.0f - sampleCoord.y;

if(input.LightPos.z < ShadowMap.Sample(Linear, sampleCoord).x + 0.00005f)
{
float3 N = normalize(input.Norm);
float3 V = normalize(EyePos - input.wPos);
float3 R = normalize(reflect(-L, N));

diff = saturate(dot(N, L));
spec = pow(saturate(dot(V, R)), 32);
}

float4 output;
output.rgb = (float3)0.5f * (amb + diff + spec);
output.a = 1;
return output;
}
Which turns out as expected, but not good enough.

And then when I try and implement the gradient:

float4 PS(PS_In input) : SV_TARGET
{
float amb = 0.4f;
float diff = 0;
float spec = 0;

float2 gradientVector = float2(input.LightPos.z / input.LightPos.x, input.LightPos.z / input.LightPos.y);
float gradient = length(gradientVector);

float2 sampleCoord = 0.5f * input.LightPos.xy / input.LightPos.w + float2(0.5, 0.5);
sampleCoord.y = 1.0f - sampleCoord.y;

float difference = ShadowMap.Sample(Linear, sampleCoord).x - input.LightPos.x;

if(saturate(difference / gradient + 1))
{
float3 N = normalize(input.Norm);
float3 V = normalize(EyePos - input.wPos);
float3 R = normalize(reflect(-L, N));

diff = saturate(dot(N, L));
spec = pow(saturate(dot(V, R)), 32);
}

float4 output;
output.rgb = (float3)0.5f * (amb + diff + spec);
output.a = 1;
return output;
}
Which turns out all with shadow in random places. What am I doing wrong?

Inane_Dork
24-Mar-2007, 21:23
I have no D3D10/SM4 experience and have not seen gradient shadow mapping, but could you explain this line?
if(saturate(difference / gradient + 1))
Whatever 'difference / gradient' turns out to be, adding 1 and saturating it will always yield 1, I would think. And you should probably be testing the result to be greater than or less than a certain value. I don't know what testing a float for true/false means.

jbizzler
24-Mar-2007, 22:23
Nor do I. This is just a SM4 implementation of the pseudocode in Shader X5, that they don't explain bust instead refer to Shader X4. I can't seem to find any documentation on it other than it.

maxest
11-Jul-2011, 15:20
Yeah, it's a bit late but it's better than never... The points is that you misinterpreted the formula with (dz/dx, dz/dy). These are partial derivatives, which can be computed taking finite differencing.

Here you have some nice slides: http://www.slideshare.net/ohyecloudy/42-eliminating-surface-acne-with-gradient-shadow-mapping

And code I've just written:

float SSM(float2 projTexCoord, float depth, float bias)
{
float texelSize = 1.0f / shadowMapSize;

float d1 = tex2D(shadowMapSampler_point, projTexCoord + float2(+texelSize, 0.0f));
float d2 = tex2D(shadowMapSampler_point, projTexCoord + float2(-texelSize, 0.0f));
float d3 = tex2D(shadowMapSampler_point, projTexCoord + float2(0.0f, +texelSize));
float d4 = tex2D(shadowMapSampler_point, projTexCoord + float2(0.0f, -texelSize));

float dx = abs(d1 - d2);
float dy = abs(d3 - d4);

float gradient = length(float2(dx, dy));

float slopeScaleBias = 2.0f;

return tex2D(shadowMapSampler_point, projTexCoord) > depth - slopeScaleBias*gradient;
}


Note that gradient can also be compute with gradient = max(dx, dy). Length just seems a bit more natural.