- Home /
Tiling problem with Perlin generated terrain chunks
I'm trying to create a procedural generator for terrain using Unity's Perlin Noise generator. I've managed to create a grid of 3x3 terrains with what seems to be a working repetition, except at the very top and right edges of each terrain they take a plunge to 0.
I've looked around for solutions to this (mostly trying to offset the noise applied by 1 pixel up and right), but nothing seems to work. Any ideas what I'm doing wrong? Thanks in advance!
void GenerateMesh (int xOrg, int yOrg)
{
float[,] Heights= MultiDim.FloatArray ((int)m_MapSize.x, (int)m_MapSize.y);
Heights=CalcNoise (xOrg,yOrg);
TerrainData NewTerrain= new TerrainData();
NewTerrain.heightmapResolution = (int)m_MapSize.x;
NewTerrain.size = new Vector3 (m_MapSize.x, m_MaxHeight, m_MapSize.y);
NewTerrain.baseMapResolution = (int)m_MapSize.x/2;
NewTerrain.SetDetailResolution (1024, 16);
NewTerrain.SetHeights(0,0,Heights);
GameObject TerrainSquare= Terrain.CreateTerrainGameObject(NewTerrain);
TerrainSquare.transform.position = new Vector3 ((xOrg*m_MapSize.x)-m_MapSize.x/2, 0,(yOrg*m_MapSize.y)-m_MapSize.y/2);
}
public float PerlinNoise(float x, float y)
{
float noise = Mathf.PerlinNoise (x/(m_MapSize.x)*m_ScaleRED,(y/(m_MapSize.y)*m_ScaleRED));
return noise;
}
float[,] CalcNoise(int xOrg, int yOrg)
{
float y = 0.0f;
float [,] finalheight =MultiDim.FloatArray ((int)m_MapSize.x, (int)m_MapSize.y);
while (y < m_NoiseTexture.height)
{
float x= 0.0f;
while (x < m_NoiseTexture.width)
{
float Xcoord = xOrg*m_MapSize.x+(x-1);
float Ycoord = yOrg*m_MapSize.y+(y-1);
float ColorSample = PerlinNoise(Xcoord,Ycoord);
m_PixelColor[(int)y*m_NoiseTexture.width+(int)x]= new Color(ColorSample,ColorSample,ColorSample);
finalheight[(int)y,(int)x]=0+(ColorSample);
x++;
}
y++;
}
m_NoiseTexture.SetPixels (m_PixelColor);
m_NoiseTexture.Apply ();
return finalheight;
}
Answer by AlucardJay · Jun 25, 2014 at 11:56 AM
The problem is heightmaps are to the power of 2 + 1. Imagine it like this :
Each black dot is a member of the heightmap array. Each color square is a member of the NoiseTexture array.
Factoring this in, your Heights Arrays would be (int)m_MapSize.x + 1 (same for y). For the noise you would also need to loop through every member of the heightmap array. But with your texture you have to check if you havn't exceeded the texture array size. (Or also for the colours you may want to interpolate a sample that is in between the heightmap array values).
eg :
void GenerateMesh (int xOrg, int yOrg)
{
float[,] Heights= MultiDim.FloatArray ((int)m_MapSize.x + 1, (int)m_MapSize.y + 1);
Heights = CalcNoise (xOrg,yOrg);
TerrainData NewTerrain = new TerrainData();
NewTerrain.heightmapResolution = (int)m_MapSize.x;
NewTerrain.size = new Vector3 (m_MapSize.x, m_MaxHeight, m_MapSize.y);
NewTerrain.baseMapResolution = (int)m_MapSize.x/2;
NewTerrain.SetDetailResolution(1024, 16);
NewTerrain.SetHeights(0,0,Heights);
GameObject TerrainSquare = Terrain.CreateTerrainGameObject(NewTerrain);
TerrainSquare.transform.position = new Vector3 ((xOrg*m_MapSize.x)-m_MapSize.x/2, 0,(yOrg*m_MapSize.y)-m_MapSize.y/2);
}
public float PerlinNoise(float x, float y)
{
float noise = Mathf.PerlinNoise (x/(m_MapSize.x)*m_ScaleRED,(y/(m_MapSize.y)*m_ScaleRED));
return noise;
}
float[,] CalcNoise(int xOrg, int yOrg)
{
float [,] finalheight =MultiDim.FloatArray ((int)m_MapSize.x + 1, (int)m_MapSize.y + 1);
float y = 0.0f;
while (y < m_NoiseTexture.height + 1)
{
float x = 0.0f;
while (x < m_NoiseTexture.width + 1)
{
float Xcoord = xOrg*m_MapSize.x+(x-1);
float Ycoord = yOrg*m_MapSize.y+(y-1);
float ColorSample = PerlinNoise(Xcoord,Ycoord);
finalheight[(int)y,(int)x]=0+(ColorSample);
if ( y < m_NoiseTexture.height && x < m_NoiseTexture.width ) // check if within the texture array
m_PixelColor[(int)y*m_NoiseTexture.width+(int)x]= new Color(ColorSample,ColorSample,ColorSample);
x++;
}
y++;
}
m_NoiseTexture.SetPixels (m_PixelColor);
m_NoiseTexture.Apply ();
return finalheight;
}
Oh my, thank you! This fixes it (other than a few very slight seams, but they're almost innoticeable) quite elegantly. I do have to say it seems very strange to me for the heightmaps to use odd dimensions, any idea why this is the case?
On another note, I just noticed that around the seams the terrain is behaving oddly. I get a lot of shapes like the one in the screenshot. Did I do something wrong in the tiling of the noisemap, or is this something else?
TerrainData is a highly guarded secret by Unity! All my findings are based on trial and error rather than actual knowledge, but I shall try to answer.
I can only guess that the heightmaps are 2^n+1 for using the heightmap vertices as UV coordinates for the splatmap data. Like the picture in my answer, one quad would need 4 vertices for generating the triangles and assigning UVs.
The noticeable 'seams' are probably the calculations for the normal of each vertex in the terrain. At the edges, the terrain cannot get all of the adjacent vertices (because they don't exist from the perspective of each terrain object), therefore they are calculated as flat rather than in relation to where the adjacent vertices of the next terrain piece are.
Regarding your image, this looks like mirroring of the perlin noise. All I can assume is you are assigning your terrain chunks between a negative value and a positive value. Perlin Noise doesn't continue into the negative axis, rather the results are a mirror of the positive axis, eg :
// both of these will return the same value
$$anonymous$$athf.PerlinNoise ( 1, 1 );
$$anonymous$$athf.PerlinNoise ( -1, 1 );
// both of thee will return the same value
$$anonymous$$athf.PerlinNoise ( 2, 1 );
$$anonymous$$athf.PerlinNoise ( -2, 1 );
// etc etc
the only way to compensate for this would be to start your chunks at (0,0), and increment positively. Or add an offset in your PerlinNoise function with a magnitude greater than half of your world size so that all perlin noise values returned are in the values of positive perlin axis.
Your answer
Follow this Question
Related Questions
How can I correctly offset seeded perlin noise over multiple terrains? 1 Answer
Tile generation problem 1 Answer
[BEGINNER] Generating Terrain with Perlin noise flat and nothing happens ? 1 Answer
Only Effect One Material? 1 Answer
How would one approach tile-by-tile terrain generation with Perlin Noise? 0 Answers