Procedural, curved mesh generation in Unity — Part 1

Procedural mesh generation is a very important skill for a game developer, especially if you’re making one of these endless games. Take Alto’s Adventure or Tiny Wings for example. Both of these games generate beautiful endless, curved terrain. In this article I’m going to show you a way to generate meshes like these using Unity and cubic Bezier curves.

Alto's Adventure

Before we proceed it will help us to very briefly describe what a mesh is. A mesh is essentially the underlying skeleton for all your models and it is made up entirely of triangles. The most simple example of a mesh is called a Quad — a square that is made from 2 triangles:

Quad

More complex meshes simply have more triangles and our mesh generation code will do just this. Create triangles. More specifically it will create vertices and then define how those vertices connect to form triangles. Let’s look at a slightly more complicated mesh:

Mesh 1

As you can see this mesh is essentially 3 quads. There are 4 vertices at the top and 4 at the bottom. Now the reason I’ve chosen this shape as our starting point is because we can construct a single cubic Bezier curve from the 4 points on top. Let’s take a look at the code needed to generate this. In your Unity scene add a new Quad and then to it a new Script:

using UnityEngine;
using System.Collections.Generic;
 
public class TerrainGenerator : MonoBehaviour {
 
   // Reference to the mesh we will generate
   private Mesh mesh = null;
 
   // The terrain points along the top of the mesh
   private Vector3[] points = null;
 
   // Mutable lists for all the vertices and triangles of the mesh
   private List<Vector3> vertices = new List<Vector3>();
   private List<int> triangles = new List<int>();
 
   void Start () {
 
      // Get a reference to the mesh component and clear it
      MeshFilter filter = GetComponent<MeshFilter>();
      mesh = filter.mesh;
      mesh.Clear();
 
      // Generate 4 random points for the top 
      points = new Vector3[4];
      for (int i = 0; i < points.Length; i++) {            
         points[i] = new Vector3(0.5f * (float)i, Random.Range(1f, 2f), 0f);
         AddTerrainPoint(points[i]);    
      }
 
      // Assign the vertices and triangles to the mesh
      mesh.vertices = vertices.ToArray();
      mesh.triangles = triangles.ToArray();
   }
 
   void AddTerrainPoint(Vector3 point) {
     // Create a corresponding point along the bottom
     vertices.Add(new Vector3(point.x, 0f, 0f));
     // Then add our top point
     vertices.Add(point);
     if (vertices.Count >= 4) {
         // We have completed a new quad, create 2 triangles
         int start = vertices.Count - 4;
         triangles.Add(start + 0);
         triangles.Add(start + 1);
         triangles.Add(start + 2);
         triangles.Add(start + 1);
         triangles.Add(start + 3);
         triangles.Add(start + 2);    
      }
   }
}

Let’s go through what this is doing. In the Start call I essentially create 4 random points for the top part of the mesh and then I add each one using AddTerrainPoint. For each point passed to this function for the top of the mesh, a corresponding point is also created along the bottom.

Since this function is creating 2 points, every call after the first will complete a new quad and 2 triangles will be added. A triangle is represented by 3 integers, each integer corresponding to a vertex in the vertices array. However, the ordering of these integers is very important. Let’s take a look at our first pair of triangles:

Triangles

Each number above represents the index of the vertex in the vertices array. When creating a triangle we need 3 vertices in a clockwise order. This is because a front-facing polygon in Unity has a clockwise winding order. If we start at index 0 and move clockwise we get 0 — 1 then 1 — 2 and from this Unity already knows 2 — 0. So our first triangle is simply 0, 1, 2. The second 1, 3, 2. We can repeat this process for each new pair of vertices added.

Now, with this code in place it is very easy to generate a curved mesh. We already have a method to add points to the terrain and create the necessary triangles. Instead of using the 4 points along the top as vertices for our terrain, let’s use them to create a Bezier curve.

private Vector3 CalculateBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) {
 
      float u = 1 - t;
      float tt = t * t;
      float uu = u * u;
      float uuu = uu * u;
      float ttt = tt * t;
 
      Vector3 p = uuu * p0;
      p += 3 * uu * t * p1;
      p += 3 * u * tt * p2;
      p += ttt * p3;
 
      return p;
}

The function above will compute a point on the curve at t, a value between 0.0 and 1.0 which represents the start point and end point of the curve. The other two points are called the control points. You can learn more about how this works here.

So, let’s go back to the code and change it to use this function. In our Start call add:

points = new Vector3[4];
for (int i = 0; i < points.Length; i++) {            
    // Generate 4 random points
    points[i] = new Vector3(0.5f * (float)i, Random.Range(1f, 2f), 0f);
    // AddTerrainPoint(points[i]);
}
// Number of points to draw, how smooth the curve is
int resolution = 20;
for (int i = 0; i < resolution; i++) {
    float t = (float)i / (float)(resolution - 1);
    // Get the point on our curve using the 4 points generated above
    Vector3 p = CalculateBezierPoint(t, points[0], points[1], points[2], points[3]);
    AddTerrainPoint(p);
}

Now if you run it in Unity you’ll see that our mesh looks like this:

Curve

This concludes Part 1. In the next part of this series I will show you how to generate multiple curves, how to stitch them together and apply smoothing. You can check out the full source for this tutorial on Github.