Search Unity

Bug Why do I have artifact with a default Lit shader graph on a cube

Discussion in 'Shader Graph' started by ArthyShow, Oct 11, 2021.

  1. ArthyShow

    ArthyShow

    Joined:
    Aug 6, 2016
    Posts:
    23
    Hi,

    I'm working on a Voxel map generator (using URP) and I have a weird render artifact no my procedural generated mesh.

    So I tried with a simple Cube, created shader (Universal Render Pipeline > Lit Shader Graph) and applied on both of my mesh and the cube.
    I just updated the Base Color to white and this is the result:

    upload_2021-10-11_16-18-8.png

    In the beginning I did the Voxel object on the back-left where vertices are shared (between face of a cube and cube next to each other).

    I saw that the default Unity Cube create 4 new vertices for every face (so a total of 24 vertices), so I updated my mesh generator and now I have the same issue on the edge of my Voxel object.

    What the deal ? How to fix this ?

    Thank you all
     
  2. razzraziel

    razzraziel

    Joined:
    Sep 13, 2018
    Posts:
    396
    It is not a bug. It looks like you modified the default unity cube. Restart Unity and it may be back as it used to be.
     
    Last edited: Oct 11, 2021
  3. ArthyShow

    ArthyShow

    Joined:
    Aug 6, 2016
    Posts:
    23
    It's not a bug ? It's not what I asked for ^^

    I did not update the default Unity cube. Restarted Unity, same. Recreated another cube, apply the material with the default URP Lit Shader graph, same.

    And even if I updated the cube, the mesh isn't the issue because other voxel mesh are created using procedural code and have the same issue
     
  4. Mauri

    Mauri

    Joined:
    Dec 9, 2010
    Posts:
    2,664
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    Shadow Maps!

    You don't!

    No, really, you don't. You can sort of work around the problem, usually at the cost of other artifacts, but there is no fix for this. At least not without going to raytraced shadows or stencil based shadows (both of which have their own issues). What you're seeing is shadow acne due to shadow map precision limitations and aliasing.

    Search online and you'll find a ton of resources explaining what shadow acne is, as well as discussing some of the work arounds. Usually some form of "biasing".



    In Unity's case, it uses both light direction bias and normal bias to reduce shadow acne, otherwise these kinds of artifacts would appear on all surfaces all of the time. You can test that by going to your directional light and setting the "Bias" (which is the light direction bias) and "Normal Bias" to 0.0. Now all surfaces will get weird lines or dots on them. You can play with the bias settings and you'll see most of the artifacts go away even with fairly small amounts of bias.

    Both of these work essentially the same way. Light direction bias pushes the shadow casting surface away from the light source so that the visible surface and the matching shadow casting surface aren't at the same depth. This works, but can be heavy handed, and not all surfaces need the same amount of bias depending on the angle the surface is relative to the light direction. It can also create an artifact called "peter panning" where the base of an object does not cast a shadow because it's been pushed back too far. Normal bias works by pushing the surface down along its surface normal rather than along the light direction. This better approximates the amount of bias needed to avoid aliasing at all angles, and reduces how much biasing is needed. But it too has artifacts, and are most of what you see above.

    For the Unity cube and your split vertex voxel mesh, the flat surfaces are being pushed back, and the "dotted line" you see is where the shadow caster surface actually is in the shadow map. The "edge" of the geometry is still right at the surface, so you still get the shadow acne artifacts there.

    A mesh with smooth normals, like your shared vertex mesh, might seem like a fix for this as it's pulling the vertices away from all of the walls, and it is. But you need more bias to avoid shadow acne because the shadow surfaces aren't beed pulled as far from the visible surface as it would be with hard edge normals. For something like a cube mesh, the vertex normals are only going be be "0.57735" on any axis, so they'll only get pulled away from the visible surface by 58% of the normal bias as compared to a cube with unique vertices per axis, which have normals of "1.0" on that axis, so will be pushed away effectively 100% of the normal bias.

    So "solutions":
    Increase the bias
    This really just pushes the "dotted line" back. But for certain lighting angles it can be enough to solve the problem. Just be mindful of the peter panning problem. For voxel geometry isn't a huge issue, but you might notice objects near the back edge of a voxel will appear "in the light" when it obviously shouldn't be.

    Adjust the light direction
    Try your best to avoid light angles that are very close to parallel with a major axis. Lots of games already do this in subtle ways like the light direction never drops below a certain angle on the horizon regardless of what position the sun / moon is in the sky. But it can also be done by trying to avoid staying at the other axes too. If you don't have a dynamic time of day this is quite easy to deal with.

    Use separate shadow and visible normals
    This can be done either by having two meshes, or by encoding two sets of normals into your mesh data. One with the hard edge normals for the visible geometry and one with the smooth normals for shadow casting. You can also calculate flat normals in the fragment shader using pixel derivative functions with a custom shader, meaning you don't need the split vertex mesh at all. Once you do this you can increase the normal bias on the light to the point the acne goes away and you're good to go. Though if you push it too much you might again notice objects behind voxels getting lit when they shouldn't, it's generally less obvious than when increasing the light direction bias.

    Use noisy surface textures
    And this is the one used by most AAA games. Just use a sufficiently noisy surface texture and the artifacts just disappear! The "grungy" look of many games from the early 2000's were born from trying to hide this exact issue. That and early SSAO was noisy as heck too.
     
    Ruchir likes this.
  6. ArthyShow

    ArthyShow

    Joined:
    Aug 6, 2016
    Posts:
    23
    Mauri: Yes ! It fixe my problem thank.

    bgolus: What an amazing answer ! It's very helpful !

    So I tried to rotate light to avoid parallel angle but nothing to do, I always have acne on at least a face. So I tried to update the shadow bias and it's fine for a value of 3 and more.

    About normals I don't know a lots about them. I created the voxel mesh by code (only by placing vertices and triangles, witout any uvs or normals) and used the function `mesh.RecalculateNormals()`. Do I have something to do more than that ?

    After some try to understand normals in my case (and try to update them to have another render and maybe fix some acne issue), I think I have an issue:
    I tried to apply a UV Node (linked to Base Color instead of solid white) and my result is.... black ?
    Do this have a relation with normals?
    upload_2021-10-11_18-3-43.png
     
    Last edited: Oct 11, 2021
  7. ArthyShow

    ArthyShow

    Joined:
    Aug 6, 2016
    Posts:
    23
    After some search I decide to render vertices, and found that I have the same result as Unity Cube, so I this question is close (and my black issue come from something else ^^)

    upload_2021-10-11_18-56-44.png


    BTW (out of scope) but I also found that a cube mesh with triangles that share corners vertices do not have normals pointing at 45deg (because of triangles position on faces)

    upload_2021-10-11_19-3-5.png
     
  8. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,343
    If you aren’t assigning any UVs, then yes, the UVs are going to be black, because they’re going to be zero everywhere. But UVs and normals are unrelated.

    If you end up wanting to use normal maps you’ll need tangents, which depend on both the normal and UV. Or you’ll want to use world space UVs. But that’s another topic for later.

    Nope, that’s good enough. Especially for the hard edge.

    For the shared vertex setup, Unity is calculating the average normal of the faces using that vertex. With that cubes particular triangle layout you’re getting an in even number of triangles per face sharing each vertex. That one pointed sort of towards the camera for example, there are two triangles on the top, two triangles on the right, and one triangle on the left. A slightly different triangle layout could make the automatic normal calculation produce perfect “45” degree normals (note, the corners of a cube don’t actually average to a 45 degree angle, though it’ll look like that if viewed along the axes). But you might just want to hard code them.