Summed area table(SAT) Variance Shadow Map Question

Started by
0 comments, last by Neooooo 1 year, 2 months ago

Recently, I am learning SAT VSM on Gpu Gem3. I try my best to achieve similar result of demo on Directx12.
However, I meet some problems that I can not solve or understand when programming. I wish YOU can help me and I will appreciate for that.

My questions :

  • In Chapter 8 of Gpu Gems3, the author suggested that uint32 format SAT can avoid numerical precision error except attention on overflow. There is a saying in this paper:“Fortunately,the overflow behavior in Direct3D 10 (wraparound) actually work to our advantage. “What is that meaning? And I can not find any method to handle this problem in source code and shaders.And I find that the overflow is very common in uint format SAT. You can see the following picture.

Every curve describes the position of overflow.So if we do nothing for this,how could we get correct mean and variance? And if a filter is located at different overflow area , the result is right?

  • Question 2 looks like a shadow antialiasing . When I finish my programming about SAT VSM and the SAT format is uint32. But the result is not good like the demo. You can see a screenshot of my app.

As you can see,there is a very obvious jagged antialiasing at the edge of the shadow.But I can’t see this error in the demo with same shadow resolution.And I have tried to improve shadow map resolution and the filter minimum size.Unfortunately both methods work nothing.I can not understand where I am wrong.

I post my main shader code here for you.Here I use cascaded shadow map, so you can see Texture2DArray CascadedSAT and int CurrentCascadeIndex.For this question,you can just see this as normal Texture2D.

//Pixel shader ----Generate shadow map
uint2 SATVSM_INT_PS(VertexOut pin) : SV_TARGET
{
    MaterialData matdata = gMatData[gMatIndex];

    float4 diffuse = gDiffuseMap[matdata.DiffuseMapIndex].Sample(gsamLinearWrap,pin.TexC) * 	matdata.DiffuseAlbedo;
    #ifdef ALPHA_TEST
        clip(diffuse.a - 0.1f);
    #endif

    float depth = pin.PosH.z / pin.PosH.w;
    float depth2 = depth * depth;

    float2 moments = float2(depth,depth2);

	//g_NormalizedFloatToSATUINT = 1 << 18 
    uint2 MomentsUINT = uint2(round(moments * g_NormalizedFloatToSATUINT));

    return MomentsUINT;
}
//Compute filter pixel size
float2 GetFilterPixelSize(float2 dx , float2 dy, float2 shadowMapSize)
{
    return 2.0f * (abs(dx) + abs(dy)) * shadowMapSize;
}

//Get filter texel size and return left-upper point texcoords(is not pixel center)
float2 GetFilterTexelSizeAndLeftUpperCoords(
    in float2 texCoords,
    in float2 shadowMapSize,
    in float2 dx,
    in float2 dy,
    out float2 FilterSize)
{
    float2 texelSize = 1.0f / shadowMapSize;

    float2 FilterMinWidth = 1.5f;

	//g_SATUINTMaxFilterWidth = 128
    float2 FilterMaxWidth = g_SATUINTMaxFilterWidth;
    
    FilterSize = min((GetFilterPixelSize(dx,dy,shadowMapSize)),FilterMaxWidth);


    FilterSize = round(max(FilterMinWidth,FilterSize)) * texelSize;

    return texCoords - 0.5f * FilterSize;
}

//Get blineaer Weights and return centered left-upper point texcoords
float2 GetBilinearLeftUpperCoordsAndWeights(
    in float2 leftupperCoords,
    in float2 shadowMapSize,
    out float4 weights
)
{
    float2 texelSize = 1.0f / shadowMapSize;
    float2 Coords = leftupperCoords * shadowMapSize;

    float2 BilinearLeftUpperCoords = floor(Coords - 0.5f) + 0.5f;

    weights.xy = Coords - BilinearLeftUpperCoords;
    weights.zw = 1.0f - weights.xy;
    weights = weights.zxxz * weights.wwyy;

    return BilinearLeftUpperCoords * texelSize;
}

float ChebyshevPercentLit(
    in float2 Moments,
    in float  ComparedDepth
)
{
    float mean = Moments.x;
    float variance = Moments.y - mean * mean;

    if(ComparedDepth < mean)
    {
        return 1.0f;
    }
    //here min_variance for standard VSM = 0.000001f
    variance = min(1.0f,max(variance,0.001f));
    //using chebyshev inequality to compute possiblity of lit
    float upperBound = variance / (variance + (ComparedDepth - mean) * (ComparedDepth - mean));
    //allevating light bleeding
    return pow(upperBound,4.0f);
}

