- Home /
Yet Another Terrain Seams Question
Hello Everybody,
I've been playing around with Unity trying to create terrains at run-time. I've managed to make a terrain load from a socket connection providing heightmap information, and now I'm trying to make 2 terrains stitch together seamlessly.
I don't know if I took the best approach (correct me if I didn't), but I created 2 empty GameObjects in my scene named TerrainContainer1 and TerrainContainer2. In each of those, I added my script which will connect to my server, will request for the correct heightmap and will generate a terrain in run-time with the data the server sent to it. So far, it is doing pretty good. I placed a white pixel in each of both terrains' corners to check if I'm rendering everything and placed numbers in each corner to check if I'm joining the correct sides, and seems it does nicely.
Then, I read around that I should set the SetNeighbors so that each terrain points to each other to overcome LOD problems while doing seamless terrains. As when I play my "game" I don't have any terrain loaded, I created another empty GameObject and added a C# script to it with 2 static variables. In the update loop, I check if both terrains are already loaded, and if so, I set the neighbors only once (i placed a flag variable there so I don't setNeighbors every frame).
I also tried to set neighbors in every possible arrangement only to ensure that I'm setting them correctly, and placed some Debug.Log to see if the setNeighbor call happens AFTER the 2 terrains loading, and yes, it does.
Anyway, even doing all that, I still have a seam. Strangely enough, where my corner white pixels are, the terrain match nicely, but not in the rest of it.
To generate the heightmap, I made a 2050x1025 image in Photoshop, and cut 2 1025x1025 images from it, and saved as PNG non-interleaved, grayscale.
There is the image from when I run the app:
What I'm doing wrong? it is the fact each terrain resides within different GameObjects, so they can't setNeighbor each other? Any ideas? Did I take a nice approach in doing this, or my design is flawed?
Thanks in advance!
If by nice you mean complex, I think your approach is pretty darn good.
Thanks! I'm pretty used to corporative softwares, and I know some things work quite differently in the game world, that's why I asked. $$anonymous$$aybe, for example, putting the terrains all in one GameObject or all of them directly in the main node could be better, don't know. But if it is good as it is, I'm glad, and I shall continue this way then =D
Answer by spinaljack · Sep 08, 2010 at 10:22 PM
Have you tried changing the height maps from "repeat" to "clamp" wrap mode? That might be causing anomalies along the edges. Alternatively you can set a single sold height along all the edges to ensure a match on both sides and then you'll have to hide it somehow like with rocks and bushes or hills made to match the terrain.
Just some ideas as your system sounds pretty good, but just setting neighbours wont make the height the same on each terrain as you've seen.
Sorry, but I do not know which property in run-time I can set this heightmap mode. Which is the property I must set in the terrainData or Terrain class to do so?
Oh, forget it.... Seems it is my inability to understand heightmaps and photoshop properly =D Shame on me. I cannot make a 2050x1025 image and split them in two. Seems that one heightmap must share a pixel line with the other one in order to make them work together seamlessy. I just copied the bottom line of my top heightmap and placed it in the 1st line of my bottom heightmap and all the vertexes joined together magically =D... So, I need to make a 2048x1024 heightmap and always duplicate the bottom/left pixels to the next heightmap. Living and learning.
YES, thank you! This is the correct answer. It can seems like it's maybe not when you look at wrong texture object or at wrong time in your pipeline tho.
Answer by xabblll · Nov 08, 2013 at 01:44 AM
Changing wrap mode didn't helped me. So i wrote a script for fix it manually. It is pretty basic, but maybe it can help somebody. You can run it once, because all terrainData will saved automatically.
public static void Fix(Terrain cur, Terrain right, Terrain bottom)
{
float[,] newHeights = new float[resolution, resolution];
float[,] rightHeights = new float[resolution, resolution], bottomHeights = new float[resolution, resolution];
if (right != null)
{
rightHeights = right.terrainData.GetHeights(0, 0, resolution, resolution);
}
if (bottom != null)
{
bottomHeights = bottom.terrainData.GetHeights(0, 0, resolution, resolution);
}
if (right != null || bottom != null)
{
newHeights = cur.terrainData.GetHeights(0, 0, resolution, resolution);
for (int i = 0; i < resolution; i++)
{
if (right != null)
newHeights[i, resolution - 1] = rightHeights[i, 0];
if (bottom != null)
newHeights[0, i] = bottomHeights[resolution - 1, i];
}
cur.terrainData.SetHeights(0, 0, newHeights);
}
}