- Home /
Rebuilding mesh.triangles after removing vertices
I am assembling meshes together and any vertices that were in the same place (actually a lot, because there are a lot of small cylindrical segments) , I wanted to remove them and update the triangles. I naively thought I could do it like this:
var oldVertsA : Vector3[] = myMF.mesh.vertices;
var oldTrianglesA :int[] = myMF.mesh.triangles;
var dupVertsA : List.<int> = new List.<int>();
var uniqueVertsA : List.<Vector3> = oldVertsA.Distinct().ToList();
var tempTrisA : List.<int> = new List.<int>();
for (var q : int = 0; q < oldVertsA.Length; q++)
{
if (!uniqueVertsA.Contains (oldVertsA [q]) )
{
dupVertsA.Add (q);
}
}
for (var p : int = 0; p < oldVertsA.Length; p++)
{
if (dupVertsA.Contains (p) )
{
tempTrisA.Add (uniqueVertsA.IndexOf (oldVertsA [p] ) );
}
else
{
tempTrisA.Add (p);
}
}
myMF.mesh.vertices = uniqueVertsA.ToArray();
myMF.mesh.triangles = tempTrisA.ToArray();
myT.gameObject.SetActive (true);
but it takes a long time, slows the editor to a crawl, messes up the model, and throws "Mesh.triangles is too small" and "Failed setting triangles" errors. So I'm probably doing more than one thing wrong.
Answer by aldonaletto · Nov 14, 2013 at 12:09 PM
That's not so easy: there are several other attributes associated to each vertex, and you can only reduce vertices when all attributes are equal. In Unity, the most popular vertex attributes are uv and normal (almost all shaders need them) - you should thus compare at least the elements of three arrays: vertices, uv and normals. You should also compare them with Unity equality operators: Vector3 an Vector2 comparisons are made by squared distance, what solves the problematic float comparison.
The idea is: iterate through the triangle list and, for each entry, check whether the vertex list already contains a compatible vertex; if so, get its index; if not, add it to the list and get its index; anyway, assign this index to the triangle entry. The code could be something like this (untested!):
// cache the mesh:
var mesh = myMF.mesh;
// get its arrays:
var tris = mesh.triangles;
var verts = mesh.vertices;
var uvs = mesh.uv;
var normals = mesh.normals;
// create the lists:
var newVerts = new List.<Vector3>();
var newUvs = new List.<Vector2>();
var newNormals = new List.<Vector3>();
// iterate through all triangle entries:
for (var i=0; i<tris.Length; i++){
// for each triangle entry...
var t = tris[i];
// get its vertex, uv and normal
var vert = verts[t];
var normal = normals[t];
var uv = uvs[t];
// vertexFound is the compatible vertex index, if any:
var vertexFound = -1;
// check if the vertex is already in the list:
for (var j=0; j<nVert; j++){
// if compatible vertex already in the new list...
if (vert == newVerts[j] && normal == newNormals[j] && uv == newUvs[j]){
vertexFound = j; // get its index...
break; // and stop the loop
}
}
if (vertexFound < 0){ // if no compatible vertex in the list...
// get the index of the next new element...
vertexFound = newVerts.Count;
// then add the vertex and attributes to the list
newVerts.Add(vert); // add new vertex...
newUvs.Add(uv); // and attributes to the list
newNormal.Add(normal);
}
tris[i] = vertexFound; // anyway, update triangle entry...
}
mesh.vertices = newVerts.ToArray();
mesh.uv = newUvs.ToArray();
mesh.normals = newNormals.ToArray();
Notice that there's no need to create a new triangle list: the vertex indexes replace the original ones.
@aldonaletto Can you update script, please? I get this message: $$anonymous$$ identifier: 'nVert'.
List function ToArray takes huge GC alloc if list is long. Is there better way in the terms of GC allocation size?
Your answer
Follow this Question
Related Questions
Mesh extrusion overlapping triangles problem 0 Answers
Problem drawing a mesh with Graphics.DrawMeshNow 1 Answer
Holes in procedural mesh 0 Answers
Highmap on a cube. 0 Answers
How to make sure two meshes have the same vertex count 0 Answers