Depth of Field shader problem

FoxMcCloud

Newcomer
I'm trying to write a Depth of Field shader using circle of confusion-based texture fetches. Here's my code so far (Cg):

Code:
#define DOF_TAP_COUNT 8
#define DOF_TAP_MAX_COUNT 16

float4 do_dof(in float2 TexCoord,
            sampler2D Texture, 
            sampler2D DepthTexture, 
            float DepthOfFieldCenter, 
            float DepthOfFieldMaxDistance,
            float CoCMaxSize, float4 CenterColor, float CenterDepth, float Offset)
{ 
    float2 TapOffsets[DOF_TAP_MAX_COUNT];
    TapOffsets[0] = float2(0.0f, 0.0f);
    TapOffsets[1] = float2(0.527837f, -0.085868f);
    TapOffsets[2] = float2(-0.040088f, 0.536087f);
    TapOffsets[3] = float2(-0.670445f, -0.179949f);
    TapOffsets[4] = float2(-0.419418,-0.616039);
    TapOffsets[5] = float2( 0.440453,-0.639399);
    TapOffsets[6] = float2(-0.757088, 0.349334);
    TapOffsets[7] = float2( 0.574619, 0.685879);
    TapOffsets[8] = float2(0.0f, 0.0f);
    TapOffsets[9] = float2(0.0f, 0.0f);
    TapOffsets[10] = float2(0.0f, 0.0f);
    TapOffsets[11] = float2(0.0f, 0.0f);
    TapOffsets[12] = float2(0.0f, 0.0f);
    TapOffsets[13] = float2(0.0f, 0.0f);
    TapOffsets[14] = float2(0.0f, 0.0f);
    TapOffsets[15] = float2(0.0f, 0.0f);
    float2 tap[DOF_TAP_COUNT];
    float4 Color[DOF_TAP_COUNT];
    float Depth[DOF_TAP_COUNT];
    // Fetch center samples from depth and focus maps
    float TotalContribution = 1.0f;
    float Contribution;
    float CoCSize = CoCMaxSize; // Scale the Circle of Confusion 
    float DepthDelta = abs(DepthOfFieldCenter - CenterDepth);
    if(DepthDelta > DepthOfFieldMaxDistance)
    {
        DepthDelta = DepthOfFieldMaxDistance;
    }
    CoCSize = CoCMaxSize * (DepthDelta / DepthOfFieldMaxDistance);
    int N = 0;
    for(int i=0; i < DOF_TAP_COUNT; i++) // Run through all of the taps
    {
        // Compute tap locations relative to center tap
        tap[i]	= TexCoord + (CoCSize * TapOffsets[i]);
        Color[i] = tex2D(Texture, tap[i]);
        Depth[i] = -tex2D(DepthTexture, tap[i]).z;
        // Compute tap's contribution to final color
        float Threshold = 1.0f;
        if(abs(CenterDepth - Depth[i]) > Threshold)
        {
            Contribution = 0.0f;
            ++N;
        }
        else
        {
            Contribution = 1.0f;//(Depth[i].x > CenterFocus.x) ? CenterFocus.y : Depth[i].y;
        }
        CenterColor += Contribution * Color[i];
        TotalContribution += Contribution;
    }
    float4 FinalColor = CenterColor / TotalContribution;
    return FinalColor;
}

float4 main(in float2 TexCoord : TEXCOORD0,
            uniform sampler2D Texture : TEXUNIT0, 
            uniform sampler2D DepthTexture : TEXUNIT1, 
            uniform float DepthOfFieldCenter, 
            uniform float DepthOfFieldMaxDistance,
            uniform float CoCMaxSize) : COLOR
{
    /////
    float4 CenterColor = tex2D(Texture, TexCoord);
    float CenterDepth = -tex2D(DepthTexture, TexCoord).z;
    //
    return do_dof(TexCoord, Texture, DepthTexture, DepthOfFieldCenter, DepthOfFieldMaxDistance, CoCMaxSize, CenterColor, CenterDepth, 0);
}

I'm running into a problem though - in the code I'm rejecting samples that come from an area that's significantly in front of or below the center point (using the linear screen-space depth stored in the depth texture) - however, I'm seeing "acne":

http://www.flickr.com/photos/59098813@N06/7998075690/

I don't understand it - shouldn't that acne be rejected by my test and have its contribution set to zero? Here's the visualized depth buffer for reference:

http://www.flickr.com/photos/59098813@N06/7998069833/

All buffers are FP16, running on OS X Mountain Lion on a Retina MacBook Pro (Kepler, 650M).
 
Do you have linear filtering enabled? Or are you working with a downscaled color buffer?
 
Linear filtering enabled for color texture, nearest filtering used with the depth texture - neither buffers are downscaled.
 
Last edited by a moderator:
Hmmm, I seem to have found the problem - I recently added FXAA before the Depth of Field step, moving that to after the DoF (which is where it should be) seems to fix it.
 
And one of the reasons GoW AA was so good was the fact it was done before all other postprocessing. They do talk about that in some GDC or Siggraph presentation, you might wanna take a look at it.
 
That's interesting - how can that avoid errors? If I have a foreground blue object with a red background there will be some pixels around the edges whose depth is either background / foreground but whose color is purple (a mixture of red / blue). Won't that cause some visible errors?
 
Back
Top