Procedural Mesh Tutorial

Posted by admin on May 26th, 2019 filed in Development, Games

If you’re a hobbyist game developer, you surely have looked into https://store.unity.com/. The Personal edition is free if you make little or no money from selling games. You are only expected to upgrade to the $25-monthly subscription after you earn $100k-200k per year. That’s a very fair deal that gives any hobbyist a chance to become proficient in the tool without investing a lot of money up front.

Now I’m watching this extremely well done tutorial by Board To Bits Games on procedural mesh generation. Basically, instead of creating 3D objects in an editor (such as Blender), I want to write a script that generates custom objects out of triangles.

Procedural generation only makes sense for creating objects that are simple or follow math functions, of course, you typically wouldn’t use it for naturalistic/artistic content. What I like about procedural generation is that it is similar to natural language generation — there is syntax and semantics in how characters, cities, vehicles, etc. are composed in meaningful ways. :-)

Here my notes from watching the tutorial:

Unity uses C Sharp, and the basics are easy to pick up for people who know Java. Also Visual Studio gives helpful hints if you, say, capitalise a method wrong.

The C# data types needed to create custom meshes

Vector3[] vertices
Vertices define where the corner points of the shape are in 3D (but not the order in which they are connected). Numbered by index. Reusable.
int[] triangles
A list of vertex indices in the order so they form triangles. Triangle corners are read in groups of three. We define the order clockwise, that’s important because it implicitly defines the triangle’s frontside (which is used by the backface-culling optimisation).

Creating the GameObject in Unity

In Unity, create a new scene, with a camera, directional light, and GameObject.
In the Scene Hierarchy, select the GameObject (we can rename it). Then in the Inspector:

  1. Add component “mesh filter” to GameObject. Holds an instance of (built-in) Mesh class which defines the shape.
  2. Add component “mesh renderer”. Renderer uses info in the Filter to draw the surface of the mesh object on the screen.
    Open the Material property and click the Element selector to select any material (for testing).
  3. Add “new script” in C Sharp. That’s because we don’t want to fill the mesh with statically loaded data, we want to fill it procedurally = script.

Writing the script in Visual Studio

Next we open the (default generated) script in VS.

  1. In the script header, we want to ensure that our mesh script can only be added to a suitable object:
    [RequireComponent (typeof(MeshFilter))]
  2. In the class, add private variables to hold the mesh, its triangles and its vertex data.
  3. Create a void function that initialises the data — this is where the custom proc gen code goes. (For testing, you can of course use static values.)
  4. Create a void function that loads the custom mesh data into this Unity GameObject. Since we added the MeshFilter Component to this GameObject, we can do that.

Here’s the code sample with static mesh generation — it generates one triangle.

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(MeshFilter))]

public class ProcGenMesh : MonoBehaviour
{
    Mesh mesh;
    Vector3[] vertices;
    int[] triangles;

    // ------ custom methods -------

    // 1) I procedurally generate custom shape data.
    private void GenerateMeshData()
    {
        // generate vertices here
        vertices = new Vector3[] { new Vector3(0, 0, 0), new Vector3(0, 0, 1), new Vector3(1, 0, 0) };

        // generate triangle indices here
        triangles = new int[] { 0,1,2 };

    }
    // 2) reset myself and load the generated shape data.
    private void LoadMeshData()
    {
        mesh.Clear(); // reset
        mesh.vertices = vertices;
        mesh.triangles = triangles;
    }

    // ------ built-in methods -------

    void Awake() // 1) I init myself as a mesh
    {
        mesh = GetComponent().mesh; 
    }

    void Start() // 2) I generate and load my mesh content
    {
        GenerateMeshData();
        LoadMeshData();
    }

    void Update(){} // 3) I run my main update loop, once per frame -- not used yet.

}

Comments are closed.