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?
Resetting a Mesh
For now, you want to give yourself an easy way to reset your mesh so you can play around without fear. Go back to MeshInspector.cs.
OnInspectorGUI
lets you customize the Inspector for your object with extra GUI elements and logic. In OnInspectorGUI
, find the comment //draw reset button
and replace it with the following:
if (GUILayout.Button("Reset")) //1
{
mesh.Reset(); //2
}
- This code draws a Reset button in the Inspector. The draw function returns
true
when it’s pressed. - When pressed, the button calls
Reset
in MeshStudy.cs.
Save the file and return to MeshStudy.cs. Add the following to Reset
:
if (clonedMesh != null && originalMesh != null) //1
{
clonedMesh.vertices = originalMesh.vertices; //2
clonedMesh.triangles = originalMesh.triangles;
clonedMesh.normals = originalMesh.normals;
clonedMesh.uv = originalMesh.uv;
meshFilter.mesh = clonedMesh; //3
vertices = clonedMesh.vertices; //4
triangles = clonedMesh.triangles;
}
Here’s what this code does step-by-step:
- Checks that both the original mesh and the clone mesh exist, in case the object’s mesh filter doesn’t have any data in it.
- Resets all the properties of
clonedMesh
to those of the original mesh. - Assigns
clonedMesh
back to the Mesh Filter component. - Updates local variables.
Save the file and return to Unity.
In the Inspector, click on the Test Edit button to mess with the cube’s mesh, then press the Reset button to restore it.
Understanding Vertices and Triangles With Unity
As you saw earlier, a mesh consists of vertices connected by edges to form triangles. Triangles define the basic shape of the object.
For example, the group triangles[0], triangles[1], triangles[2]
represents one triangle, the group triangles[3], triangles[4], triangles[5]
represents the next triangle and so on.
So, in a simple Quad mesh that consists of four vertices and two triangles, the Quad’s mesh data would be:
- It stores vertices as an array of
Vector3
. - It stores triangles as an array of integers. Each integer is the index of one of the vertices in the verts array, and each group of three consecutive integers represents one triangle.
Mesh
class keeps track of vertices and triangles with two arrays:
Visualizing Vertices
It will be easier to see how this works if you can draw and move around the vertices on a mesh with handles. Handles are tools for working with objects in the Scene view, like the draggable sphere for the Rotate tool. Now, you’re going to write your own handle!
In MeshInspector.cs, look for EditMesh
and add the following:
handleTransform = mesh.transform; //1
handleRotation = Tools.pivotRotation == PivotRotation.Local ?
handleTransform.rotation : Quaternion.identity; //2
for (int i = 0; i < mesh.vertices.Length; i++) //3
{
ShowPoint(i);
}
- Gets the mesh's transform, which you'll need to know where to draw the vertices in world space.
- Gets the current pivot Rotation mode, to draw the handle the same way as everything else in the scene.
- Loops through the mesh's vertices and draws dots with
ShowPoint
.
In ShowPoint
, replace the //draw dot
comment with:
Vector3 point = handleTransform.TransformPoint(mesh.vertices[index]); //1
Handles.color = Color.blue;
point = Handles.FreeMoveHandle(point, handleRotation, mesh.handleSize,
Vector3.zero, Handles.DotHandleCap); //2
- This line converts the vertex's local position into world space.
- Draws the dot using the
Handles
utility class.
Handles.FreeMoveHandle
makes an unconstrained movement handle, which you will use in the next section to enable dragging the points around.
Save the file and return to Unity.
Check the Cube's MeshInspector and make sure that you've checked Move Vertex Point.
You should now see the vertices of the mesh marked with blue dots on screen. Try attaching the script to other 3D objects and see the results for yourself! :]
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!
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]
.