Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question SDF derivatives have artifacts

Discussion in 'General Graphics' started by customphase, Oct 26, 2022.

  1. customphase

    customphase

    Joined:
    Aug 19, 2012
    Posts:
    243
    Im rendering out some meshes and generating an SDF out of their sillhouettes using JFA. The resulting SDF seems to be correct. Heres an sdf of a sphere for example (red is positive distance, green is negative/inner distance):

    upload_2022-10-27_2-41-42.png

    And heres the same SDF but using frac so its a bit easier to see:

    upload_2022-10-27_2-42-34.png

    However when im trying to calculate the derivatives im getting these streaking artifacts:

    upload_2022-10-27_2-43-23.png

    And heres the code for calculating derivatives:

    Code (CSharp):
    1. float sdf = SAMPLE_TEXTURE2D(_SDFTex, my_point_clamp_sampler, i.uv).r;
    2.  
    3. float sdfRight = SAMPLE_TEXTURE2D(_SDFTex, my_point_clamp_sampler, i.uv + _SDFTex_TexelSize.xy * float2(1,0)).r;
    4. float sdfLeft = SAMPLE_TEXTURE2D(_SDFTex, my_point_clamp_sampler, i.uv - _SDFTex_TexelSize.xy * float2(1,0)).r;
    5. float sdfTop = SAMPLE_TEXTURE2D(_SDFTex, my_point_clamp_sampler, i.uv + _SDFTex_TexelSize.xy * float2(0,1)).r;
    6. float sdfBottom = SAMPLE_TEXTURE2D(_SDFTex, my_point_clamp_sampler, i.uv - _SDFTex_TexelSize.xy * float2(0,1)).r;
    7.  
    8. float sdfDX = sdfRight - sdfLeft;
    9. float sdfDY = sdfTop - sdfBottom;
    10. float2 grad = normalize(float2(sdfDX, sdfDY));
    11. return float4(grad, 0, 1);
    Am i missing something? Is this an expected behaviour? Am i generating the SDF wrong? The result doesnt really look wrong to me. SDFs are in RFloat format, so it shouldnt be a precision issue.
     
  2. c0d3_m0nk3y

    c0d3_m0nk3y

    Joined:
    Oct 21, 2021
    Posts:
    554
    So you are only wondering about the dark streaks in the last picture - not the general look, right?

    Does the size of _SDFTex match the render target size? If not, it might be because you are using a point sampler. Have you tried using a bilinear sampler instead?
     
    Last edited: Oct 27, 2022
  3. customphase

    customphase

    Joined:
    Aug 19, 2012
    Posts:
    243
    Hey, thanks for the reply.

    Correct.

    Im outputting it on a quad in the world, so no, i guess? But it shouldnt matter anyway.

    Yes, i used bilinear initially, it had the same artifacts, so i switched to point to make sure its not the filtering causing this.
     
    Last edited: Oct 27, 2022
  4. customphase

    customphase

    Joined:
    Aug 19, 2012
    Posts:
    243
    Ok, this seems to be a general problem not related to my implementation. Tried generating an SDF and calculating its normal in Substance Designer and got the same (or at least similar) artifacts:

    upload_2022-10-27_14-19-2.png

    I assume you need to blur/prefilter an SDF somehow to avoid these problems.

    Also another related topic, unfortunately without an answer: https://polycount.com/discussion/200541/substance-designer-normal-map-artifacting
     
    Last edited: Oct 27, 2022
  5. Neto_Kokku

    Neto_Kokku

    Joined:
    Feb 15, 2018
    Posts:
    1,751
    My guess is the derivatives are revealing the aliasing in your SDF. Does it look better if you downsample the SDF by 50% first? If so, you might want to implement some sort of multi sampling or super sampling in your SDF generation algorithm.
     
  6. customphase

    customphase

    Joined:
    Aug 19, 2012
    Posts:
    243
    Blurring the SDF does make it look slightly better, the larger the radius the less noticeable it is, but never fully resolves the problem.
     
  7. c0d3_m0nk3y

    c0d3_m0nk3y

    Joined:
    Oct 21, 2021
    Posts:
    554
    Maybe it has something to do with floating point precision. Have you tried calculating the distance on the fly instead of reading it from a texture?
     
    halley likes this.
  8. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    1,873
    Looks like it's due to the clamping of sample at r=R (where r is the pixel's radius and R is the desired green/red transition radius of the SDF). The typical approach to measure the derivative, you sample r1=r+e and r2=r-e (with e being a small value), but if you clamp the two samples at r>=R (outer radius) or r<=R, you are going to get a discontinuity.
     
  9. c0d3_m0nk3y

    c0d3_m0nk3y

    Joined:
    Oct 21, 2021
    Posts:
    554
    I don't know if it helps but I've tried it in shadertoy without a texture and I'm seeing the same streaks, just less severe:
    https://www.shadertoy.com/view/msXGWf

    upload_2022-10-27_8-53-26.png

    but you even get that if you just render a color gradient
    upload_2022-10-27_8-54-1.png
     
  10. customphase

    customphase

    Joined:
    Aug 19, 2012
    Posts:
    243
    You mean using analytical SDF, instead of the one from the texture? If so then yes, it works correctly like that, but it says nothing about the core of the issue, other than the fact that SDF from the texture has discontinuities.

    Hm, not sure i understand what you mean. Can you please elaborate more? Im not clamping any samples.
     
  11. c0d3_m0nk3y

    c0d3_m0nk3y

    Joined:
    Oct 21, 2021
    Posts:
    554
    No, I mean still using finite differences but just cutting out the texture part. Look at my shadertoy code. It does the same as you did just without storing it in a texture.

    There are way fewer streaks that way and the remaining ones seem to be present in any color gradient.

    Does the RFloat type map to a 16 bit float maybe instead of 32 bit? (Update: Hm, no it doesn't)
     
  12. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    1,873
    I guess I was taking the name
    my_point_clamp_sampler
    too seriously, then.
     
  13. customphase

    customphase

    Joined:
    Aug 19, 2012
    Posts:
    243
    Its just to prevent the SDF texture from tiling at the edges. Not anything related to the issue unfortunately, using linear_repeat sampler has the same problems.

    Thats what i meant when i said analytical SDF, you calculate it from a function. Didnt say anythign about the derivatives.

    Anyway, im about 99% sure that its just that JFA inherently produces distance fields with slight errors. Those errors are normally unnoticeable, but become apparent when you do derivatives.

    Quote from this paper (https://www.comp.nus.edu.sg/~tants/jfa/i3d06-submitted.pdf):
     
    Last edited: Oct 27, 2022