If you haven’t heard about it before, Procedural Mesh Generation is a very cool and flexible way to make your models and assets by generating them dynamically using math and code, instead of modeling everything by hand in your specific 3D modeling software of choice.

Doing things this way can get pretty involved and means you’ll need to be intimately aware of almost every little triangle in your mesh and how it’s made. It’s probably not be the best way to go about modeling things if what you need is just a simple, static character or prop for your scenes. BUT this approach gives you pretty much full control over your mesh during runtime. It can be very useful if you want to make dynamic assets that change based on user input or events that happen in game.

Usually, generated meshes are used  for things like making dynamic levels, drawing 3D UI elements, (editable) terrain, fences/ walls , destructible objects and much, much more.

I highly recommend checking out Jayelindas’s blog post on this topic. It explains the whole process in a very approachable way. I ended up referencing it all the time and have been using a lot of the code pretty much as is. In fact much of the code you’ll see in this post is from there, I just added a few bits for my own purposes. What follows is kind of a short summation my experience using it for making my own meshes.

It’s Pretty Weird at First – Using Helper Classes Helps!

Keeping track of all the vertices and triangles gets exponentially harder the more complex your meshes get. It becomes important to make many little helper functions that’ll get some of the tedious grind out of the way and automate the process as much as possible.

One thing that helps with organizing things is having some structs or other classes to hold the vertex data for you.

This is a simple Quad struct that holds four Vector3 points that will represent the corners of a simple rectangle. It also has a Normal vector to hold it’s.. well –  Normal Vector.

public struct Quad
{
    public Vector3 Normal , TopLeft , TopRight , BottomLeft , BottomRight ;

    public Quad ( Vector3 BottomLeft , Vector3 TopLeft , Vector3 TopRight , Vector3 BottomRight , Vector3 Normal )
    {
       this.Normal      = Normal ;
       this.TopLeft     = TopLeft ;
       this.TopRight    = TopRight ;
       this.BottomLeft  = BottomLeft ;
       this.BottomRight = BottomRight ;
    }
}

A good way to simplify the mesh making process is to make triangle, plane, box, etc. building functions that automate the placement of vertices. This way you don’t have to worry about every single little vertex all the time and focus on what your trying to build instead.

Like say you need a floor tile and you know it’s always gonna be laying flat on the ground and facing a certain way. You can then make a function that builds the tile using just a single position vector (or maybe also width/height if you’re feeling fancy).

Here’s an example of a basic floor tile builder that makes a quad based on a position, width, length and a specific ground height:

public static Quad FloorQuad ( int x , int y , float width , float length , float height)
{
    Vector3 normal      = Vector3.up ;
    Vector3 topLeft     = new Vector3 ( x - width  , height , y + length );
    Vector3 topRight    = new Vector3 ( x + width  , height , y + length );
    Vector3 bottomLeft  = new Vector3 ( x - width  , height , y - length );
    Vector3 bottomRight = new Vector3 ( x + width  , height , y - length );

    return new Quad ( bottomLeft , topLeft , topRight , bottomRight , normal );
}

 If you REALLY don’t want to bother with all of that, and just want a quad of a fixed size,  than you can easily get away with just having something like this:

 This one makes a 1×1 unit square quad at ground level for any position x,y (y in this case will actually be the Z axis in world space). The position is supplied as an int so the vertex of every square tile will align perfectly if they are positioned next to each other as long as you make sure not to pass in the same position multiple times.

public static Quad FloorQuad ( int x , int y )
{
    Vector3 normal      = Vector3.up;
    Vector3 topLeft     = new Vector3 ( x - 0.5f , 0f , y + 0.5f );
    Vector3 topRight    = new Vector3 ( x + 0.5f , 0f , y + 0.5f );
    Vector3 bottomLeft  = new Vector3 ( x - 0.5f , 0f , y - 0.5f );
    Vector3 bottomRight = new Vector3 ( x + 0.5f , 0f , y - 0.5f );

    return new Quad ( bottomLeft , topLeft , topRight , bottomRight , normal );
}

Make an Object From Script

First off you’ll need some variables to hold the mesh, material, object reference and the prefab that will be used to instantiate new objects from. ( you can create that object through code also, but I decided to use a prefab ) Just a simple empty game object with a Mesh Filter and Mesh Renderer Component on it will do the job.

public  GameObject  meshPrefab ;
public  Material    meshMaterial ;
private GameObject  meshObject ;
private Mesh        mesh ;

