//Take the raw part geometry and simplify it so that further simplification of the entire vessel is faster public static PANELFARPartLocalMesh PreProcessLocalMesh(PANELFARPartLocalMesh mesh) { //Array of vertices; indexing must not change Vector3[] verts = new Vector3[mesh.vertexes.Length]; mesh.vertexes.CopyTo(verts, 0); //Array of triangles; each triangle points to an index in verts MeshIndexTriangle[] indexTris = new MeshIndexTriangle[mesh.triangles.Length]; mesh.triangles.CopyTo(indexTris, 0); //Array of a list of triangles that contain a given vertex; indexing is same as verts, each index in list points to an index in indexTris List <int>[] trisAttachedToVerts = GetTrisAttachedToVerts(verts, indexTris); //Array of quadrics associated with a particular vertex; indexing is same as verts Quadric[] vertQuadrics = CalculateVertQuadrics(verts, indexTris); //A list of possible vertex pairs that can be contracted into a single point MinHeap <MeshPairContraction> pairContractions = GeneratePairContractions(indexTris, verts, vertQuadrics); int faces = (int)Math.Floor(indexTris.Length * 0.5); faces = DecimateVertices(faces, ref pairContractions, ref verts, ref indexTris, ref trisAttachedToVerts, ref vertQuadrics); //This will be used to update the old array (which has many empty elements) to a new vertex array and allow the indexTris to be updated as well Dictionary <int, int> beforeIndexAfterIndex = new Dictionary <int, int>(); int currentIndex = 0; List <Vector3> newVerts = new List <Vector3>(); for (int i = 0; i < verts.Length; i++) { Vector3 v = verts[i]; if (trisAttachedToVerts[i] != null) { beforeIndexAfterIndex.Add(i, currentIndex); currentIndex++; newVerts.Add(v); } } MeshIndexTriangle[] newIndexTris = new MeshIndexTriangle[faces]; currentIndex = 0; foreach (MeshIndexTriangle tri in indexTris) { if (tri != null) { MeshIndexTriangle newTri = new MeshIndexTriangle(beforeIndexAfterIndex[tri.v0], beforeIndexAfterIndex[tri.v1], beforeIndexAfterIndex[tri.v2]); newIndexTris[currentIndex] = newTri; currentIndex++; } } mesh.vertexes = newVerts.ToArray(); mesh.triangles = newIndexTris; return(mesh); }
public static PANELFARPartLocalMesh GenerateFromPart(Part p) { PANELFARPartLocalMesh mesh = new PANELFARPartLocalMesh(); Matrix4x4 partUpMatrix = p.transform.worldToLocalMatrix; List <Vector3> vertexList = new List <Vector3>(); List <MeshIndexTriangle> vertexForTriList = new List <MeshIndexTriangle>(); int vertexOffset = 0; foreach (Transform t in p.FindModelComponents <Transform>()) { MeshFilter mf = t.GetComponent <MeshFilter>(); if (mf == null) { continue; } Mesh m = mf.mesh; if (m == null) { continue; } if (p.InternalModelName == m.name) { continue; } Matrix4x4 matrix = partUpMatrix * t.localToWorldMatrix; foreach (Vector3 vertex in m.vertices) { Vector3 v = matrix.MultiplyPoint(vertex); vertexList.Add(v); } for (int i = 0; i < m.triangles.Length; i += 3) { MeshIndexTriangle tri = new MeshIndexTriangle(); tri.v0 = m.triangles[i] + vertexOffset; tri.v1 = m.triangles[i + 1] + vertexOffset; tri.v2 = m.triangles[i + 2] + vertexOffset; vertexForTriList.Add(tri); //Vertex offset since otherwise there will be problems with parts that contain multiple mesh transforms } vertexOffset += m.vertices.Length; } mesh.vertexes = vertexList.ToArray(); mesh.triangles = vertexForTriList.ToArray(); mesh.part = p; mesh = PANELFARMeshSimplification.PreProcessLocalMesh(mesh); return(mesh); }
//This returns an array that contains (in each element) a list of indexes that specify which MeshIndexTriangles (in indexTris) are connected to which Vector3s (in verts) public static List <int>[] GetTrisAttachedToVerts(Vector3[] verts, MeshIndexTriangle[] indexTris) { List <int>[] trisAttachedToVerts = new List <int> [verts.Length]; for (int i = 0; i < trisAttachedToVerts.Length; i++) { trisAttachedToVerts[i] = new List <int>(); } for (int i = 0; i < indexTris.Length; i++) { MeshIndexTriangle tri = indexTris[i]; trisAttachedToVerts[tri.v0].Add(i); trisAttachedToVerts[tri.v1].Add(i); trisAttachedToVerts[tri.v2].Add(i); } return(trisAttachedToVerts); }
public static int DecimateVertices(int targetFaces, ref MinHeap <MeshPairContraction> pairContractions, ref Vector3[] verts, ref MeshIndexTriangle[] indexTris, ref List <int>[] trisAttachedToVerts, ref Quadric[] vertQuadrics) { int validFaces = indexTris.Length; int counter = 1; StringBuilder debug = new StringBuilder(); debug.AppendLine("Target Faces: " + targetFaces); try { while (validFaces > targetFaces) { debug.AppendLine("Iteration: " + counter + " Faces: " + validFaces); //Get the pair contraction with the least error associated with it MeshPairContraction pair = pairContractions.ExtractDominating(); debug.AppendLine("Contraction between vertices at indicies: " + pair.v0 + " and " + pair.v1); debug.AppendLine("Tris attached to v0: " + trisAttachedToVerts[pair.v0].Count + " Tris attached to v1: " + trisAttachedToVerts[pair.v1].Count); //Get faces that will be deleted / changed by contraction ComputeContraction(ref pair, indexTris, trisAttachedToVerts); //Act on faces, delete extra vertex, change all references to second vertex validFaces -= ApplyContraction(ref pair, ref pairContractions, ref verts, ref indexTris, ref trisAttachedToVerts, ref vertQuadrics); counter++; } for (int i = 0; i < indexTris.Length; i++) { MeshIndexTriangle tri = indexTris[i]; if (tri == null) { continue; } if (trisAttachedToVerts[tri.v0] == null) { debug.AppendLine("Tri at index " + i + " points to nonexistent vertex at index " + tri.v0); } if (trisAttachedToVerts[tri.v1] == null) { debug.AppendLine("Tri at index " + i + " points to nonexistent vertex at index " + tri.v1); } if (trisAttachedToVerts[tri.v2] == null) { debug.AppendLine("Tri at index " + i + " points to nonexistent vertex at index " + tri.v2); } } debug.AppendLine("Final: Faces: " + validFaces); } catch (Exception e) { debug.AppendLine("Error: " + e.Message); debug.AppendLine("Stack trace"); debug.AppendLine(e.StackTrace); } Debug.Log(debug.ToString()); return(validFaces); }
public static int ApplyContraction(ref MeshPairContraction pair, ref MinHeap <MeshPairContraction> pairContractions, ref Vector3[] verts, ref MeshIndexTriangle[] indexTris, ref List <int>[] trisAttachedToVerts, ref Quadric[] vertQuadrics) { int removedFaces = pair.deletedFaces.Count; //Move v0, clear v1 verts[pair.v0] = pair.contractedPosition; verts[pair.v1] = Vector3.zero; foreach (int triIndex in trisAttachedToVerts[pair.v1]) { if (!pair.deletedFaces.Contains(triIndex) && !trisAttachedToVerts[pair.v0].Contains(triIndex)) { trisAttachedToVerts[pair.v0].Add(triIndex); } } //Clear out all the tris attached to a non-existent vertex trisAttachedToVerts[pair.v1] = null; //Accumulate quadrics, clear unused one vertQuadrics[pair.v0] += vertQuadrics[pair.v1]; vertQuadrics[pair.v1] = new Quadric(); //Adjust deformed triangles foreach (int changedTri in pair.deformedFaces) { MeshIndexTriangle tri = indexTris[changedTri]; if (tri.v0.Equals(pair.v1)) { tri.v0 = pair.v0; } else if (tri.v1.Equals(pair.v1)) { tri.v1 = pair.v0; } else { tri.v2 = pair.v0; } indexTris[changedTri] = tri; } //Clear deleted triangles foreach (int deletedTri in pair.deletedFaces) { indexTris[deletedTri] = null; } List <MeshPairContraction> pairList = pairContractions.ToList(); for (int i = 0; i < pairContractions.Count; i++) { MeshPairContraction otherPair = pairList[i]; if (otherPair.v0.Equals(pair.v1)) { otherPair.v0 = pair.v0; } else if (otherPair.v1.Equals(pair.v1)) { otherPair.v1 = pair.v0; } pairList[i] = otherPair; } int count = pairList.Count; for (int i = 0; i < count; i++) { MeshPairContraction iItem = pairList[i]; for (int j = i + 1; j < count; j++) { if (pairList[j].Equals(iItem)) { pairList.RemoveAt(j); //Remove duplicate element count--; //Reduce length to iterate over j--; //Make sure not to skip over a duplicate } } if (iItem.v1 == iItem.v0) { pairList.RemoveAt(i); //Remove degenerate edge count--; //Reduce length to iterate over i--; //Make sure not to skip over a duplicate continue; } CalculateTargetPositionForPairContraction(ref iItem, verts, vertQuadrics); pairList[i] = iItem; } pairContractions = new MinHeap <MeshPairContraction>(pairList); return(removedFaces); }
public MeshTriangle(MeshIndexTriangle triangle, MeshVertex[] verts) { tri = triangle; attachedVerts = verts; }
public MeshTriangle(MeshIndexTriangle triangle) : this(triangle, new MeshVertex[3]) { }