Terrain hill generating by code

Hello, friends.

I have a small problem which I couldnt find a solution for.

I am working on a terrain which randomly generates hills on it, I have made a method which makes hills, but makes them very pointy, more like round pyramids.

Thats the call for the method:

CreateHill(Random.Range(0,513),Random.Range(0,513),Random.Range(0.005f,0.1f),Random.Range(1f,10f));

and thats the method itself:

public void CreateHill(int x, int y, float height,float pointyness)
	{
		float point = 0;
		float distanceFromTop;
		
		terrainGRID[x,y]=height;

		for(int a=0;a<513;a++)
		{	
			for(int b=0;b<513;b++)
			{
				distanceFromTop=Mathf.Sqrt(   Mathf.Pow((y-b),2)  +  Mathf.Pow((x-a),2)   );
		 		point=((height-terrainGRID[a,b])*1000 - distanceFromTop*pointyness)/1000 ;
				
				if(point<0)
				point=0;
				
				terrainGRID[a,b]+=point;
			}
		}
	}

what comes from it is:

What I’m trying to achive is a hilly hill, something more like

(The second one was made in the editor, not by code lol).

MANY thanks for anyone who helps me out! :slight_smile:

you need something like this to smooth your terrain points and round everything off a little. It’s not the best example of terrain smoothing but it should give you an idea of what to do.

    private void Smooth()
    {

        float[,] height = terrain.terrainData.GetHeights(0, 0, terrain.terrainData.heightmapWidth,
                                          terrain.terrainData.heightmapHeight);
        float k = 0.5f;
        /* Rows, left to right */
        for (int x = 1; x < terrain.terrainData.heightmapWidth; x++)
            for (int z = 0; z < terrain.terrainData.heightmapHeight; z++)
                height[x, z] = height[x - 1, z] * (1 - k) +
                          height[x, z] * k;

        /* Rows, right to left*/
        for (int x = terrain.terrainData.heightmapWidth - 2; x < -1; x--)
            for (int z = 0; z < terrain.terrainData.heightmapHeight; z++)
                height[x, z] = height[x + 1, z] * (1 - k) +
                          height[x, z] * k;

        /* Columns, bottom to top */
        for (int x = 0; x < terrain.terrainData.heightmapWidth; x++)
            for (int z = 1; z < terrain.terrainData.heightmapHeight; z++)
                height[x, z] = height[x, z - 1] * (1 - k) +
                          height[x, z] * k;

        /* Columns, top to bottom */
        for (int x = 0; x < terrain.terrainData.heightmapWidth; x++)
            for (int z = terrain.terrainData.heightmapHeight; z < -1; z--)
                height[x, z] = height[x, z + 1] * (1 - k) +
                          height[x, z] * k;

        terrain.terrainData.SetHeights(0, 0, height);
    }

OK, so I took your code that process a grid, using the distance from the centre to calculate the hill height.

Now, if you use a linear function you’ll get a linear/sharp hill.

So, my version uses a bezier function which creates a nice sloping hill.

[ExecuteInEditMode]
public class HillGenerator : MonoBehaviour
{
public int x;
public int y;
public int radius;
public float height;
}

[CustomEditor (typeof(HillGenerator))]
public class HillGeneratorEditor : Editor
{
	public static Vector2 BezierCurve(float t, Vector2 pOne, Vector2 pTwo, Vector2 pThree, Vector2 pFour)
	{
		return Mathf.Pow (1 - t, 3) * pOne + 3 * Mathf.Pow (1 - t, 2) * t * pTwo + 3 * (1 - t) * t * t * pThree + Mathf.Pow (t, 3) * pFour;
	}

	public override void OnInspectorGUI()
	{
		DrawDefaultInspector ();

		var script = this.target as HillGenerator;

		if (GUILayout.Button ("Generate"))
		{
			this.CreateHill (script.x, script.y, script.height, script.radius);
		}
	}

	public void CreateHill(int x, int y, float height, int radius)
	{
		var diameter = radius * 2;
		var heightsCenteX = radius;
		var heightsCenteY = radius;
		var baseX = x - heightsCenteX;
		var baseY = y - heightsCenteY;

		var script = this.target as HillGenerator;
		var terrianData = script.GetComponent<Terrain> ().terrainData;
		var heights = terrianData.GetHeights (baseX, baseY, diameter, diameter);

		var controlPoint1 = new Vector2 (0.52f, 0.06f);
		var controlPoint2 = new Vector2 (0.42f, 0.95f);

		for (int a = 0; a < diameter; a++)
		{    
			for (int b = 0; b < diameter; b++)
			{
				var distanceFromCenter = Mathf.Sqrt (Mathf.Pow ((heightsCenteY - b), 2) + Mathf.Pow ((heightsCenteX - a), 2));
				var time = Math.Max (1 - (distanceFromCenter / radius), 0);
				var bezierPoint = BezierCurve (time, new Vector2 (0, 0), controlPoint1, controlPoint2, new Vector2 (1, 1));

				var pointHeight = bezierPoint.y * height;

				if (pointHeight < 0)
					pointHeight = 0;

				heights [a, b] = pointHeight;
			}
		}

		terrianData.SetHeights (baseX, baseY, heights);
	}
}

example: CreateHill(250, 250, 0.3, 100)

To visualise the curve you can use this site:

controlPoint1 = site.point1 & 2

controlPoint2 = site.point3 & 4

Attach the script to a Terrain, set up the properties and hit Generate.