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;

	}

The problem is heightmaps are to the power of 2 + 1. Imagine it like this :

28256-heightmapexample.png

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;
}