Search Unity

Question [SOLVED] Android URP Shader Graph circle distance artifact

Discussion in 'Shader Graph' started by Markus3, Apr 29, 2022.

  1. Markus3

    Markus3

    Joined:
    Aug 5, 2018
    Posts:
    4
    I'm getting a distance artifact when using a URP Shader Graph Lit material on Android in the Unity 2021.2.5f1 Editor. When zooming out from a large plane with the material, a circle appears which shrinks the farther you are from the object. I'm wondering if it's a simple fix or an issue with Android, but normal URP materials and non-Android targets don't have this issue.

    To reproduce:
    1. Use the URP template. Create a new scene. Turn off fog in the Lighting/Environment settings.
    2. Create a new URP Lit Shader Graph. Change the Base Color to anything. Create a material from this shader.
    3. Create a plane. Scale it uniformly 100 units. Assign previous material. Zoom out in the Editor and see the issue.
    The further out you zoom, the smaller the circle of the expected color. If you use a normal URP Lit material, there is no such circle.

    Here's an image of what I see - (alternative link: https://imgur.com/a/oc5f7q0)
    unity-artifact.jpg

    Any suggestions for how to fix this?
     
  2. Markus3

    Markus3

    Joined:
    Aug 5, 2018
    Posts:
    4
    The problem disappears when removing environment reflections entirely (Rendering -> Lighting -> Environment -> Environment Reflections -> Source: Custom).

    Is there a way to control the environment reflections in a shader graph manually?
     
  3. Markus3

    Markus3

    Joined:
    Aug 5, 2018
    Posts:
    4
    The artifact is still visible in Unity 2020.3.33f but not as much, so I moved all the code there.
     
  4. samu_kallio

    samu_kallio

    Joined:
    Jan 18, 2022
    Posts:
    2
    This is probably related to: https://issuetracker.unity3d.com/is...-platform-when-its-260-units-away-from-camera

    The problem is the use of SafeNormalize() at line 25 in com.unity.render-pipelines.universal\Editor\ShaderGraph\Includes\PBRForwardPass.hlsl (and some other files as well, but that one involves the usual forward rendering pass). SafeNormalize computes the squared length of the view vector, which quickly becomes too large to represent using half-floats (e.g. on Android and iOS) as the view distance increases.

    We've solved the issue for now by making our own copy of the com.unity.render-pipelines.universal package (i.e. moving all the files for the package from Library/PackageCache/ to Packages/) and then replacing the use of SafeNormalize() with normalize().
     
  5. Markus3

    Markus3

    Joined:
    Aug 5, 2018
    Posts:
    4
    This solves the issue.

    Out of curiosity, is it because of perf reasons that the SafeNormalize uses the squared length (doesn't a typical normalize also need to square the length before sqrt)? Does the choice of precision in the Shader Graph editor not affect the precision for these calculations? And do the non-Shader Graph URP shaders just use normalize?
     
  6. samu_kallio

    samu_kallio

    Joined:
    Jan 18, 2022
    Posts:
    2
    I would guess so. It uses rsqrt to normalize the vector which is usually (or at least used to be) more efficient than a separate sqrt-and-divide. An ordinary normalize() needs to compute the squared length as well, but as an intrinsic function it can probably sidestep representation issues and use higher precision internally.

    SafeNormalize uses a "real" data type which is an alias for some concrete data type according to platform settings, but from a quick glance I couldn't find any dependency on graph settings.

    Non-Shader Graph shaders each have their own hand-written vertex/fragment pass routines, so it depends on the shader. The URP standard lit shader seems to use normalize().