Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Gap appearing between quads in a 3D world

Discussion in 'General Graphics' started by HardlyDifficultLLC, Aug 4, 2016.

  1. HardlyDifficultLLC

    HardlyDifficultLLC

    Joined:
    Aug 4, 2016
    Posts:
    10
    We have an occasional single frame rendering issue: a small gap on the x axis sometimes appears.

    Our world is an endless runner, we are traveling positive z only.

    We have created a test world which removes as many variables as possible and still repros the problem.
    - The camera is positioned at 0, 1, 0 and then travels positive z (in whole number increments) until it reaches 10,000 then loops back to 0.
    - The floor tiles are positioned at x, 0, z where x is a whole number -10 -> 10 and z is a whole number 0->11,000.
    - The floor tile material uses the default shader, no Albedo map and set to solid black.
    - The floor tiles are Unity quads (although this issue also impacts custom models).
    - The camera has a 20 degree x rotation.
    - We tried changing the camera clipping values from the Unity default of .3->1000 to 1->10 with no change (gap still occurs).
    - The ground is made up of quads with a 90 degree x rotation and scale of 1.
    - The skybox is set to none and the camera clear is purple to make the gap easier to spot.
    - Everything else should be at the default setting for a new Unity project.
    - Tested on PC with NVidia GTX 760, issue also seem more common on various Android devices.
    - Tested in editor and as a .exe, gaps appear with Fantastic or Fast quality selected.

    Source included.

    What options do we have to address this? It looks minor in the screenshot but when playing a mobile game it is very distracting.

    Screenshot showing the camera position when gap occurred (0, 1, 9923):
    cameraPosition.png

    Screenshot showing one of the floor tile positions for a tile which is touching the gap (0, 0, 9925):
    floorTilePositionWhereGapIs.png

    A couple more examples of the issue from a PC .exe build: http://imgur.com/a/SG5SD
     

    Attached Files:

    • Gap.zip
      File size:
      31.8 KB
      Views:
      484
    Last edited: Aug 4, 2016
  2. Daniel-Schemann

    Daniel-Schemann

    Joined:
    Oct 22, 2013
    Posts:
    5
    Hey,

    we had such a problem before, we fixed it by putting all world objects into a parent.

    Cheers.
     

    Attached Files:

  3. HardlyDifficultLLC

    HardlyDifficultLLC

    Joined:
    Aug 4, 2016
    Posts:
    10
    Thanks Daniel for the tip, however I downloaded your updated world and the problem remains. Note that the problem does not occur very frequently, you may need to let it run for several minutes.
     
  4. Daniel-Schemann

    Daniel-Schemann

    Joined:
    Oct 22, 2013
    Posts:
    5
    Ok, i see you are right, it took some time to occur. I have tested a bit more and came with a movement code change:

    Code (CSharp):
    1.       var pos = transform.position;
    2.       pos.z += 10f;
    3.       transform.position = pos;
    Let me know if this changed something.
     
  5. HardlyDifficultLLC

    HardlyDifficultLLC

    Joined:
    Aug 4, 2016
    Posts:
    10
    Thanks again, however I tested with your updated code and the problem remains.
     
    Last edited: Aug 4, 2016
  6. Daniel-Schemann

    Daniel-Schemann

    Joined:
    Oct 22, 2013
    Posts:
    5
    Ah, bad. Then it looks like i can't reproduce it anymore. Hope someone could find a solution that will fix it for you.
    Good luck.
     
    HardlyDifficultLLC likes this.
  7. steego

    steego

    Joined:
    Jul 15, 2010
    Posts:
    969
    9000 units from the origin is probably far enough that you start having floating point precision errors. I haven't tested your example, so I can't say for sure that's what is happening, but it sounds likely. To test, try reducing the distance the camera can travel to 4000 or 2000 units.

    A better way to solve this, if possible in your game, is to keep the camera stationary and just move the level instead.
     
  8. HardlyDifficultLLC

    HardlyDifficultLLC

    Joined:
    Aug 4, 2016
    Posts:
    10
    Thanks steego, but I'm still unable to resolve the issue. In order for movement in our game to be smooth, we need about 5 digits of precision... so we tested you're approach using 4-5 digits at various scales but the issue remains. We also tried moving the world instead of the camera with no change.

    Specifically, we tested:
    - 0->1000 with one decimal (@107.1)
    - 0->100 with two decimals (@86.38)
    - 0->1 with four (actually looking okay but may not be enough precision to look smooth in the game)
    - 0->1 with five (issue returns @.4846)
    - World moves with whole numbers only 0->10000 (@Tile offset 9281)
    - World moves 0->1 with four decimals (@Tile offset .4902)
    We also tried adjusting the camera clip settings (and the y position) to match the change in magnitude.

    Let me know if anyone has other suggestions to try. Thanks for the help!
     
  9. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    You can try not moving the camera and moving the "world" instead to keep the camera near 0,0,0. Rotation on the camera is fine, it's just the distance from the center of the world you want to avoid. Alternatively you can move the camera but ever ~100 units or so snap the camera and the world back 100 units.
     
  10. HardlyDifficultLLC

    HardlyDifficultLLC

    Joined:
    Aug 4, 2016
    Posts:
    10
    We tried that as well. Sorry for not being clear in my previous post, but a few of those test cases was exactly that - the world moved around the camera and camera was frozen at 0, 1, 0. Thanks for the tip tho
     
  11. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Have you tried combining the quads into a single mesh?
     
  12. HardlyDifficultLLC

    HardlyDifficultLLC

    Joined:
    Aug 4, 2016
    Posts:
    10
    Sort of... so I have not tested that in this test world environment. However in our game we have screenshot-ed the gap happening at the center of a single mesh created in blender where there was welded vertices... I may try adding that to this test world in the future, but that take a little time to setup. Tx
     
  13. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Welded vertices, but presumably a break in materials, UVs or normals? Or is it a mesh with a lot of polygons (>65k)?
     
  14. HardlyDifficultLLC

    HardlyDifficultLLC

    Joined:
    Aug 4, 2016
    Posts:
    10
    The materials/UV repeats per 'segment' (by which I mean where the vertices are). No normals used in this world. Here's the model itself if you would like to take a look.
     

    Attached Files:

  15. Ari_Interactive

    Ari_Interactive

    Joined:
    Aug 5, 2016
    Posts:
    1
    I can confirm that I had the exact same issue months ago and that your project also replicates this behaviour. Good luck on solving the problem, I'll be lulkin on this thread.
     
  16. Althaj

    Althaj

    Joined:
    Sep 21, 2013
    Posts:
    3
    Few more suggestions from top of my head:
    Try changing the rendering between forward, vertex lit, deferred.
    Try changing the colour space to linear.
    Try changing the renderer between various versions of DirectX and OpenGL.
    Try turning off various batchings and skinnings.
    Try changing fixed time step.
     
  17. HardlyDifficultLLC

    HardlyDifficultLLC

    Joined:
    Aug 4, 2016
    Posts:
    10
    So we didn't find a complete fix, but have mitigated the issue with the following:
    - Reduced the scale of the world by 10x (so a character stands at about 1m)
    - Added a lip to every quad where it connects to another mesh. That lip has UV so that the texture matches.
    - Added a small rotation on the camera to the Y axis (doesn't really make a visual difference but when gaps occur they don't extend the entire width of the screen).

    Let me know if there are any other suggestions, the issue still remains just not as frequent and not as sever.
     
    Last edited: Aug 14, 2016
  18. Hufo_

    Hufo_

    Joined:
    Aug 14, 2016
    Posts:
    2
    Hello Hardly,

    In OpenGL (and I guess DirectX), you are guaranteed to have no gaps between two triangles if and only if the vertices of the shared edge provide exactly the same transformed coordinates to the rasterization stage. When quads (or more complex meshes) are put side by side by adding offsets in their world transform matrix, then with the default shaders those matrices get mixed with the view and projection matrices in such a way that vertices from adjacent quads will no longer end up providing exactly the same results.

    When the object to world transforms are simple integers translations (as in your example scene), and the mesh borders are also on integer boundaries, then applying this transform first will provide exact matches (up to the number of bits in the vertex shader float computations, to be 100% sure this computation could be done using integers instead). Then the view and project transforms can be applied (as they are the same for all chunks), and there will be no gaps any more!

    Attached is a version of the test project that adds a shader with this implemented (and the default single-matrix transform within an #if 0 to switch between the two).

    In this test with a camera rotation of 22 in X and 2 in Y show many gaps with the fix disabled in the shader, but none with it :)
    I also added in the shader an option to show object position as colors to better see the quads. Note that the batching feature in Unity affects with this, so it is disabled in the shader.

    I hope this helps,

    Hufo.
     

    Attached Files:

    Wraithy likes this.
  19. HardlyDifficultLLC

    HardlyDifficultLLC

    Joined:
    Aug 4, 2016
    Posts:
    10
    Thanks Hufo, this appears to be a significant improvement. The issue is not completely gone from our tests so far, but it does appear to happen much less often. We will be combining this approach with the mitigations mentioned above.
     
  20. Hufo_

    Hufo_

    Joined:
    Aug 14, 2016
    Posts:
    2
    I can't be satisfied with only an incomplete fix!
    So I investigated further, and I found that Unity's 90° rotation matrix is not exact, the diagonal values for Y and Z should be 0 but are -1.192e-07 o_O (as shown in the cb0_12 to cb0_15 values as captured by RenderDoc below)
    gapshader1.png

    I tried providing the exact quaternion to Unity hoping that it would fix it, but it was the same.
    The safest option would be to never apply any rotation to meshes that you want to tile perfectly.
    But as an alternative, here is a new version with 2 ways to fix in within the shader itself.

    There are 4 flags at the top of the shader to choose between:
    • V1_DEFAULT: the default unity transform function (with lots of gaps)
    • V2_SPLITMATRIX: the first fix of splitting up the two transform matrices (same as previous post, less gaps but still a few)
    • V3_FIXEDROTATION: the shader hardcodes the 90° rotation around X using an exact computation (and faster that a matrix transform)
    • V4_CLAMPWORLD: the world space position is clamped to only keep 10 bits after the decimal point (which should be enough to preserve the shape of the model while getting rid of the imprecision from Unity's matrix, but can be slower to compute and not 100% guaranteed to work for all models and rotations)
    With V3 or V4 enabled, I was unable to reproduce any further gaps (but maybe you will ;))

    If you need, I can provide more explanations and guidelines on how to avoid gap problems, and we can discuss during one of your (week-end) streams.

    Let's hope for a gap-free future ! :D
     

    Attached Files:

  21. HardlyDifficultLLC

    HardlyDifficultLLC

    Joined:
    Aug 4, 2016
    Posts:
    10
    Hufo's V4 solution (rounding in the shader) works! Thanks so much