Sign in to follow this  
bjarnia

Shadow mapping: Receiver Plane Depth Bias?

Recommended Posts

I have stumbled upon references to the use of "Receiver Plane Depth Bias" to alleviate errors in traditional shadow maps. Such as here (page 37): http://ati.amd.com/developer/gdc/2006/Isidoro-ShadowMapping.pdf As well as realizing that there is a DX renderstate that seems to set "SlopeScaleDepthBias" which to my understanding is the same thing. I have tried to integrate the implementation in the above presentation with no luck at all, as well as trying a lot of different values for that renderstate with little effect. Can someone point me to a simple sample or a paper that uses this technique properly? Maybe my googling skills are just wearing thin :P I am using an orthographic light if that makes a difference. This is how my very naive implementation looks: http://www.steik.org/dump/Cosmopolis2010-02-1718-56-36-56.png I'll just include my HLSL code too... What is confusing me the most is if I can just use my normal shadow texture coordinates? I'm thinking not? I am anyway :) The code has been modified slightly to account for lack of Fetch4 that the presentation assumes.

float2 quadOffsets[] = { float2( 0,  0), float2( 1,  0), float2( 1,  1), float2( 1,  0), float2( 1, -1), float2( 0, -1), float2(-1, -1), float2(-1,  0), float2(-1,  1)};


float SamplePCFSlope(sampler2D depthSampler, float4 texCoord, float bias, float texelSize, float mapSize)
{
    //Packing derivatives of u,v, and distance to light source w.r.t. screen space x, and y
    float4 duvdist_dx = ddx(texCoord);
    float4 duvdist_dy = ddy(texCoord);

    //Invert texture Jacobian and use chain rule to compute ddist/du and ddist/dv
    // |ddist/du| = |du/dx du/dy|-T * |ddist/dx|
    // |ddist/dv| |dv/dx dv/dy| |ddist/dy|
    
    //Multiply ddist/dx and ddist/dy by inverse transpose of Jacobian
    float invDet = 1 / ((duvdist_dx.x * duvdist_dy.y) - (duvdist_dx.y * duvdist_dy.x) );
    
    //Top row of 2x2
    float2 ddist_duv;
    ddist_duv.x = duvdist_dy.y * duvdist_dx.w ; // invJtrans[0][0] * ddist_dx
    ddist_duv.x -= duvdist_dx.y * duvdist_dy.w ; // invJtrans[0][1] * ddist_dy
    
    //Bottom row of 2x2
    ddist_duv.y = duvdist_dx.x * duvdist_dy.w ; // invJtrans[1][1] * ddist_dy
    ddist_duv.y -= duvdist_dy.x * duvdist_dx.w ; // invJtrans[1][0] * ddist_dx

    ddist_duv *= invDet;

    float percentInLight = 0;
    float2 texCoordOffset;
    float shadowMapVals;
    float dist;
    float4 inLight;
    float invNumTaps = 1.0 / 9.0f;

    // Not ideal, too lazy to set in code for now
    float2 g_vFullTexelOffset = float2(texelSize, texelSize);

    //compute depth offset and PCF taps 4 at a time
    for(int i=0; i < 9; i++)
    {
        //offset of texel quad in texture coordinates;
        texCoordOffset = (g_vFullTexelOffset * quadOffsets[i] );

        //shadow map values
        shadowMapVals = tex2D(depthSampler, texCoord.xy + texCoordOffset.xy ).r;
        
        //Apply receiver plane depth offset
        dist = texCoord.w + (ddist_duv.x * texCoordOffset.x) + (ddist_duv.y * texCoordOffset.y);
        //dist = texCoord.z + bias; // Normal shadow mapping.. Works fine
        inLight = ( dist < shadowMapVals );

        percentInLight += inLight * invNumTaps;
    }

    return percentInLight;
}

Share this post


Link to post
Share on other sites

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