- Home /
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:
![alt text][1]
What I'm trying to achive is a hilly hill, something more like ![alt text][2]
(The second one was made in the editor, not by code lol).
MANY thanks for anyone who helps me out! :) [1]: /storage/temp/13506-untitled.png [2]: /storage/temp/13507-untitled2.png
Answer by tnetennba · Jul 25, 2013 at 01:26 PM
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);
     }
Looks good, I'll try it out and see if it works for this issue :)
It works great! $$anonymous$$any thanks, that is what I was looking for! :)
Answer by raygun · Sep 01, 2016 at 08:36 AM
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: http://www.css3beziercurve.net
controlPoint1 = site.point1 & 2
controlPoint2 = site.point3 & 4
Attach the script to a Terrain, set up the properties and hit Generate.
Your answer
 
 
              koobas.hobune.stream
koobas.hobune.stream 
                       
                
                       
			     
			 
                