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.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Runtime Mesh Manipulation With Unity
35 mins
- Getting Started
- Understanding Meshes
- Setting Up the Project
- Poking and Prodding Meshes With a Custom Editor
- Customizing the Editor Script
- Cloning a Mesh
- Resetting a Mesh
- Understanding Vertices and Triangles With Unity
- Visualizing Vertices
- Moving a Single Vertex
- Looking at the Vertices Array
- Finding All Similar Vertices
- Manipulating Meshes
- Collecting the Selected Indices
- Deforming the Sphere Into a Heart Shape
- Making the Vertices Move Smoothly
- Saving Your Mesh in Real Time
- Putting It All Together
- Using the Curve Method
- Where to Go From Here?
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
}
-
GUI.changed
monitors any changes made to the dots, which works nicely withHandles.FreeMoveHandle
to detect a dragging action. - 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 withInverseTransformPoint
.
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
- Updates the target vertex's position.
- Assigns the updated vertices array back to the cloned mesh.
- 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.
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.
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.
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.
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();
- Gets the target vertex position from the
vertices
array. - Finds all the vertices that share the same position as the target vertex and puts their indices into a list.
- Loops through that list and updates the position of all related vertices.
- Assigns the updated
vertices
back toclonedMesh.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.
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.
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.
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
}
- This makes Unity draw the vertices of the mesh as buttons, so you can click on them.
- 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.
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.