Endless, 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 Bezier curves.

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:

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:

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
    Mesh mesh;
 
    // The points used to create the curve
    Vector3[] curve = new Vector3[4];
 
    // The vertices and triangles of the mesh
    List<Vector3> vertices = new List<Vector3> ();
    List<int> triangles = new List<int> ();
 
    void Start ()
    {
        // Get a reference to the mesh and clear it
        var filter = GetComponent<MeshFilter> ();
        mesh = filter.mesh;
        mesh.Clear ();
 
        // Generate 4 random points for the top
        var xPos = 0f;
        for (int i = 0; i < curve.Length; i++) { 
            var p = new Vector3 (xPos, Random.Range (1f, 2f), 0f);
            curve [i] = p;
            AddTerrainPoint (p);
            xPos += 0.5f;
        } 
 
        // 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) {
            // 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.

Every new pair of points that is created, except the first, will complete a new quad. That means two triangles will be added. Each triangle is represented by 3 integers and each integer corresponds to a vertex in the vertices array. The ordering of these integers, however, is significant. Let’s take a look at our first pair of 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 01 then 12 and from this Unity already knows 20. So our first triangle is simply 0, 1, 2. The second is 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.

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. If you’re interested, 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:

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

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

In the next part of this series I show you how to generate multiple curves, or rather a Composite Bezier curve that is smooth and can be any length. You can check out the full source for this tutorial on Github.