Runtime Mesh Manipulation With Unity

One of the benefits of using Unity as your game development platform is its powerful 3D engine. In this tutorial, you’ll get an introduction to the world of 3D objects and mesh manipulation. By Sean Duffy.

4.8 (31) · 2 Reviews

Download materials
Save for later
Share
You are currently viewing page 3 of 5 of this article. Click here to view the first page.

Moving a Single Vertex

You'll start with the most basic kind of mesh manipulation: Moving a single vertex.

Open MeshInspector.cs. Inside ShowPoint, replace the //drag comment with the following:

if (GUI.changed) //3
{
    mesh.DoAction(index, handleTransform.InverseTransformPoint(point)); //4
}
  1. GUI.changed monitors any changes made to the dots, which works nicely with Handles.FreeMoveHandle to detect a dragging action.
  2. On dragging a vertex, call mesh.DoAction with the index of the vertex and the vertex's position as parameters. This line also converts the vertex's position back to local space with InverseTransformPoint.

Save MeshInspector.cs and go to MeshStudy.cs. Add the following in DoAction:

PullOneVertex(index, localPos);

Then add the following to PullOneVertex:

vertices[index] = newPos; //1
clonedMesh.vertices = vertices; //2
clonedMesh.RecalculateNormals(); //3
  1. Updates the target vertex's position.
  2. Assigns the updated vertices array back to the cloned mesh.
  3. Tells Unity to re-draw the mesh to reflect the change.

Save the script and return to Unity. Try dragging one of the dots on the cube.

SScreenshot showing how the cube looks when you've dragged the dots.

It seems like some of the vertices share the same position, so when you pull only one, the other vertices stay behind and your mesh breaks. You'll learn how to fix this problem shortly. :]

Looking at the Vertices Array

Visually, a cube mesh consists of eight vertices, six sides and 12 triangles. Time to see if Unity agrees.

Visual depiction of a cube mesh.

Go to MeshStudy.cs, and before Start, look for a variable named vertices. You'll see that it has the [HideInInspector] attribute.

Temporarily comment out that attribute for a quick peek into the array:

//[HideInInspector]
public Vector3[] vertices;

Note: More complicated 3D meshes can have thousands of vertices. Unity will freeze up if it tries to show all those values in the Inspector, so in general, you'll hide the array with [HideInInspector]. You're just peeking!

Note: More complicated 3D meshes can have thousands of vertices. Unity will freeze up if it tries to show all those values in the Inspector, so in general, you'll hide the array with [HideInInspector]. You're just peeking!

Save the file, return to Unity and look at your cube. You can now see the vertices property on Mesh Study. Click on the arrow icon beside it to show the array of Vector3 elements.

Screenshot of the vertices property on Mesh Study.

You can see that the array size is 24, which means that there are definitely vertices sharing the same position! Take a moment and think about why there might be multiple vertices in the same place.

[spoiler title = "Why 24 Vertices?"]
The simplest answer is:
A cube has six sides and each side has four vertices that form a plane. 6 × 4 = 24 vertices.

There are other ways to think about this, if this is hard to grasp. But for now, just know that some meshes will have vertices that share the same position.


[/spoiler]

Since you're done peeking into the verts array, go ahead and uncomment [HideInInspector].

Finding All Similar Vertices

You can see that manipulating a mesh is going to take more than just moving single vertices — you have to move all the vertices for a particular point in space in order to keep the mesh together. So you're now ready to unbreak your heart, er, mesh.

In MeshStudy.cs, replace all the code inside DoAction with:

PullSimilarVertices(index, localPos);

Go to PullSimilarVertices and add the following:

Vector3 targetVertexPos = vertices[index]; //1
List<int> relatedVertices = FindRelatedVertices(targetVertexPos, false); //2
foreach (int i in relatedVertices) //3
{
    vertices[i] = newPos;
}
clonedMesh.vertices = vertices; //4
clonedMesh.RecalculateNormals();
  1. Gets the target vertex position from the vertices array.
  2. Finds all the vertices that share the same position as the target vertex and puts their indices into a list.
  3. Loops through that list and updates the position of all related vertices.
  4. Assigns the updated vertices back to clonedMesh.vertices, then redraws the mesh.

Save the file and return to Unity. Click and drag any of the vertices; the mesh should now retain its form without breaking.

Gif of a Cube mesh that retains its form without breaking.

Save the scene. You've taken the first step towards being a mesh magician!

Manipulating Meshes

Editing meshes in Unity is fun, but what if you could add some "squish" to your game by deforming meshes at runtime? Next, you'll try that out in its most basic form — pushing and pulling some predefined vertices.

No math...

No math...

Collecting the Selected Indices

You'll start by making a custom editor that lets you select the vertices to move around in real time. Open up the 02 Create Heart Mesh scene inside RW/Scenes. You'll see a red sphere in the Scene view.

Screenshot of the red sphere that you'll transform into a heart.

Select the Sphere in the Hierarchy and look at the Heart Mesh component. This is the script that will store the verts you select.

But right now, there aren't any verts shown in the scene. So next, you're going to fix that!

Open RW/Editor/HeartMeshInspector.cs. In ShowHandle, inside the if statement, add the following code:

Handles.color = Color.blue;
if (Handles.Button(point, handleRotation, mesh.pickSize, mesh.pickSize, 
    Handles.DotHandleCap)) //1
{
    mesh.selectedIndices.Add(index); //2
}
  1. This makes Unity draw the vertices of the mesh as buttons, so you can click on them.
  2. When you click the button, it adds the selected index to the mesh.selectedIndices list.

Add the following code at the end of OnInspectorGUI, after the existing if statement:

if (GUILayout.Button("Clear Selected Vertices"))
{
    mesh.ClearAllData();
}

This adds a custom Reset button in the Inspector. Next, you'll write the code to clear out your selection.

Save the file and open RW/Scripts/HeartMesh.cs. In ClearAllData, add the following:

selectedIndices = new List<int>();
targetIndex = 0;
targetVertex = Vector3.zero;

This clears the values in the selectedIndices list and sets targetIndex to zero. It also resets the targetVertex position.

Save the file and return to Unity. Select the Sphere and look at its HeartMesh component. Make sure you've checked Is Edit Mode so you can see the mesh's vertices in the Scene view. Then click on the arrow icon next to Selected Indices to show the array.

Click on a few blue dots and watch new entries appear in Selected Indices. Try out your Clear Selected Vertices button to make sure it clears all values correctly.

Gif showing how Selected Indices works.

Note: You have the option to show/hide the transform handle with Show Transform Handle in the custom Inspector, since it can get in the way of selecting verts. Just remember not to panic when you find the Transform handle missing from your other scenes! Be sure to switch it back on before you exit.

Note: You have the option to show/hide the transform handle with Show Transform Handle in the custom Inspector, since it can get in the way of selecting verts. Just remember not to panic when you find the Transform handle missing from your other scenes! Be sure to switch it back on before you exit.