Unity Procedural Sphere

Drag this on the GameObject. You will need the Custom/VertexColorShader which can also be found on here.

using UnityEngine;

public class ProceduralSphere : MonoBehaviour
{
    public float radius = 1.0f;
    public int subdivisions = 16;
    public Color color = Color.white;

    private void Start()
    {
        // Create a new mesh
        Mesh mesh = new Mesh();

        // Define the vertices of the sphere
        Vector3[] vertices = new Vector3[(subdivisions + 1) * (subdivisions + 1)];
        for (int i = 0; i <= subdivisions; i++)
        {
            float v = (float)i / (float)subdivisions * Mathf.PI;
            float sinV = Mathf.Sin(v);
            float cosV = Mathf.Cos(v);
            for (int j = 0; j <= subdivisions; j++)
            {
                float u = (float)j / (float)subdivisions * Mathf.PI * 2.0f;
                float sinU = Mathf.Sin(u);
                float cosU = Mathf.Cos(u);
                int index = i * (subdivisions + 1) + j;
                vertices[index] = new Vector3(sinU * sinV, cosV, cosU * sinV) * radius;
            }
        }

        // Define the triangles that make up the sphere
        int[] triangles = new int[subdivisions * subdivisions * 6];
        int triangleIndex = 0;
        for (int i = 0; i < subdivisions; i++)
        {
            for (int j = 0; j < subdivisions; j++)
            {
                int index = i * (subdivisions + 1) + j;
                triangles[triangleIndex++] = index;
                triangles[triangleIndex++] = index + 1;
                triangles[triangleIndex++] = index + subdivisions + 1;

                triangles[triangleIndex++] = index + 1;
                triangles[triangleIndex++] = index + subdivisions + 2;
                triangles[triangleIndex++] = index + subdivisions + 1;
            }
        }

        // Define the colors of each vertex
        Color[] colors = new Color[vertices.Length];
        for (int i = 0; i < colors.Length; i++)
        {
            colors[i] = color;
        }

        // Assign the vertices, triangles, and colors to the mesh
        mesh.vertices = vertices;
        mesh.triangles = triangles;
        mesh.colors = colors;

        // Create a new mesh renderer and assign the mesh to it
        MeshRenderer meshRenderer = gameObject.AddComponent<MeshRenderer>();
        meshRenderer.sharedMaterial = new Material(Shader.Find("Custom/VertexColorShader"));

        // Create a new mesh filter and assign the mesh to it
        MeshFilter meshFilter = gameObject.AddComponent<MeshFilter>();
        meshFilter.mesh = mesh;
    }
}

Unity Procedural Cube

Drag this on the GameObject. You will need the Custom/VertexColorShader which can also be found on here.

using UnityEngine;

public class ProceduralCube : MonoBehaviour
{
    public float size = 1.0f;
    public Color color = Color.white;

    private void Start()
    {
        // Create a new mesh
        Mesh mesh = new Mesh();

        // Define the vertices of the cube
        Vector3[] vertices = new Vector3[]
        {
            new Vector3(-size, -size, -size),
            new Vector3(-size, -size, size),
            new Vector3(-size, size, -size),
            new Vector3(-size, size, size),
            new Vector3(size, -size, -size),
            new Vector3(size, -size, size),
            new Vector3(size, size, -size),
            new Vector3(size, size, size),
        };

        // Define the triangles that make up the cube
        int[] triangles = new int[]
        {
            0, 1, 2, // front
            2, 1, 3,
            4, 0, 6, // back
            6, 0, 2,
            5, 4, 7, // right
            7, 4, 6,
            1, 5, 3, // left
            3, 5, 7,
            2, 3, 6, // top
            6, 3, 7,
            4, 5, 0, // bottom
            0, 5, 1,
        };

        // Define the colors of each vertex
        Color[] colors = new Color[]
        {
            color, color, color, color, color, color, color, color,
        };

        // Assign the vertices, triangles, and colors to the mesh
        mesh.vertices = vertices;
        mesh.triangles = triangles;
        mesh.colors = colors;

        // Create a new mesh renderer and assign the mesh to it
        MeshRenderer meshRenderer = gameObject.AddComponent<MeshRenderer>();
        meshRenderer.sharedMaterial = new Material(Shader.Find("Custom/VertexColorShader"));

        // Create a new mesh filter and assign the mesh to it
        MeshFilter meshFilter = gameObject.AddComponent<MeshFilter>();
        meshFilter.mesh = mesh;
    }
}

