Edge Detection Anomaly

46 views Asked by At

I found something odd. When I branch texture samples, the mip breaks in some 2x2 pixels. This normally means the partial derivatives DDX/DDY found a discontinuity somewhere. But when I use partial derivatives to find the problematic 2x2 pixels, I do not find all of them.

shader screenshot (or see Shadertoy example https://www.shadertoy.com/view/McSXzh ) This GLSL shader aims to show the problem regions in the following colors:

  • Red/Green = Edge Pixel found by branch
  • Cyan/Pink = Edge pixel found by fwidth and branch
  • Blue = Edge pixel found by fwidth
  • Black = No Edge
    // Arbitrary condition for branching, here a circle
    bool branch = length(uv) > 0.4;
    
    vec3 color;
    if (branch) {
        // Outside circle
        
        // Calculate absolute difference to neighbors
        vec2 uvf = fwidth(uv) * 512.;   

        // Make edge mask
        color.x =  1. - clamp(uvf.x + uvf.y, 0., 1.);
        
        // Forces branching?
        texture(iChannel0, vec2(0.));
        
    } else {
        // Inside circle

        // Return green on border
        vec2 uvf = fwidth(-uv * 2.) * 512.;   

        // Make edge mask
        color.y =  1. - clamp(uvf.x + uvf.y, 0., 1.);
    }    
    
    // Use fwidth to select the border and mark it in blue
    color.z = clamp(fwidth(float(branch)), 0., 1.);

In theory, all pixels on the border should be found by both the fwidth and branching fwidth. However, it appears that if the upper right pixel is different, fwidth doesn't find it. Interestingly, an unused texture sample in the branch seems to be required for it to find the border, but I am not quite sure why.

The same also happens in Unreal Engine using HLSL, but with the lower right pixel.

While texturegrad easily fixes this, it's also ~2x slower than a texture sample. So, I tried quantizing the branching with fwidth and found this exception. See functon ifTex2x2Width: https://www.shadertoy.com/view/ctGBDR

0

There are 0 answers