You have to instantiate the object before you can add your meshes to it, naturally. ( I do that in Start() )

The parent here is set to the object that’s running this script, but you are encouraged to not be a slob and come up with a neat and tidy system to organize your objects. So put it away somewhere and don’t clutter your scene with a billion different spawned objects, you’ll thank me later!

meshObject = Instantiate ( meshPrefab ) as GameObject;
meshObject.transform.SetParent ( transform );
meshObject.name = "YourMeshObjectName";

You probably want to have a material on your brand new object. ( unless you want it displayed in the debug shader’s  neon pink, which is a bold choice, but not super useful outside provocative art projects )

You can add a material at any time, or change it whenever, doing it now just means you won’t have to worry about it later.

meshObject.GetComponent<Renderer>().material = meshMaterial ;

This step creates a new mesh and saves it for later use

MeshFilter meshFilter = meshObject.GetComponent <MeshFilter> ( );
meshFilter.mesh = new Mesh ( );
mesh = meshFilter.sharedMesh ;

If you plan on making a lot of changes to your object at runtime, it’s a good idea to mark the mesh as dynamic – very simply like so:

mesh.MarkDynamic ( );

 Make-A-Mesh!

This part is the real meat of the process. If you’ve been very diligent and thoughtful with your helper classes, it can also be surprisingly straight forward too!

Every mesh object you want to make should have its own Mesh Builder object. Once you have that you can pass it triangles, quads and any other other geometry you want built. When everything is ready simply set the mesh with your mesh builder object and you’re done!

MeshBuilder meshBuilder = new MeshBuilder ( );
Quad quad = Quad.FloorQuad ( x , y );
ProceduralMesh.BuildQuad ( meshBuilder , quad );
ProceduralMesh.SetMesh ( meshBuilder , ref mesh );

Looks simple, right?  Well that’s because all the heavy lifting and unsightly code is tucked away in handy helper functions!

Speaking of which, here’s what the BuildQuad and SetMesh functions from the above code look like.( again, scavenged from Jayelinda’s post )

public void SetMesh ( MeshBuilder meshBuilder , ref Mesh mesh )
{
    Mesh newMesh = meshBuilder.CreateMesh ( );
    mesh.Clear ( );

    mesh.vertices = newMesh.vertices;
    mesh.uv = newMesh.uv;
    mesh.triangles = newMesh.triangles;
    mesh.colors = newMesh.colors;
    mesh.RecalculateNormals ( );

    mesh.RecalculateBounds ( );
    mesh.Optimize ( );
}

public static void BuildQuad ( MeshBuilder meshBuilder , Quad quad )
{
    BuildQuad ( meshBuilder , quad.BottomLeft , quad.TopLeft , quad.TopRight , quad.BottomRight , quad.Normal ); 
}
public static void BuildQuad ( MeshBuilder meshBuilder , Vector3 bottomLeft , Vector3 topLeft , Vector3 topRight , Vector3 bottomRight , Vector3 normal )
{
    meshBuilder.Vertices.Add ( bottomLeft );
    meshBuilder.UVs.Add ( new Vector2 ( 0f , 0f ) ); 
    meshBuilder.Normals.Add ( normal );

    meshBuilder.Vertices.Add ( topLeft );
    meshBuilder.UVs.Add ( new Vector2 ( 0f , 1f ) );
    meshBuilder.Normals.Add( normal );
   
    meshBuilder.Vertices.Add ( topRight );
    meshBuilder.UVs.Add ( new Vector2 ( 1f , 1f ) );
    meshBuilder.Normals.Add( normal );

    meshBuilder.Vertices.Add ( bottomRight );
    meshBuilder.UVs.Add ( new Vector2 ( 1f , 0f ) );
    meshBuilder.Normals.Add( normal );

    //we don't know how many verts the meshBuilder is up to, but we only care about the four we just added:
    int baseIndex = meshBuilder.Vertices.Count - 4;
   
    meshBuilder.AddTriangle ( baseIndex , baseIndex + 1 , baseIndex + 2 );
    meshBuilder.AddTriangle ( baseIndex , baseIndex + 2 , baseIndex + 3 );
}

 

There see, it’s actually not that intimidating, when you get into it. Once you can get in the habit of imagining how the triangles get built and the order in which to put the vertices in you’ll do just fine.

I encourage you to go ahead and dabble in mesh generation yourself. It’s quite rewarding and you can make some amazing things with it!

– Happy Meshing!