🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Implementing nvidia's PCSS

Started by
1 comment, last by adam7 3 years ago

Hi I'm trying to implement nvidia's PCSS into my engine, but Im having issues. Currently, this is the result that I get:

as you can see this is not the desired output (you can see the shadow depth map in the top right). I am unsure if this is an issue with the shadowmap coordinates that are required for this implementation. The nvidia paper does not mention how to calculate this value but from reading around I have determined that it's done like this:

float4 coords = mul(input.lightViewMatrix, float4(input.worldPos.xyz, 1.0f));
coords = float4(coords.xyz / coords.w, 1.0f);

Another question I have is related to the shadowmap bias. It seems like at no point in the nvidia implementation tis here a mention of a bias value so I am unsure where to add this into the shadow calculation. I would like to add a sloped scale bias so that directonal light shadows are correct.

Here is my code, it is basically the same thing that's in the nvidia paper:

float PenumbraSize(float zReceiver, float zBlocker) {
    return (zReceiver - zBlocker) / zBlocker;
}



void FindBlocker(out float avgBlockerDepth, out float numBlockers, float2 uv, float zReceiver) {
    //This uses similar triangles to compute what
    //area of the shadow map we should search
    float searchWidth = LIGHT_SIZE_UV * (zReceiver - NEAR_PLANE) / zReceiver;
    float blockerSum = 0;
    numBlockers = 0;

    for (int i = 0; i < BLOCKER_SEARCH_NUM_SAMPLES; ++i) {
        float shadowMapDepth = depthMapTexture3.SampleLevel(SampleTypeClamp, uv + poissonDisk[i] * searchWidth, 0);
        if (shadowMapDepth < zReceiver) {
            blockerSum += shadowMapDepth;
            numBlockers++;
        }
    }

    avgBlockerDepth = blockerSum / numBlockers;
}

float PCF_Filter(float2 uv, float zReceiver, float filterRadiusUV)
{
    float sum = 0.0f;
    for (int i = 0; i < PCF_NUM_SAMPLES; ++i)
    {
       float2 offset = poissonDisk[i] * filterRadiusUV;
       // float2 offset = float2(0.1223f, 0.4343f);
        sum += depthMapTexture3.SampleCmpLevelZero(SampleComp, uv + offset, zReceiver);
    }
    return sum / PCF_NUM_SAMPLES;
}

float PCSS(Texture2D shadowMapTex, float4 coords, float3 N)
{
    float2 uv = coords.xy;
    float zReceiver = coords.z; // Assumed to be eye-space z in this code

    // STEP 1: blocker search
    float avgBlockerDepth = 0;
    float numBlockers = 0;
    FindBlocker(avgBlockerDepth, numBlockers, uv, zReceiver);
    if (numBlockers < 1)
        //There are no occluders so early out (this saves filtering)
        return 1.0f;
    // STEP 2: penumbra size
    float penumbraRatio = PenumbraSize(zReceiver, avgBlockerDepth);
    float filterRadiusUV = penumbraRatio * LIGHT_SIZE_UV * NEAR_PLANE / coords.z;

    // STEP 3: filtering
    return PCF_Filter(uv, zReceiver, filterRadiusUV);
   // return 1.0f;
}

///////////////////////////////////
// this part happens main function
float4 coords = mul(input.lightView, float4(input.worldPos.xyz, 1.0f));
float4 coords2 = float4(coords.xyz / coords.w, 1.0f);
 
 




// N is surface normal for bias calculation

// shadowFactor is multiplied with result of lighting calculation later on
shadowFactor = PCSS(depthMapTexture3, coords2, N);



Thanks for your help

Advertisement

So I have made some progress by computing a light view position in the vertex shader and then putting it into the 0.0 to 1.0 range like this:

 output.lightViewPosition = mul(input.position, worldMatrix);
 output.lightViewPosition = mul(output.lightViewPosition, lightViewMatrix);
 output.lightViewPosition = mul(output.lightViewPosition, lightProjectionMatrix);
 
 float4 coords = float4(input.lightViewPosition.xyz / input.lightViewPosition.w / 2.0f + 0.5f, 1.0f);

Which gives something that looks like this

Which looks more correct but still not entirely…

This topic is closed to new replies.

Advertisement