I'm fighting for long time with shadows in my projects. Spent on it a lot of time and slowly getting angry and annoyed. I encountered two problems with two shadow mapping technique in Deferred Rendering:
1.
Pic.1
Pic.2
VSM: First image is non blurred vsm, only with linear filtering. Doesn't look so bad.
But on second there's blurred one. And there comes the problem. Shadow looks is not even blurred, whole penumbra which should be soft is 'eaten', and pixel is not shadowed. I'm using G16R16F format. Really don't know what cause this error. Here is code:
Generating vsm:
VSOUTPUT_SHADOW VS_Shadow( float4 inPosition : POSITION )
{
// Output struct
VSOUTPUT_SHADOW OUT = (VSOUTPUT_SHADOW)0;
float4 worldPos = mul( inPosition, matWorld );
// Output the transformed position
OUT.vPosition = mul( worldPos, matLightViewProj );
// Output the scene depth
OUT.fDepth = length(mul(worldPos, matLightView).xyz) / 2048.0f;
return OUT;
}
float4 PS_Shadow( VSOUTPUT_SHADOW IN ) : COLOR0
{
// Output the scene depth
return float4(IN.fDepth, (IN.fDepth*IN.fDepth), 0.0f, 1.0f );
}
Drawing vsm
float Vsm( float2 tex, float fragDepth )
{
fragDepth /= 2048.0f;
fragDepth -= 0.00001;
float lit = (float)0.0f;
float2 moments = tex2D(ShadowSampler, tex);
float E_x2 = moments.y;
float Ex_2 = moments.x * moments.x;
float variance = min(max(E_x2 - Ex_2, 0.0f) + 0.00001f, 1.0f);
float mD = (moments.x - fragDepth );
float mD_2 = mD * mD;
float p = variance / (variance + mD_2 );
lit = max( p, fragDepth <= moments.x );
return lit;
}
...
float fDepth = length( vLightPosition - vWorldPos );
float4 vProjCoord = mul( float4(vWorldPos, 1.0f), matLightViewProj );
vProjCoord /= vProjCoord.w;
// Rescale viewport to be [0,1] (texture coordinate space)
float2 shadowTex = vProjCoord.xy * float2(0.5, -0.5) + 0.5f;
float ShadowTerm = Vsm(shadowTex, fDepth);
ShadowTerm = saturate(ShadowTerm*2-1);
...
2. Pic.1
Pic.2
Second problems is with standard PCF Shadow Maps. Since i'm trying to get them working under deferred renderer, they're not working as they should.
On first pic there's really high biasing, caused by... don't know what. After huge increase of bias(Second Pic) removes biasing but shadow looks poorly and there is no PCF. Using R32F for shadow map.
Generating:
// Shadow generation vertex shader
VSOUTPUT_SHADOW VS_Shadow( float4 inPosition : POSITION )
{
// Output struct
VSOUTPUT_SHADOW OUT = (VSOUTPUT_SHADOW)0;
float4 worldPos = mul( inPosition, matWorld );
// Output the transformed position
OUT.vPosition = mul( worldPos, matLightViewProj );
// Output the scene depth
OUT.fDepth = OUT.vPosition.z;
return OUT;
}
float4 PS_Shadow( VSOUTPUT_SHADOW IN ) : COLOR
{
// Output the scene depth
return float4( IN.fDepth, IN.fDepth, IN.fDepth, 1.0f );
}
Drawing:
float ShadowPCF(float4 vProjCoord)
{
// Generate the 9 texture co-ordinates for a 3x3 PCF kernel
float4 vTexCoords[9];
// Texel size
float fTexelSize = 1.0f / 512.0f;
// Grab the shadow term
float fShadowTerm = 0.0f;
vTexCoords[0] = vProjCoord;
vTexCoords[1] = vProjCoord + float4( -fTexelSize, 0.0f, 0.0f, 0.0f );
vTexCoords[2] = vProjCoord + float4( fTexelSize, 0.0f, 0.0f, 0.0f );
vTexCoords[3] = vProjCoord + float4( 0.0f, -fTexelSize, 0.0f, 0.0f );
vTexCoords[6] = vProjCoord + float4( 0.0f, fTexelSize, 0.0f, 0.0f );
vTexCoords[4] = vProjCoord + float4( -fTexelSize, -fTexelSize, 0.0f, 0.0f );
vTexCoords[5] = vProjCoord + float4( fTexelSize, -fTexelSize, 0.0f, 0.0f );
vTexCoords[7] = vProjCoord + float4( -fTexelSize, fTexelSize, 0.0f, 0.0f );
vTexCoords[8] = vProjCoord + float4( fTexelSize, fTexelSize, 0.0f, 0.0f );
// Sample each of them checking whether the pixel under test is shadowed or not
for( int j = 0; j < 9; j++ )
{
float A = tex2Dproj( ShadowSampler, vTexCoords[j] ).r;
float B = vProjCoord.z - 0.0001f;
// Texel is shadowed
fShadowTerm += A < B ? 0.1f : 1.0f;
}
// Get the average
return fShadowTerm = fShadowTerm / 9.0f;
};
...
float4 posInShadow = mul( float4(vWorldPos,1), matTexture );
float ShadowTerm = ShadowPCF(posInShadow);
...
Hope somebody will help me One day more on this and i'm gonna explode .
Thanks.