Beispiel #1
0
        /// <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);
        }
Beispiel #2
0
        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
        }