//Get SAT Sum
uint2 SampleSATSum(
    Texture2DArray<uint2> CascadedSAT,
    int CurrentCascadedIndex,
    float2 shadowMapSize,
    float4 texCoords,
    uint2 CoordsOffset
)
{
    uint4 RealCoords = uint4(texCoords * shadowMapSize.xyxy) - 1 + CoordsOffset.xyxy;

    uint2 lt = CascadedSAT.Load(int4(RealCoords.xy,CurrentCascadedIndex,0));
    uint2 lb = CascadedSAT.Load(int4(RealCoords.xw,CurrentCascadedIndex,0));
    uint2 rt = CascadedSAT.Load(int4(RealCoords.zy,CurrentCascadedIndex,0));
    uint2 rb = CascadedSAT.Load(int4(RealCoords.zw,CurrentCascadedIndex,0));

    return (rb - lb - rt + lt);
}

	void SampleSATAverageOnFourPoint(
        Texture2DArray<uint2> CascadedSAT,
        int CurrentCascadedIndex,
        float2 shadowMapSize,
        float4 texCoords,
        out float2 X,
        out float2 Y,
        out float2 Z,
        out float2 W
    )
    {
        //Sample Distribution ---- the sequence is relevent with weights
        //
        // X ------ Y
        // |        |
        // |        |
        // W -------Z    
        //
        uint2 x = SampleSATSum(CascadedSAT,CurrentCascadedIndex,shadowMapSize,texCoords,uint2(0,0));
        uint2 y = SampleSATSum(CascadedSAT,CurrentCascadedIndex,shadowMapSize,texCoords,uint2(1,0));
        uint2 z = SampleSATSum(CascadedSAT,CurrentCascadedIndex,shadowMapSize,texCoords,uint2(1,1));
        uint2 w = SampleSATSum(CascadedSAT,CurrentCascadedIndex,shadowMapSize,texCoords,uint2(0,1));

        float2 dim = (texCoords.zw - texCoords.xy) * shadowMapSize;

        X = (float2)x/(dim.x * dim.y);
        Y = (float2)y/(dim.x * dim.y);
        Z = (float2)z/(dim.x * dim.y);
        W = (float2)w/(dim.x * dim.y);
    }
    
    //Bilinear interpolation
       float2 BilinearFourRange(
        float2 X,float2 Y,float2 Z,float2 W,float4 weights
    )
    {
        float2 result = 0.0f;
        result.x = dot(float4(X.x,Y.x,Z.x,W.x),weights);
        result.y = dot(float4(X.y,Y.y,Z.y,W.y),weights);
        return result;
    }
    
    //use bilinear interpolation to compute moments 
    float2 BilinearMomentsSAT(
        Texture2DArray<uint2> CascadedSAT,
        int CurrentCascadedIndex,
        float2 shadowMapSize,
        float2 texCoords
    )
    {
        float2 dx = ddx(texCoords);
        float2 dy = ddy(texCoords);

        float2 Size = 0.0f;
        float2 FilterUpperleftCoords = GetFilterTexelSizeAndLeftUpperCoords(texCoords,shadowMapSize,dx,dy,Size);
        float4 weights = 0.0f;
        float2 upperleftCoords = GetBilinearLeftUpperCoordsAndWeights(FilterUpperleftCoords,shadowMapSize,weights);

        float4 FilterRange = upperleftCoords.xyxy + float4(0,0,Size);

        float2 X,Y,Z,W = 0.0f;
        SampleSATAverageOnFourPoint(CascadedSAT,CurrentCascadedIndex,shadowMapSize,FilterRange,X,Y,Z,W);

        //Re-normalized before bilinear
        float SATUINTToNormalizedFloat = 1.0f / g_NormalizedFloatToSATUINT;
        X *= SATUINTToNormalizedFloat;
        Y *= SATUINTToNormalizedFloat;
        Z *= SATUINTToNormalizedFloat;
        W *= SATUINTToNormalizedFloat;

        float2 Moments = BilinearFourRange(X,Y,Z,W,weights);
        return Moments;
    }

    //Final function for SAT bilinear VSM(UINT)
    float BilinearSATVarianceShadowMapPercentLit(
        in Texture2DArray<SAT_FORMAT> CascadedSAT,
        in int CurrentCascadedIndex,
        in float2 shadowMapSize,
        in float3 texCoords
    )
    {
        //Bilinear
        float2 Moments = BilinearMomentsSAT(CascadedSAT,CurrentCascadedIndex,shadowMapSize,texCoords.xy);
        float  PercentLit = ChebyshevPercentLit(Moments,texCoords.z);

        return PercentLit;
    }

Finally,I have tried to debug the .exe file of the demo just like use RenderDoc or Pix to debug Directx12 App. However,the demo was written by Direct3D 10.And I have no idea about which software can debug Direct3D 10 app on Win10.So if you know some app can do this or some other methods can achieve similar prupose,please let me know!

Thank you very much for reading my questions.

None

This topic is closed to new replies.

Advertisement