- Home /
Aligning simplex noise-generated terrain
I have tried to generate terrain (the standard Unity terrain) through scripts, using simplex noise. However, when I generate more than one segment of terrain, they don't quite align at the edges (see picture).
I believe it is a problem with the part of the code that generates the hight map, but I can't really figure out what is wrong. This is that part of the code (the terrain segments are loaded into an array named terrains): foreach(Terrain terrain in terrains){ tData = terrain.terrainData;
xRes = tData.heightmapWidth;
yRes = tData.heightmapHeight;
heights = tData.GetHeights(0, 0, xRes, yRes);
for (int y = 0; y < yRes; y++) {
for (int x = 0; x < xRes; x++) {
float xpos = x+terrain.transform.position.x; //Is this wrong?
float ypos = y; //Terrain plane will always be at y 0, so no need to add position here
float height = SimplexNoise.Noise.Generate((xpos*strength), (ypos*strength))*res;
heights[x,y] = height;
}
}
tData.SetHeights(0, 0, heights);
Hi, the simplex noise is on a "XY" plane that correspond to a "XZ" plane for a terrain. I think you should add the terrain.transform.position.z to ypos.
Well, you also want to work in heightmap coordinates, not in world coordinates (terrain size can be 1245.2f while heightmap is 513 or 1025)
Also, terrains heights usually overlap 1 pixel so vertices can connect. That is, the heigthmap size is always (power of 2) + 1: i.e. a 512+1 or 256+1. That is because the generated vertices are taken from the center of the heightmaps's texels. So you also want to have last row/col of a terrain = 1st row/col of the next one etc...
And don't forget to call SetNeighbors so the normals and LOD matches :)
EDIT: well, that's difficult to explain but try to draw on paper 2 3x3 terrains (world coord = 2 2.0x2.0 terrains) and connect the centers of the heightmaps's texel as if they were vertices + draw the corresponding triangles. It should become clear :-)
I've been staring myself blind at this for the past hour now, and I just can't wrap my head around it.
I replaced the xpos and ypos with these:
float xpos = x+xRes;
float ypos = y+yRes;
if(currTerrain != 0){
xpos = x+(xRes*currTerrain);
ypos = y+(yRes*currTerrain);
}
and added an incrementing integer (currTerrain). The idea was to run over each heightmap point in turn and then shift by one (so xRes and yRes X currTerrain), but that doesn't seem to cut it.
I can't seem to find any code examples at all from anyone else that has done this either, so I'm pretty much stuck right now.
Have you checked this link ?: http://answers.unity3d.com/questions/767512/procedural-terrain-1.html
Edit: it's not so complicated, I think you are close, but it needs the exact solution so the terrains match and it takes time to get it right. Try to simplify the problem with only 2 terrains, 1 border, small values etc... That's how I solved this problem some times ago (but the code is now more complex, can't post it here). Don't hesitate to use pen and paper to figure out the differences between world coordinate and heightmap coordinates and how unity creates the polygons from the heightmaps.
The best I could get out of that was
float xpos = (xRes*(terrain.transform.position.x-1)+x)*strength;
float ypos = (xRes*(terrain.transform.position.z-1)+y)*strength;
But that seems as wrong as any other I've done so far.
I don't know, maybe I just don't understand it, but I thought it was as simple as getting each X and Y position of the heightmap and change the height value at that point. When moving between "chunks" or "tiles", I assumed you simply added the width of the heightmap (times number of "tiles") to the x and y positions.
yes, assu$$anonymous$$g everything is at position 0 and no rotations or scale. You can make the 2 coordinate system equivalent/aligned: terrain width = height = heightmap-1 (i.e. 512x512 and heightmap = 513). Then you can use xpos = (terrain.transform.position.x + x) with x = 0 to 512 (512 included, as the heightmap has 513 values and so next terrain'0 will be this one's 512).
Have you tried perlin noise to debug ? Or a cosinus (applying a small scale factor to xpos so it becomes more easily visible curves)
Answer by vbs · Sep 28, 2015 at 06:18 AM
I figured out one solution, although it creates a weirdly symmetrical alignment... it can be tweaked by making the noise sampling more complex and/or layering noise values.
Here is some sample code:
Basically i'm using a square terrain "chunk", position
is provided as the chunks Vector3 location. heightmapResolution
is equal to terrainData.heightmapHeight & terrainData.heightmapWidth. The code can be simplified / cleaned up a bit, it has some legacy things from previous implementations.
// yRes = terrainData.heightmapHeight;
// xRes = terrainData.heightmapWidth;
// yRes = heightmapResolution;
// xRes = heightmapResolution;
// print("yRes " + yRes);
// print("xRes " + xRes);
float terrainSize = chunkLength;
print("terrainSize " + terrainSize);
float offset = 1F;
float startXNoise = (position.x / chunkLength) * (heightmapResolution -1F);
float startZNoise = (position.z / chunkLength) * (heightmapResolution -1F);
print("startXNoise, startZNoise " + startXNoise + " " + startZNoise);
float xS = 0;
for (int x = 0; x < heightmapResolution; x++) {
float zS = 0;
for (int z = 0; z < heightmapResolution; z++) {
float xCoord = (startXNoise + xS) / (heightmapResolution) * 10;
float yCoord = (startZNoise + zS) / (heightmapResolution) * 10;
// float xCoord = (startXNoise + xS) / (heightmapResolution - 1F) * 10;
// float yCoord = (startZNoise + zS) / (heightmapResolution - 1F) * 10;
// SIMPLE NOISE
float combinedNoiseValues = Mathf.PerlinNoise(xCoord, yCoord);
// set height value
heights[z,x] = combinedNoiseValues;
zS += offset;
}
xS += offset;
}
terrainData.SetHeights(0, 0, heights);
Answer by xyz567 · Sep 20, 2015 at 10:21 PM
I had an issue much like this recently (excepted I was using procedural meshes rather than terrains.) How I fixed it was to add half of the width and depth of the mesh into the noise function. So change "(xpos*strength)" and the y variant to "(xpos*strength) + (widthOfTerrain/2)".
Sorry for the lack of formatting and proper code examples but I'm on my phone. I'll try to edit this later to make it more understandable.
Answer by getyour411 · Sep 19, 2015 at 01:35 AM
Purchase Stitchscape.
To whomever downvoted, not that I care too much - but go ahead and offer your solution. There are hundreds, maybe thousands of questions like this: How do I seamless connect my Terrains?. I didn't close it as a duplicate because the OP actually showed willingness to work at it, but eventually every question of this sort ends up the same - unanswered. The best solution for the Unity user base that needs this functionality is to use Stitchscape. Prove me wrong!
If I could, I would've downvoted as well. Just saying "Purchase X" is not a good answer, because it gives no sort of solution for the one who asked the question. It's just solicitation for the sake of solicitation.
A good answer would be: "You might want to try X, because it has feature Y that can do Z for you. I know you'll have to rewrite your entire thing, but if it's the functionality you're after, then X is the way to go. It costs $$anonymous$$ money, but you'll get N, O and P with it, and the Q feature makes it superior to everything else.
Check these examples, to see why."
But even then, as far as you know, the person asking the question might have wanted to know how to do it, to understand the code, rather than for a final product. In this case, I was doing some research and was trying to get into how Unity and noise map generation worked. I didn't want a product to just buy, I wanted to know how Unity handled things.
I have since abandoned this particular problem, but upon revisiting the methods in other projects, this problem has not shown up, so I still don't know what went wrong here. What I do know is that "Buy X" is not the answer I was looking for.
Anyone landing on this page from Google/Search reads through this (and all the other/duplicate posts) but once again finds it left unanswered. Stitchscape is a perfectly viable solution - spend a few bucks and this problem is solved.
A simple search on it will tell you the rest, there's no reason I need to search for you or anyone else to report "you should try X because it has feature Y..."
No, the answer to the question asked is use Stitchscape. The answer to the whine about 'but you didn't tell me features Y and it can do Z and will I get N O P Q with it?' - to that I say, do it yourself.
As I said, just saying "buy this" is not a proper answer, because you're not giving any reason for why I should buy it. It's like someone walking up to you on the street, asking for directions, and you're just saying "buy this book". The book might help them, the book might have exactly what they need to get to where they need to be, but they'll be buying the book on the word of a stranger, without ever knowing if the book will help or not. They weren't asking for literature, they were asking for directions, so even if that book would help them, they have no reason whatsoever to buy that book, without you explaining why you're recommending it.
And when asked why, your answer is "google it". Well, in that case, you might as well google the answer... in the case of an online help board, the chances are quite huge that this has already been done.
All this makes you look less like a helper and more like an advertiser.
The Asset store is full of great components that can save time and effort and move production along. It's completely viable to suggest one - nothing you say will dissuade me from that. I didn't say 'Buy uiScript' or 'Buy $$anonymous$$ixomo' or some random "book", I said buy a product that solves this problem and leave the follow-up to you, where it belongs so you can make your own decision. And anyone else searching for and finding this or any of the other countless duplicate questions about how to solve terrain seams knows there is an answer in a very reasonable priced Asset Store solution.
And just in case anyone wonders, I have absolutely no affiliation with it.
So write that as your answer, rather than just two words. In this case, it would not solve the problem, as again, that's not what I was after. I'm sure whoever downvoted you would not have done so if you had written that explanation, ins$$anonymous$$d of expecting us to react positively to what is essentially a poorly written and unwanted advertisement.
Now you are back to haranguing me about using two words ins$$anonymous$$d of 75; the extra 73 aren't needed to anyone who can lookup Stitchscape and form their own opinion. I put the Answer out there because you had not updated it since $$anonymous$$ay and it seemed doomed to be another eternal unanswered seamless terrain question. As a new Answer has now been accepted, I'm happy to see this move off of the Unanswered queue.
Your answer
Follow this Question
Related Questions
Distribute terrain in zones 3 Answers
Cube World Terrain generation 2 Answers
Mesh based on noise 1 Answer
[C#] Wondering what is amiss with my 1D Perlin Noise Terrain Generator? 2 Answers