Search Unity

Terrain Seam

Discussion in 'World Building' started by Zullar, Jan 11, 2021.

  1. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    Using the built in Unity Terrain component I notice a seam at the edge between two Terrains. The terrains are part of the same group and use the same TerrainLayer.

    To be clear the picture below only uses 1 texture/TerrainLayer (it is a combined dirt & grass texture)

    upload_2021-1-10_20-38-45.png
    Is there an easy way to fix this (as opposed to instancing TerrainLayers and shifting offsets or something similar)? Thanks in advance.

    2019.4.4f1
     
    Last edited: Jan 11, 2021
  2. wyattt_

    wyattt_

    Unity Technologies

    Joined:
    May 9, 2018
    Posts:
    424
    Hello! I think your best option is to open the texture in an image editor and try to make the texture "tile" better/seamlessly
     
  3. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    Thanks for the response. I'll try and explain the issue better.

    Here are three 10x10 planes with the texture tiled at 0.7x0.7. You can see the seam between the 3 objects and the seam because the textures do not match (The edges do not match because texture tiling is 0.7 and the UV map is 1.0 wide)
    ThreeTexturesWithSeamUnselected.png

    However if I make it one 30x10 object instead of three 10x10 objects there is no seam. This shows the texture itself is seamless. (Tiling set to 2.1x0.7) 30x10.png

    If I take my 3 10x10 planes objects and instance the materials and offset the textures I can remove the seam. The amount of texture offset required is based on world position, size, texture tiling. Code used to do this is shown below. It's worth mentioning that the mesh UV map could also be shifted to fix this issue (I think shifting the UV map is probably a better method than instancing and changing material.offset). Three 10x10 with Texture Offset to Remove Seam.png

    If I use one 30x10 Terrain object I do not have a seam. It looks good. TerrainLayer Size is set to 15x15 (which is basically the same as inverting the previous material tiling value of 0.7x0.7 for a 10x10 size plane)
    Terrain 30x10.png

    However if I use three 10x10 Terrains I get a seam. The Terrains are part of the same Terrain Group and also share the same TerrainLayer. Terrain Three 10x10.png

    Hope that clarifies the issue. Thanks for reading.

    I think there are a few ways to fix the seam issue.
    1: Instance the Material/TerrainLayers and adjust the offset (the code below does this for a mesh and plane)
    2: Shift the UV map (this is probably more efficient and the better way to do it?)
    3: Choose a Terrain size that is a multiple of the TerrainLayer.size. For example if the TerrainLayer.size is 15x15 then the Terrain size could be 15x15, 90x90, 105x105, or 150x150 but NOT 100x100. (this is a bandaid and doesn't work well considering every TerrainLayer would have it's own size and a least common multiple would be needed).

    I can bug report or upload a sample project to replicate the Terrain seam issue if you want.

    CODE DESCRIPTION
    For a texture tiling of 0.7x0.7 this code instance the material and change the material.tiling to...
    tiling=0.7x0.7 for a 1x1 size plane
    tiling=1.4x.1x4 for a 2x2 size plane
    tiling=2.1x0.7 for a 3x1 size plane
    ...and it also adjusts the material.offset such that for a 1x1 size plane the
    offset=0, 0 for a position of 0,0
    offset=0.7, 0 for a position of 1,0
    offset=1.4, 0 for a position of 2,0
    Code (csharp):
    1.  
    2. protected sealed override void ScaleMaterialsRuntime()
    3.     {
    4.         MeshRenderer meshRenderer = transform.GetChild(0).GetComponent<MeshRenderer>();
    5.         Vector2 tiling_Main_1x1 = tilingFudgeFactor * meshRenderer.material.GetTextureScale(KeyPropertyMaterialTexture.KeyTextureAlbedo.propertyID);
    6.         Vector2 tiling_Secondary_1x1 = tilingFudgeFactor * meshRenderer.material.GetTextureScale(KeyPropertyMaterialTexture.KeyTextureDetailAlbedo.propertyID); //new 2020_12_03 //even if the material doesn't have a detail/secondary map Albedo (i.e. only a normal map) this will still access the scale
    7.  
    8.         Vector2 localScale2D = new Vector2(transform.localScale.x, transform.localScale.z); //only X and Z, floors have no height
    9.         Vector2 tiling_Main_New = new Vector2(tiling_Main_1x1.x * localScale2D.x, tiling_Main_1x1.y * localScale2D.y);
    10.         Vector2 tiling_Secondary_New = new Vector2(tiling_Secondary_1x1.x * localScale2D.x, tiling_Secondary_1x1.y * localScale2D.y); //new 2020_12_03
    11.         meshRenderer.material.SetTextureScale(KeyPropertyMaterialTexture.KeyTextureAlbedo.propertyID, tiling_Main_New);
    12.         meshRenderer.material.SetTextureScale(KeyPropertyMaterialTexture.KeyTextureDetailAlbedo.propertyID, tiling_Secondary_New); //new 2020_12_03
    13.  
    14.         Vector2 posCenter = new Vector2(transform.position.x, transform.position.z);
    15.         Vector2 posLL = posCenter - localScale2D / 2f; //since UV map starts at LowerLeft
    16.         Vector2 offset_Main_New = new Vector2(posLL.x * tiling_Main_1x1.x, posLL.y * tiling_Main_1x1.y);
    17.         Vector2 offset_Secondary_New = new Vector2(posLL.x * tiling_Secondary_New.x, posLL.y * tiling_Secondary_New.y); //new 2020_12_03
    18.  
    19.         meshRenderer.material.SetTextureOffset(KeyPropertyMaterialTexture.KeyTextureAlbedo.propertyID, offset_Main_New); //new 2020_12_03
    20.         meshRenderer.material.SetTextureOffset(KeyPropertyMaterialTexture.KeyTextureDetailAlbedo.propertyID, offset_Secondary_New); //new 2020_12_03
    21.         meshRenderer.material.SetTextureOffset("_BumpMap", offset_Main_New);
    22. }
    23.  
    24.  
    //Note this code won't work exactly if you copy and paste it (it uses some other scripts of mine) but it should show the idea behind adjust texture tiling and offset based on world position and size to eliminate seams.
     
    Last edited: Jan 14, 2021
  4. wyattt_

    wyattt_

    Unity Technologies

    Joined:
    May 9, 2018
    Posts:
    424
    Ahhh ok. I understand now. Sorry. Ya the issue is as I believe you mentioned: The tiling and sampling of the Terrain Layers appears to be in local space relative to the Terrain. Solution might be to incorporate world position of the Terrain/allowing for a origin override to the sampling in some way. You mentioned a few potentially more robust solutions though.

    As you've done already, work around is to create duplicate sets of Terrain Layers per Terrain. That's not great though and would get difficult to manage and paint across seams or choose scales that are multiples/factors of the terrain scale. And every modification to scale or offset would require the additional changes to your X number of Terrain Layers

    I'll share this with the team and see what they have to say.
     
    Zullar likes this.
  5. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    OK thanks for checking with team.
     
  6. wyattt_

    wyattt_

    Unity Technologies

    Joined:
    May 9, 2018
    Posts:
    424
    Turns out we have this on our backlog already. No ETA but we are aware of the need
     
    Zullar likes this.
  7. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,191
    Bump.

    I'm not sure if this is related to the issue I have seen for years, but I believe it might be.

    The issue: When slicing/dividing a single terrain into smaller sub terrain, neighboring terrain tiles have a visible seem, even though theoretically the alphamap along the edges should be exactly equal to the alphamap of the original terrain in the same area. Could this be caused by the same issue?

    In any case, has this been fixed in any version of Unity, so that I can test my issue and see if it is resolved?

    Edit: It looks like I already came up against this issue in the past and resolved it using the separate layer/offset technique. So it is not related to the seem issue I am seeing, since I have 100% confirmed that the textures should line up correctly. In my case, the only way I can fix the seems is by setting the alphmap along the borders of neighboring terrain to be equal.

    I still wonder if the sampling has been changed to somehow incorporate world position, so that the per terrain layers were not needed (as it is a very big waste).
     
    Last edited: Aug 20, 2021
  8. jasoncatalyst

    jasoncatalyst

    Joined:
    Aug 15, 2018
    Posts:
    7
    Are we still waiting for a solution to this?