Tiled Terrain edges seem to be bleeding shadows

I have a tiled terrain that is generated on runtime. The diffuse texture of each terrain tile is a real-world top-down camera image, so I want the visuals to have as little automated tampering as possible.

However, on the very edge of each terrain tile, there is one very small strip of more shadowy area, as can be seen below. It seems to be shadow bleeding, from what little information I could find. But might be something else?
What causes this and how do I fix this?

Do note the image below is already about as zoomed in as I could get it.
Thanks!

I dont know if the same, but i saw a similar problem (with solution) on a sebastian lague’s tutorial: min 8:50

2 Likes

@pdhr I’m having the same issue, and it only happened recently where my terrains where moving in a way they weren’t before (vertically and horizontally as opposed to just horizontally). I’ve futzed with shadow settings with no effect :confused:

@bazztard24 Thanks for linking that! I didn’t think of it being in the (way I imported the) texture being used. I just thought it had to be because of the terrain / lighting.

Applying the settings in the video fixes the band of shading. It was probably just the wrapping of the texture.

Yes, this looks like a texture wrapping issue, with the texture set to black-border or wrap, instead of clamp.
Is this using a custom shader? By default in a custom shader, the texture coordinates will stretch edge-to-edge, pulling in half a pixel of border region like this. We fixed this in the default Terrain shaders by adjusting the texture coordinates so they stretch pixel-center to pixel-center, so it never samples from border regions.

If you want to do the same adjustment to a custom shader, you can modify the texture coordinates used to sample your texture:

float2 stretchedUV = (originalUV * (_MyTexture_TexelSize.zw - 1.0f) + 0.5f) * _MyTexture_TexelSize.xy;
float4 color = tex2D(_MyTexture, stretchedUV);

This stretches the texture by half a pixel along each edge.

Thansk for your reply @ChrisTchou ! Setting it to clamp fixed that seam. I was using the default terrain, so default shader.

However, I now have a different issue, and I hope you can help with that.
I set the terrain texture from a script. This worked fine (as you can see in the image above) while I was on Unity 2018.3 I believe.
However, somewhere since updating to 2019.1 or 2019.2, it no longer sets the texture, instead I get the grey checkerboard. However, the texture is loaded into the terrain layer, and I can then ‘paint’ it with the brush, but it should be set automatically like before.

Do you have any idea what changed or how to fix this? I am currently on 2019.2.1f1.

See the code below where I set it:

        {
            for (int j = 0; j < 2; ++j) //config.NumElevationTileRows
            {
                for (int i = 0; i < 2; ++i) //config.NumElevationTileColumns
                {
                    id = i + j * (config.NumElevationTileColumns);
                    TerrainData data = new TerrainData();
                    tiles[id] = Terrain.CreateTerrainGameObject(data);

                    tiles[id].name = String.Format("Terrain_{0}x{1}", i, j);
                    tiles[id].tag = "Terrain";
                    tiles[id].layer = TerrainUtils.LayerTerrain;
                    tiles[id].transform.position = center_offset + new Vector3((float)config.GetStartPositionX(id), 0, (float)config.GetStartPositionZ(id));
                    tiles[id].transform.SetParent(terrainRoot.transform);
                    tiles[id].isStatic = true;

                    tiles[id].GetComponent<Terrain>().drawInstanced = true;
                    SetElevationFromTileFile(config, tiles[id], (config.NumElevationTileRows - j - 1) * config.NumElevationTileColumns + i);
                    tiles[id].GetComponent<Terrain>().heightmapPixelError = heightmapPixelError;
                    SetTerrainImagery(config, data, id);
                    tiles[id].GetComponent<Terrain>().Flush();
                }
                Debug.LogFormat("Processed tile row {0}", j);
            }
        }

        private static void SetTerrainImagery(TileConfiguration config, TerrainData terrainData, int id)
        {
            // Initialise terrainLayer
            float tilesize = (float)config.ElevationTileDimension;
            TerrainLayer[] terrainLayers = new TerrainLayer[1];
            terrainLayers[0] = new TerrainLayer();
            terrainLayers[0].tileOffset = new Vector2();
            terrainLayers[0].tileSize = new Vector2(tilesize, tilesize);

            // Set Ortho
            Texture2D ortho = (Texture2D)(AssetDatabase.LoadAssetAtPath(String.Format("{0}\\{1}.png", TerrainUtils.ImageryPath, id), typeof(Texture2D)));
            ortho.filterMode = FilterMode.Bilinear;
            ortho.wrapMode = TextureWrapMode.Clamp;
           
            terrainLayers[0].diffuseTexture = ortho;

            // Assign terrainLayer to Terrain
            terrainData.terrainLayers = terrainLayers;
        }

See this image for what I mean:

Since I’m unsure whether this will be picked up properly, I made a separate thread here for my last question.

Setting the Draw Instanced to TRUE fixed it for me.
9800634--1406796--upload_2024-4-28_0-24-7.png
I’m not really sure what are the downsides of enabling this setting… Apparently it also improves performance.
Info here: 2018.3 terrain update: Getting started