/// <summary> /// find and isolate independent (not connecting) parts in a mesh /// </summary> public static List <ExploderMesh> IsolateMeshIslands(ExploderMesh mesh) { var triangles = mesh.triangles; var vertexCount = mesh.vertices.Length; // cache mesh data var trianglesNum = mesh.triangles.Length; var tangents = mesh.tangents; var colors = mesh.colors32; var vertices = mesh.vertices; var normals = mesh.normals; var uvs = mesh.uv; var useMeshTangents = tangents != null && tangents.Length > 0; var useVertexColors = colors != null && colors.Length > 0; var useNormals = normals != null && normals.Length > 0; if (trianglesNum <= 3) { return(null); } ExploderUtils.Assert(trianglesNum > 3, "IsolateMeshIslands error: " + trianglesNum); var lsHash = new LSHash(0.1f, vertexCount); var vertHash = new int[trianglesNum]; for (int i = 0; i < trianglesNum; i++) { vertHash[i] = lsHash.Hash(vertices[triangles[i]]); } var islands = new List <HashSet <int> > { new HashSet <int> { vertHash[0], vertHash[1], vertHash[2] } }; var islandsIdx = new List <List <int> > { new List <int>(trianglesNum) { 0, 1, 2 } }; var triVisited = new bool[trianglesNum]; triVisited[0] = true; triVisited[1] = true; triVisited[2] = true; var currIsland = islands[0]; var currIslandIdx = islandsIdx[0]; var counter = 3; var lastInvalidIdx = -1; var loopCounter = 0; while (true) { var foundIsland = false; for (int j = 3; j < trianglesNum; j += 3) { if (triVisited[j]) { continue; } if (currIsland.Contains(vertHash[j]) || currIsland.Contains(vertHash[j + 1]) || currIsland.Contains(vertHash[j + 2])) { currIsland.Add(vertHash[j]); currIsland.Add(vertHash[j + 1]); currIsland.Add(vertHash[j + 2]); currIslandIdx.Add(j); currIslandIdx.Add(j + 1); currIslandIdx.Add(j + 2); triVisited[j] = true; triVisited[j + 1] = true; triVisited[j + 2] = true; counter += 3; foundIsland = true; } else { lastInvalidIdx = j; } } if (counter == trianglesNum) { break; } if (!foundIsland) { // create new island currIsland = new HashSet <int> { vertHash[lastInvalidIdx], vertHash[lastInvalidIdx + 1], vertHash[lastInvalidIdx + 2] }; currIslandIdx = new List <int>(trianglesNum / 2) { lastInvalidIdx, lastInvalidIdx + 1, lastInvalidIdx + 2 }; islands.Add(currIsland); islandsIdx.Add(currIslandIdx); } loopCounter++; if (loopCounter > 100) { ExploderUtils.Log("10000 loop exceeded, islands: " + islands.Count); break; } } var islandNum = islands.Count; ExploderUtils.Assert(islandNum >= 1, "No island found!"); // no more than one islands if (islandNum == 1) { return(null); } var result = new List <ExploderMesh>(islands.Count); foreach (var island in islandsIdx) { var cutterMesh = new ExploderMesh(); var triCount = island.Count; var m = cutterMesh; var tt = new List <int>(triCount); var vs = new List <Vector3>(triCount); var ns = new List <Vector3>(triCount); var us = new List <Vector2>(triCount); var cs = new List <Color32>(triCount); var ts = new List <Vector4>(triCount); var triCache = new Dictionary <int, int>(trianglesNum); var centroid = Vector3.zero; var centroidCounter = 0; var triCounter = 0; foreach (var i in island) { var tri = triangles[i]; var id = 0; if (triCache.TryGetValue(tri, out id)) { tt.Add(id); continue; } tt.Add(triCounter); triCache.Add(tri, triCounter); triCounter++; centroid += vertices[tri]; centroidCounter++; vs.Add(vertices[tri]); us.Add(uvs[tri]); if (useNormals) { ns.Add(normals[tri]); } if (useVertexColors) { cs.Add(colors[tri]); } if (useMeshTangents) { ts.Add(tangents[tri]); } } m.vertices = vs.ToArray(); m.uv = us.ToArray(); if (useNormals) { m.normals = ns.ToArray(); } if (useVertexColors) { m.colors32 = cs.ToArray(); } if (useMeshTangents) { m.tangents = ts.ToArray(); } m.triangles = tt.ToArray(); cutterMesh.centroid = centroid / centroidCounter; result.Add(cutterMesh); } return(result); }
public void AddTriangle(int triangleID, int id0, int id1, Vector3 v0, Vector3 v1) { #if PROFILING MeasureIt.Begin("AddTriangle"); #endif // we need to compute position hash to make sure we find all (duplicated) vertices with different edges int hash0, hash1; lsHash.Hash(v0, v1, out hash0, out hash1); // filter out points with similar positions if (hash0 == hash1) { #if PROFILING MeasureIt.End("AddTriangle"); #endif return; } MidPoint midPoint; if (midPoints.TryGetValue(hash0, out midPoint)) { if (midPoint.idNext == Int32.MaxValue && midPoint.idPrev != hash1) { midPoint.idNext = hash1; } else if (midPoint.idPrev == Int32.MaxValue && midPoint.idNext != hash1) { midPoint.idPrev = hash1; } midPoints[hash0] = midPoint; } else { midPoints.Add(hash0, new MidPoint { id = hash0, vertexId = id0, idNext = hash1, idPrev = Int32.MaxValue /*, position = v0*/ }); } if (midPoints.TryGetValue(hash1, out midPoint)) { if (midPoint.idNext == Int32.MaxValue && midPoint.idPrev != hash0) { midPoint.idNext = hash0; } else if (midPoint.idPrev == Int32.MaxValue && midPoint.idNext != hash0) { midPoint.idPrev = hash0; } midPoints[hash1] = midPoint; } else { midPoints.Add(hash1, new MidPoint { id = hash1, vertexId = id1, idPrev = hash0, idNext = Int32.MaxValue /*, position = v1*/ }); } MidPointsCount = midPoints.Count; #if PROFILING MeasureIt.End("AddTriangle"); #endif }