Unity Vertex Color Shader

Shader "Custom/VertexColorShader" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
    }
    SubShader {
        Tags {"Queue"="Transparent" "RenderType"="Opaque"}
        LOD 100

        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata {
                float4 vertex : POSITION;
                float4 color : COLOR;
            };

            struct v2f {
                float4 vertex : SV_POSITION;
                float4 color : COLOR;
            };

            float4 _Color;

            v2f vert (appdata v) {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.color = v.color * _Color;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target {
                return i.color;
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

Unity Mesh Modification

As part of the technical preview for a project I’m working on I have ran into an interesting problem that I’m trying to solve. In Unity when you use the OnCollisionEnter/OnCollisionExit collision handling and need the information about the mesh it is colliding with.

Modifying the mesh requires knowledge of the triangles that you are interacting with; however OnCollisionEnter doesn’t give you this information, you need a RayCastHit to access this information. One way to get the RayCastHit is to perform a Physics.Raycast call based on the collision contacts. Once you have the RayCastHit you can use triangleIndex on that object to get the required information including the vertex information.

Going from the OnCollisionEnter collision contacts to a RayCastHit that gives you the correct information isn’t as simple as it should be. You have to get an offset point that is just behind the collision point, and then do the Raycast from there otherwise it detect the triangles further away and misses the one that it should be detecting. Below is the code that I used to get this all working.

private void OnCollisionEnter(Collision collision) {
    GameObject colGo = collision.collider.gameObject;
    points = collision.contacts;
    if (points.Length > 0) {
        for (int i = 0; i < points.Length; i++) {
            Vector3 offsetPoint = points[i].point - (points[i].normal + (Vector3.down * 1.1f));
            Debug.DrawRay(offsetPoint, points[i].normal, Color.blue);
            Debug.DrawRay(offsetPoint, -points[i].normal, Color.yellow);
            Debug.LogFormat("{0}-{1}=>{2}", points[i].point, points[i].normal, offsetPoint);
            if (Physics.Raycast(offsetPoint, -points[i].normal, out RaycastHit hit, Mathf.Infinity)) {
                Debug.LogFormat("{0}||{1}", points[i].point, hit.triangleIndex);
                if (hit.triangleIndex != -1) {
                    Mesh mesh = hit.collider.gameObject.GetComponent<MeshFilter>().sharedMesh;
                    Vector3[] verts = mesh.vertices;
                    int[] triangles = mesh.triangles;
                    Vector3 _a = hit.transform.TransformPoint(verts[triangles[hit.triangleIndex * 3]]);
                    Vector3 _b = hit.transform.TransformPoint(verts[triangles[hit.triangleIndex * 3 + 1]]);
                    Vector3 _c = hit.transform.TransformPoint(verts[triangles[hit.triangleIndex * 3 + 2]]);
                    Debug.LogFormat("{0}|{1}|{2}", _a, _b, _c);
                    Debug.DrawLine(_a, _b);
                    Debug.DrawLine(_b, _c);
                    Debug.DrawLine(_c, _a);
                }
            }
        }
    }
}

Unity Custom Editor

This week I have been working on a Unity custom editor, with the goal of making meshes easier to work with.

It made sense to show this editor for the MeshFilter type, since that’s the script unity uses to store the Mesh object on. Anytime the MeshFilter selected in the editor the inspector shows the custom editor inspector.

The plan for the inspector was to show just the details of the Mesh; such as the number of vertices and the number of triangles. This could then be expanded to show the values of the vertices and triangles, and lastly allow them to be live editable.

The first part of the custom inspector; showing the details; was very simple, code shown below.

for (int idx = 0; idx < mesh.vertices.Length; idx++)
{
    string str = string.Format("{0} {1}", idx, mesh.vertices[idx].ToString());
    EditorGUILayout.LabelField(str);
}
int count = 0;
for (int idx = 0; idx < mesh.triangles.Length / 3; idx++)
{
    string str = string.Format(
        "{0}, {1}, {2}",
        mesh.triangles[count++],
        mesh.triangles[count++],
        mesh.triangles[count++]
    );
    EditorGUILayout.LabelField(str);
}

Showing the values of the vertices and triangles was simple. After viewing the output of this I came to the realization that most meshes have many duplicate vertices; hinting to me that an optimize functionality would come in handy. More on this optimization later. Below is the code used to display the mesh details.

public (Vector3[], int[]) Optimize(Mesh mesh)
{
    List<Vector3> verts = new List<Vector3>();
    Dictionary<int, int> nLocation = new Dictionary<int, int>();
    List<int> tris = new List<int>();
    for (int vIndex = 0; vIndex < mesh.vertices.Length; vIndex++)
    {
        Vector3 vert = mesh.vertices[vIndex];
        int idx = verts.IndexOf(vert);
        if (idx == -1)
        {
            idx = verts.Count;
            verts.Add(vert);
        }
        nLocation[vIndex] = idx;
    }
    for (int tIndex = 0; tIndex < mesh.triangles.Length; tIndex++)
    {
        int nLoc = nLocation[mesh.triangles[tIndex]];
        Debug.Log(nLoc);
        tris.Add(nLocation[mesh.triangles[tIndex]]);
    }
    Mesh m2 = new Mesh();
    m2.triangles = new int[0];
    m2.vertices = verts.ToArray();
    m2.triangles = tris.ToArray();
    return (verts.ToArray(), tris.ToArray());
}

After running this code on the Cube mesh the results contain much less vertices, while retaining the original shape.

Solution #1 Unity Mesh Walls

The solution I have chosen is as follows. Use bezier curve that has 2 control points, these are each end of the line. Then set the rotation based on the tangent at the midpoint. Code shown below.

private static Vector3 CalculateTangent(float t, Vector3 p0, Vector3 p1)
{
    float a = 1 - t;
    float b = a * 6 * t;
    a = a * a * 3;
    float c = t * t * 3;
    return (-a * p0) + (c * p1);
}
public Mesh CalculateMesh()
{
    Mesh mesh = new Mesh();
    List<Vector3> verts = new List<Vector3>();
    Quaternion quaternion = Quaternion.LookRotation(CalculateTangent(0.5f, startPosition, endPosition));
    verts.Add( (quaternion * new Vector3(-widthOffset, 0.0f, 0.0f)) + startPosition );   // 0
    verts.Add( (quaternion * new Vector3(widthOffset, 0.0f, 0.0f)) + startPosition );    // 1
    verts.Add( (quaternion * new Vector3(-widthOffset, height, 0.0f)) + startPosition ); // 2
    verts.Add( (quaternion * new Vector3(widthOffset, height, 0.0f)) + startPosition );  // 3
    verts.Add( (quaternion * new Vector3(-widthOffset, 0.0f, 0.0f)) + endPosition );     // 4
    verts.Add( (quaternion * new Vector3(widthOffset, 0.0f, 0.0f)) + endPosition );      // 5
    verts.Add( (quaternion * new Vector3(-widthOffset, height, 0.0f)) + endPosition );   // 6
    verts.Add( (quaternion * new Vector3(widthOffset, height, 0.0f)) + endPosition );    // 7
    Face[] faces = new Face[] {
        new Face(0, 1, 2, 3),
        new Face(0, 1, 4, 5),
        new Face(0, 2, 4, 6),
        new Face(1, 3, 5, 7),
        new Face(2, 3, 6, 7),
        new Face(4, 5, 6, 7)
    };
    List<int> tris = new List<int>();
    for (int i = 0; i < faces.Length; i++)
    {
        tris.AddRange(faces[i].Tris());
    }
    mesh.vertices = verts.ToArray();
    mesh.triangles = tris.ToArray();
    return mesh;
}

Problem #1 Unity Mesh Walls

This is a problem I have encountered while working on my personal side project, a simulation game. Unity mesh allows developers to dynamically create meshes at runtime. Meshes take an array of Vector3s and an array of Integers to create the mesh. Vector3 is a data type that stores the X, Y, and Z positions as floating point numbers.

Creating an array of Vector3s, which is the vertices, and the array of integers; signifying the triangles; allows the developer to make any shape they would like. The array of integers which is grouped into threes, tells the mesh system which three vertices, by index from the array of vertices, make up the triangle. All triangles are rendered as one sided triangles, developers can change which side is rendered by swapping the first and last indexes of the triangle. Example 1,2,3 should be come 3,2,1 to reverse it.

Wall generation will utilize a starting and ending point, passed in as Vector3s. They also have an extrude height and an extrude width. This will allow a lot of customization in the long run. Below is an image showing the wall generation tool with two selected points that are 3 units apart in the X direction.

However when you make the same distance wall in the Z direction it looks more like the image below.

Broken Dynamically Generated Wall

The problem is when the walls are generated in the Z direction their extrude outward from the input points isn’t calculated correctly and makes the wall flat. Below is the code used to add the vertices to the list of vertices.

verts.Add(startPosition + new Vector3(0.0f, 0.0f, -widthOffset)); // 0
verts.Add(startPosition + new Vector3(0.0f, 0.0f, widthOffset));  // 1
verts.Add(startPosition + new Vector3(0.0f, height, -widthOffset)); // 2
verts.Add(startPosition + new Vector3(0.0f, height, widthOffset));  // 3
verts.Add(endPosition + new Vector3(0.0f, 0.0f, -widthOffset)); // 4
verts.Add(endPosition + new Vector3(0.0f, 0.0f, widthOffset));  // 5
verts.Add(endPosition + new Vector3(0.0f, height, -widthOffset));// 6
verts.Add(endPosition + new Vector3(0.0f, height, widthOffset)); // 7

Potential Solutions

Solution #1: Create the object using the distance between the start position and end position in the X(or Z) direction and then rotate the object towards the end point. This might work if you use the origin as the start position and then set transform.position on the object to move it to the correct position.

Solution #2: Use mathematic formula derived from the formula to calculate the tangent of a bezier curve to calculate the rotation needed at the start and end points.

Solution #3: Use bezier curve that has 4 points and set the two control points to the midpoint of the line. I have already implemented a 4 point bezier wall generation system, wouldn’t be too hard to convert. Four point bezier curve is shown below in wireframe mode.

Polygon Generation in Unity

Dynamic generation of polygonal 2d meshes is a useful stepping stone to more dynamic shapes. Unity Mesh object can be broken down into two major components, an array of Vector3s and an array of integers. The simplest polygons have equal angles and side lengths, this is an easy calculation to do; to calculate the X and Y values we use Cosine and Sine functions.

float angle = Mathf.Deg2Rad * ( 360 / sides );
Vector3[] verts = new Vector3[sides];
for (int i = 0; i < verts.Length; i++)
{
    float h = angle * i;
    float x = Mathf.Cos(h) * distance;
    float y = Mathf.Sin(h) * distance;
    verts[i] = new Vector3(x, y, 0.0f);
 }

The next step of making a mesh dynamically is to determine the triangles that the face is made up of. We first figure out how many triangles we require, this can be done by taking the number of vertices and subtract 2. Now we can walk thru each triangle and determine the index of each vertex. Making the simple assumption that every triangle of the face is going to start at the first vertex; we then have to determine the two other vertices. Once we determine the vertex indices of the individual triangles we then have to add them to the mesh triangles indices list. Before we can add them to that array we must order them so that the faces are facing the correct direction.

List<int> triangles = new List<int>();
int triangleCount = verts.Length - 2;
for (int i = 0; i < triangleCount; i++)
{
    int a = 0;
    int b = 1 + i;
    int c = 2 + i;
    switch (faceDirection)
    {
        case FaceDirection.FRONT:
            triangles.AddRange(new int[] { c, b, a });
            break;
        case FaceDirection.BACK:
            triangles.AddRange(new int[] { a, b, c });
            break;
        case FaceDirection.BOTH:
            triangles.AddRange(new int[] { c, b, a });
            triangles.AddRange(new int[] { a, b, c });
            break;
    }
}

Now that we have both the components we need, time to apply them to the mesh object.

Mesh mesh = new Mesh();
mesh.vertices = verts;
mesh.triangles = triangles.ToArray();

Once you have the mesh object, you will have to set it to the MeshFilter component on a game object. This can be used in both the Start and Update methods.