Ejemplo n.º 1
0
        public int Hash(Vector3 p)
        {
            for (int i = 0; i < count; i++)
            {
                var item = buckets[i];

                float diffX  = p.x - item.x;
                float diffY  = p.y - item.y;
                float diffZ  = p.z - item.z;
                float sqrMag = diffX * diffX + diffY * diffY + diffZ * diffZ;

                if (sqrMag < bucketSize2)
                {
                    return(i);
                }
            }

            if (count >= buckets.Length)
            {
                ExploderUtils.Log("Hash out of range: " + count + " " + buckets.Length);
                return(count - 1);
            }

            buckets[count++] = p;
            return(count - 1);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Compute intersection between a segment line (a, b) and a plane (p)
        /// from Real-Time Collision Detection Book by Christer Ericson
        /// </summary>
        /// <param name="a">first point of a segment</param>
        /// <param name="b">second point of a segment</param>
        /// <param name="t">normalized distance of intersection point on vector (ab)</param>
        /// <param name="q">point in intersection</param>
        /// <returns>true if there is an intersection</returns>
        public bool IntersectSegment(Vector3 a, Vector3 b, out float t, ref Vector3 q)
        {
            var abx = b.x - a.x;
            var aby = b.y - a.y;
            var abz = b.z - a.z;

            var dot0 = Normal.x * a.x + Normal.y * a.y + Normal.z * a.z;
            var dot1 = Normal.x * abx + Normal.y * aby + Normal.z * abz;

            t = (Distance - dot0) / dot1;

            if (t >= 0.0f - epsylon && t <= 1.0f + epsylon)
            {
                q.x = a.x + t * abx;
                q.y = a.y + t * aby;
                q.z = a.z + t * abz;

                return(true);
            }

            ExploderUtils.Log("IntersectSegment failed: " + t);
            q = Vector3.zero;
            return(false);
        }
Ejemplo n.º 3
0
        float Cut(ExploderMesh mesh, ExploderTransform meshTransform, Plane plane, bool triangulateHoles, bool allowOpenMesh, ref List <ExploderMesh> meshes)
        {
            var stopWatch = new Stopwatch();

            stopWatch.Start();

#if PROFILING
            MeasureIt.Begin("CutAllocations");
#endif

            // cache mesh data
            var trianglesNum    = mesh.triangles.Length;
            var verticesNum     = mesh.vertices.Length;
            var meshTriangles   = mesh.triangles;
            var meshTangents    = mesh.tangents;
            var meshColors      = mesh.colors32;
            var meshVertices    = mesh.vertices;
            var meshNormals     = mesh.normals;
            var meshUV          = mesh.uv;
            var useMeshTangents = meshTangents != null && meshTangents.Length > 0;
            var useVertexColors = meshColors != null && meshColors.Length > 0;
            var useNormals      = meshNormals != null && meshNormals.Length > 0;

            // preallocate buffers
            AllocateBuffers(trianglesNum, verticesNum, useMeshTangents, useVertexColors);

            ExploderMesh mesh0, mesh1;

#if PROFILING
            MeasureIt.End("CutAllocations");
            MeasureIt.Begin("CutCycleFirstPass");
#endif

            // first pass - find complete triangles on both sides of the plane
            for (int i = 0; i < trianglesNum; i += 3)
            {
                // get triangle points
                var v0 = meshVertices[meshTriangles[i]];
                var v1 = meshVertices[meshTriangles[i + 1]];
                var v2 = meshVertices[meshTriangles[i + 2]];

                var side0 = plane.GetSideFix(ref v0);
                var side1 = plane.GetSideFix(ref v1);
                var side2 = plane.GetSideFix(ref v2);

                meshVertices[meshTriangles[i]]     = v0;
                meshVertices[meshTriangles[i + 1]] = v1;
                meshVertices[meshTriangles[i + 2]] = v2;

//                Utils.Log(plane.Pnt + " " + v0 + " " + v1 + " " + " " + v2);

                // all points on one side
                if (side0 == side1 && side1 == side2)
                {
                    var idx = side0 ? 0 : 1;

                    if (meshTriangles[i] >= triCache.Length)
                    {
                        ExploderUtils.Log("TriCacheError " + meshTriangles[i] + " " + triCache.Length + " " + meshVertices.Length);
                    }

                    if (triCache[meshTriangles[i]] == 0)
                    {
                        triangles[idx].Add(triCounter[idx]);
                        vertices[idx].Add(meshVertices[meshTriangles[i]]);
                        uvs[idx].Add(meshUV[meshTriangles[i]]);

                        if (useNormals)
                        {
                            normals[idx].Add(meshNormals[meshTriangles[i]]);
                        }

                        if (useMeshTangents)
                        {
                            tangents[idx].Add(meshTangents[meshTriangles[i]]);
                        }

                        if (useVertexColors)
                        {
                            vertexColors[idx].Add(meshColors[meshTriangles[i]]);
                        }

                        centroid[idx] += meshVertices[meshTriangles[i]];

                        triCache[meshTriangles[i]] = triCounter[idx] + 1;
                        triCounter[idx]++;
                    }
                    else
                    {
                        triangles[idx].Add(triCache[meshTriangles[i]] - 1);
                    }

                    if (triCache[meshTriangles[i + 1]] == 0)
                    {
                        triangles[idx].Add(triCounter[idx]);
                        vertices[idx].Add(meshVertices[meshTriangles[i + 1]]);
                        uvs[idx].Add(meshUV[meshTriangles[i + 1]]);

                        if (useNormals)
                        {
                            normals[idx].Add(meshNormals[meshTriangles[i + 1]]);
                        }

                        if (useMeshTangents)
                        {
                            tangents[idx].Add(meshTangents[meshTriangles[i + 1]]);
                        }

                        if (useVertexColors)
                        {
                            vertexColors[idx].Add(meshColors[meshTriangles[i + 1]]);
                        }

                        centroid[idx] += meshVertices[meshTriangles[i + 1]];

                        triCache[meshTriangles[i + 1]] = triCounter[idx] + 1;
                        triCounter[idx]++;
                    }
                    else
                    {
                        triangles[idx].Add(triCache[meshTriangles[i + 1]] - 1);
                    }

                    if (triCache[meshTriangles[i + 2]] == 0)
                    {
                        triangles[idx].Add(triCounter[idx]);
                        vertices[idx].Add(meshVertices[meshTriangles[i + 2]]);
                        uvs[idx].Add(meshUV[meshTriangles[i + 2]]);

                        if (useNormals)
                        {
                            normals[idx].Add(meshNormals[meshTriangles[i + 2]]);
                        }

                        if (useMeshTangents)
                        {
                            tangents[idx].Add(meshTangents[meshTriangles[i + 2]]);
                        }

                        if (useVertexColors)
                        {
                            vertexColors[idx].Add(meshColors[meshTriangles[i + 2]]);
                        }

                        centroid[idx] += meshVertices[meshTriangles[i + 2]];

                        triCache[meshTriangles[i + 2]] = triCounter[idx] + 1;
                        triCounter[idx]++;
                    }
                    else
                    {
                        triangles[idx].Add(triCache[meshTriangles[i + 2]] - 1);
                    }
                }
                else
                {
                    // intersection triangles add to list and process it in second pass
                    cutTris.Add(i);
                }
            }

            if (vertices[0].Count == 0)
            {
                centroid[0] = meshVertices[0];
            }
            else
            {
                centroid[0] /= vertices[0].Count;
            }

            if (vertices[1].Count == 0)
            {
                centroid[1] = meshVertices[1];
            }
            else
            {
                centroid[1] /= vertices[1].Count;
            }

//            UnityEngine.Debug.LogFormat("cut: {0} -- {1}, normal: {2}, tris: {3}", vertices[0].Count, vertices[1].Count, plane.Normal, cutTris.Count);

#if PROFILING
            MeasureIt.End("CutCycleFirstPass");
            MeasureIt.Begin("CutCycleSecondPass");
#endif

            if (cutTris.Count < 1)
            {
                stopWatch.Stop();
                return(stopWatch.ElapsedMilliseconds);
            }

            AllocateContours(cutTris.Count);

            // second pass - cut intersecting triangles in half
            foreach (var cutTri in cutTris)
            {
                var triangle = new Triangle
                {
                    ids      = new[] { meshTriangles[cutTri + 0], meshTriangles[cutTri + 1], meshTriangles[cutTri + 2] },
                    pos      = new[] { meshVertices[meshTriangles[cutTri + 0]], meshVertices[meshTriangles[cutTri + 1]], meshVertices[meshTriangles[cutTri + 2]] },
                    normal   = useNormals ? new[] { meshNormals[meshTriangles[cutTri + 0]], meshNormals[meshTriangles[cutTri + 1]], meshNormals[meshTriangles[cutTri + 2]] } : new[] { Vector3.zero, Vector3.zero, Vector3.zero },
                    uvs      = new[] { meshUV[meshTriangles[cutTri + 0]], meshUV[meshTriangles[cutTri + 1]], meshUV[meshTriangles[cutTri + 2]] },
                    tangents = useMeshTangents ? new[] { meshTangents[meshTriangles[cutTri + 0]], meshTangents[meshTriangles[cutTri + 1]], meshTangents[meshTriangles[cutTri + 2]] } : new [] { Vector4.zero, Vector4.zero, Vector4.zero },
                    colors   = useVertexColors ? new[] { meshColors[meshTriangles[cutTri + 0]], meshColors[meshTriangles[cutTri + 1]], meshColors[meshTriangles[cutTri + 2]] } : new Color32[] { Color.white, Color.white, Color.white },
                };

                // check points with a plane
                var side0 = plane.GetSide(triangle.pos[0]);
                var side1 = plane.GetSide(triangle.pos[1]);
                var side2 = plane.GetSide(triangle.pos[2]);

                float   t0, t1;
                Vector3 s0 = Vector3.zero, s1 = Vector3.zero;

                var idxLeft  = side0 ? 0 : 1;
                var idxRight = 1 - idxLeft;

                if (side0 == side1)
                {
                    var a = plane.IntersectSegment(triangle.pos[2], triangle.pos[0], out t0, ref s0);
                    var b = plane.IntersectSegment(triangle.pos[2], triangle.pos[1], out t1, ref s1);

                    ExploderUtils.Assert(a && b, "!!!!!!!!!!!!!!!");

                    // left side ... 2 triangles
                    var s0Left = AddIntersectionPoint(s0, triangle, triangle.ids[2], triangle.ids[0], cutVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals);
                    var s1Left = AddIntersectionPoint(s1, triangle, triangle.ids[2], triangle.ids[1], cutVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals);
                    var v0Left = AddTrianglePoint(triangle.pos[0], triangle.normal[0], triangle.uvs[0], triangle.tangents[0], triangle.colors[0], triangle.ids[0], triCache, cornerVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals);
                    var v1Left = AddTrianglePoint(triangle.pos[1], triangle.normal[1], triangle.uvs[1], triangle.tangents[1], triangle.colors[1], triangle.ids[1], triCache, cornerVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals);

                    // Triangle (s0, v0, s1)
                    triangles[idxLeft].Add(s0Left);
                    triangles[idxLeft].Add(v0Left);
                    triangles[idxLeft].Add(s1Left);

                    // Triangle (s1, v0, v1)
                    triangles[idxLeft].Add(s1Left);
                    triangles[idxLeft].Add(v0Left);
                    triangles[idxLeft].Add(v1Left);

                    // right side ... 1 triangle
                    var s0Right = AddIntersectionPoint(s0, triangle, triangle.ids[2], triangle.ids[0], cutVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals);
                    var s1Right = AddIntersectionPoint(s1, triangle, triangle.ids[2], triangle.ids[1], cutVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals);
                    var v2Right = AddTrianglePoint(triangle.pos[2], triangle.normal[2], triangle.uvs[2], triangle.tangents[2], triangle.colors[2], triangle.ids[2], triCache, cornerVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals);

                    // Triangle (v2, s0, s1)
                    triangles[idxRight].Add(v2Right);
                    triangles[idxRight].Add(s0Right);
                    triangles[idxRight].Add(s1Right);

                    // buffer intersection vertices for triangulation
                    if (triangulateHoles)
                    {
                        if (idxLeft == 0)
                        {
                            contour.AddTriangle(cutTri, s0Left, s1Left, s0, s1);
                        }
                        else
                        {
                            contour.AddTriangle(cutTri, s0Right, s1Right, s0, s1);
                        }
                    }
                }
                else if (side0 == side2)
                {
                    var a = plane.IntersectSegment(triangle.pos[1], triangle.pos[0], out t0, ref s1);
                    var b = plane.IntersectSegment(triangle.pos[1], triangle.pos[2], out t1, ref s0);

                    ExploderUtils.Assert(a && b, "!!!!!!!!!!!!!");

                    // left side ... 2 triangles
                    var s0Left = AddIntersectionPoint(s0, triangle, triangle.ids[1], triangle.ids[2], cutVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals);
                    var s1Left = AddIntersectionPoint(s1, triangle, triangle.ids[1], triangle.ids[0], cutVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals);
                    var v0Left = AddTrianglePoint(triangle.pos[0], triangle.normal[0], triangle.uvs[0], triangle.tangents[0], triangle.colors[0], triangle.ids[0], triCache, cornerVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals);
                    var v2Left = AddTrianglePoint(triangle.pos[2], triangle.normal[2], triangle.uvs[2], triangle.tangents[2], triangle.colors[2], triangle.ids[2], triCache, cornerVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals);

                    // Triangle (v2, s1, s0)
                    triangles[idxLeft].Add(v2Left);
                    triangles[idxLeft].Add(s1Left);
                    triangles[idxLeft].Add(s0Left);

                    // Triangle (v2, v0, s1)
                    triangles[idxLeft].Add(v2Left);
                    triangles[idxLeft].Add(v0Left);
                    triangles[idxLeft].Add(s1Left);

                    // right side ... 1 triangle
                    var s0Right = AddIntersectionPoint(s0, triangle, triangle.ids[1], triangle.ids[2], cutVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals);
                    var s1Right = AddIntersectionPoint(s1, triangle, triangle.ids[1], triangle.ids[0], cutVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals);
                    var v1Right = AddTrianglePoint(triangle.pos[1], triangle.normal[1], triangle.uvs[1], triangle.tangents[1], triangle.colors[1], triangle.ids[1], triCache, cornerVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals);

                    // Triangle (s0, s1, v1)
                    triangles[idxRight].Add(s0Right);
                    triangles[idxRight].Add(s1Right);
                    triangles[idxRight].Add(v1Right);

                    // buffer intersection vertices for triangulation
                    if (triangulateHoles)
                    {
                        if (idxLeft == 0)
                        {
                            contour.AddTriangle(cutTri, s0Left, s1Left, s0, s1);
                        }
                        else
                        {
                            contour.AddTriangle(cutTri, s0Right, s1Right, s0, s1);
                        }
                    }
                }
                else
                {
                    var a = plane.IntersectSegment(triangle.pos[0], triangle.pos[1], out t0, ref s0);
                    var b = plane.IntersectSegment(triangle.pos[0], triangle.pos[2], out t1, ref s1);

                    ExploderUtils.Assert(a && b, "!!!!!!!!!!!!!");

                    // right side ... 2 triangles
                    var s0Right = AddIntersectionPoint(s0, triangle, triangle.ids[0], triangle.ids[1], cutVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals);
                    var s1Right = AddIntersectionPoint(s1, triangle, triangle.ids[0], triangle.ids[2], cutVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals);
                    var v1Right = AddTrianglePoint(triangle.pos[1], triangle.normal[1], triangle.uvs[1], triangle.tangents[1], triangle.colors[1], triangle.ids[1], triCache, cornerVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals);
                    var v2Right = AddTrianglePoint(triangle.pos[2], triangle.normal[2], triangle.uvs[2], triangle.tangents[2], triangle.colors[2], triangle.ids[2], triCache, cornerVertCache[idxRight], vertices[idxRight], normals[idxRight], uvs[idxRight], tangents[idxRight], vertexColors[idxRight], useMeshTangents, useVertexColors, useNormals);

                    // Triangle (v2, s1, v1)
                    triangles[idxRight].Add(v2Right);
                    triangles[idxRight].Add(s1Right);
                    triangles[idxRight].Add(v1Right);

                    // Triangle (s1, s0, v1)
                    triangles[idxRight].Add(s1Right);
                    triangles[idxRight].Add(s0Right);
                    triangles[idxRight].Add(v1Right);

                    // left side ... 1 triangle
                    var s0Left = AddIntersectionPoint(s0, triangle, triangle.ids[0], triangle.ids[1], cutVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals);
                    var s1Left = AddIntersectionPoint(s1, triangle, triangle.ids[0], triangle.ids[2], cutVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals);
                    var v0Left = AddTrianglePoint(triangle.pos[0], triangle.normal[0], triangle.uvs[0], triangle.tangents[0], triangle.colors[0], triangle.ids[0], triCache, cornerVertCache[idxLeft], vertices[idxLeft], normals[idxLeft], uvs[idxLeft], tangents[idxLeft], vertexColors[idxLeft], useMeshTangents, useVertexColors, useNormals);

                    // Triangle (s1, v0, s0)
                    triangles[idxLeft].Add(s1Left);
                    triangles[idxLeft].Add(v0Left);
                    triangles[idxLeft].Add(s0Left);

                    // buffer intersection vertices for triangulation
                    if (triangulateHoles)
                    {
                        if (idxLeft == 0)
                        {
                            contour.AddTriangle(cutTri, s0Left, s1Left, s0, s1);
                        }
                        else
                        {
                            contour.AddTriangle(cutTri, s0Right, s1Right, s0, s1);
                        }
                    }
                }
            }

#if PROFILING
            MeasureIt.End("CutCycleSecondPass");
#endif

            if (triangulateHoles)
            {
#if PROFILING
                MeasureIt.Begin("FindContours");
#endif

                contour.FindContours();

                if (contour.contour.Count == 0 || contour.contour[0].Count < 3)
                {
//                    triangulateHoles = false;

                    if (allowOpenMesh)
                    {
                        triangulateHoles = false;
                    }
                    else
                    {
                        stopWatch.Stop();
                        return(stopWatch.ElapsedMilliseconds);
                    }
                }

#if PROFILING
                MeasureIt.End("FindContours");
#endif
            }

            List <int>[] trianglesCut = null;
            var          centroid0    = Vector3.zero;
            var          centroid1    = Vector3.zero;
            var          min0         = Vector3.zero;
            var          max0         = Vector3.zero;
            var          min1         = Vector3.zero;
            var          max1         = Vector3.zero;

            ExploderMesh.CalculateCentroid(vertices[0], ref centroid0, ref min0, ref max0);
            ExploderMesh.CalculateCentroid(vertices[1], ref centroid1, ref min1, ref max1);

            if (triangulateHoles)
            {
#if PROFILING
                MeasureIt.Begin("Triangulate");
#endif

                trianglesCut = new List <int>[2]
                {
                    new List <int>(contour.MidPointsCount),
                    new List <int>(contour.MidPointsCount)
                };

                Triangulate(contour.contour, plane, vertices, normals, uvs, tangents, vertexColors, trianglesCut, true, useMeshTangents, useVertexColors, useNormals);

#if PROFILING
                MeasureIt.End("Triangulate");
#endif
            }

            if (vertices[0].Count > 3 && vertices[1].Count > 3)
            {
#if PROFILING
                MeasureIt.Begin("CutEndCopyBack");
#endif

                mesh0 = new ExploderMesh();
                mesh1 = new ExploderMesh();

                var verticesArray0 = vertices[0].ToArray();
                var verticesArray1 = vertices[1].ToArray();

                mesh0.vertices = verticesArray0;
                mesh0.uv       = uvs[0].ToArray();

                mesh1.vertices = verticesArray1;
                mesh1.uv       = uvs[1].ToArray();

                if (useNormals)
                {
                    mesh0.normals = normals[0].ToArray();
                    mesh1.normals = normals[1].ToArray();
                }

                if (useMeshTangents)
                {
                    mesh0.tangents = tangents[0].ToArray();
                    mesh1.tangents = tangents[1].ToArray();
                }

                if (useVertexColors)
                {
                    mesh0.colors32 = vertexColors[0].ToArray();
                    mesh1.colors32 = vertexColors[1].ToArray();
                }

                if (trianglesCut != null && trianglesCut[0].Count > 3)
                {
                    triangles[0].AddRange(trianglesCut[0]);
                    triangles[1].AddRange(trianglesCut[1]);
                }

                mesh0.triangles = triangles[0].ToArray();
                mesh1.triangles = triangles[1].ToArray();

                mesh0.centroid = centroid0;
                mesh0.min      = min0;
                mesh0.max      = max0;

                mesh1.centroid = centroid1;
                mesh1.min      = min1;
                mesh1.max      = max1;

#if PROFILING
                MeasureIt.End("CutEndCopyBack");
#endif

                meshes = new List <ExploderMesh> {
                    mesh0, mesh1
                };

                stopWatch.Stop();
                return(stopWatch.ElapsedMilliseconds);
            }

            stopWatch.Stop();

//            UnityEngine.Debug.Log("Empty cut! " + vertices[0].Count + " " + vertices[1].Count);

            return(stopWatch.ElapsedMilliseconds);
        }
Ejemplo n.º 4
0
        private void Cut()
        {
            bool cutting      = true;
            var  cycleCounter = 0;

            cutAttempt = 0;

            while (cutting)
            {
                cycleCounter++;

                if (cycleCounter > core.parameters.TargetFragments)
                {
                    ExploderUtils.Log("Explode Infinite loop!");
                    break;
                }

                newFragments.Clear();
                meshToRemove.Clear();

                cutting = false;

                foreach (var mesh in meshSet)
                {
                    if (core.targetFragments[mesh.id] > 1)
                    {
                        var plane = cuttingPlane.GetPlane(mesh.mesh, cutAttempt);

                        var triangulateHoles         = true;
                        var crossSectionVertexColour = Color.white;
                        var crossSectionUV           = new Vector4(0, 0, 1, 1);

                        if (mesh.option)
                        {
                            triangulateHoles         = !mesh.option.Plane2D;
                            crossSectionVertexColour = mesh.option.CrossSectionVertexColor;
                            crossSectionUV           = mesh.option.CrossSectionUV;
                            core.splitMeshIslands   |= mesh.option.SplitMeshIslands;
                        }

                        if (core.parameters.Use2DCollision)
                        {
                            triangulateHoles = false;
                        }

                        List <ExploderMesh> meshes = null;
                        cutter.Cut(mesh.mesh, mesh.transform, plane, triangulateHoles, core.parameters.DisableTriangulation, ref meshes, crossSectionVertexColour, crossSectionUV);

                        cutting = true;

                        if (meshes != null)
                        {
                            foreach (var cutterMesh in meshes)
                            {
                                newFragments.Add(new MeshObject
                                {
                                    mesh = cutterMesh,

                                    material        = mesh.material,
                                    transform       = mesh.transform,
                                    id              = mesh.id,
                                    original        = mesh.original,
                                    skinnedOriginal = mesh.skinnedOriginal,
                                    bakeObject      = mesh.bakeObject,

                                    parent     = mesh.transform.parent,
                                    position   = mesh.transform.position,
                                    rotation   = mesh.transform.rotation,
                                    localScale = mesh.transform.localScale,

                                    option = mesh.option,
                                });
                            }

                            meshToRemove.Add(mesh);
                            core.targetFragments[mesh.id] -= 1;
                        }
                        else
                        {
                            cutAttempt++;
                        }
                    }
                }

                meshSet.ExceptWith(meshToRemove);
                meshSet.UnionWith(newFragments);
            }
        }
Ejemplo n.º 5
0
        public override bool Run(float frameBudget)
        {
            var count = core.pool.Count;

            while (core.poolIdx < count)
            {
                var fragment = core.pool[core.poolIdx];
                var mesh     = core.postList[core.poolIdx];

                core.poolIdx++;

                if (!mesh.original)
                {
                    continue;
                }

                var unityMesh = mesh.mesh.ToUnityMesh();

                fragment.meshFilter.sharedMesh = unityMesh;

                // choose proper material

                if (mesh.option && mesh.option.FragmentMaterial)
                {
                    fragment.meshRenderer.sharedMaterial = mesh.option.FragmentMaterial;
                }
                else
                {
                    if (core.parameters.FragmentOptions.FragmentMaterial != null)
                    {
                        fragment.meshRenderer.sharedMaterial = core.parameters.FragmentOptions.FragmentMaterial;
                    }
                    else
                    {
                        fragment.meshRenderer.sharedMaterial = mesh.material;
                    }
                }

                unityMesh.RecalculateBounds();

                var oldParent = fragment.transform.parent;
                fragment.transform.parent     = mesh.parent;
                fragment.transform.position   = mesh.position;
                fragment.transform.rotation   = mesh.rotation;
                fragment.transform.localScale = mesh.localScale;
                fragment.transform.parent     = null;
                fragment.transform.parent     = oldParent;

                if (core.parameters.PartialExplosion)
                {
                }
                else
                {
                    if (mesh.original != core.parameters.ExploderGameObject)
                    {
                        ExploderUtils.SetActiveRecursively(mesh.original, false);
                    }
                    else
                    {
                        ExploderUtils.EnableCollider(mesh.original, false);
                        ExploderUtils.SetVisible(mesh.original, false);
                    }

                    if (mesh.skinnedOriginal && mesh.skinnedOriginal != core.parameters.ExploderGameObject)
                    {
                        ExploderUtils.SetActiveRecursively(mesh.skinnedOriginal, false);
                    }
                    else
                    {
                        ExploderUtils.EnableCollider(mesh.skinnedOriginal, false);
                        ExploderUtils.SetVisible(mesh.skinnedOriginal, false);
                    }

                    if (mesh.skinnedOriginal && mesh.bakeObject)
                    {
                        GameObject.DestroyObject(mesh.bakeObject, 1);
                    }
                }

                var plane = mesh.option && mesh.option.Plane2D;

                var use2d = core.parameters.Use2DCollision;

                if (!core.parameters.FragmentOptions.DisableColliders)
                {
                    if (core.parameters.MeshColliders && !use2d)
                    {
                        // dont use mesh colliders for 2d plane
                        if (!plane)
                        {
                            fragment.meshCollider.sharedMesh = unityMesh;
                        }
                    }
                    else
                    {
                        if (core.parameters.Use2DCollision)
                        {
                            MeshUtils.GeneratePolygonCollider(fragment.polygonCollider2D, unityMesh);
                        }
                        else
                        {
                            fragment.boxCollider.center = unityMesh.bounds.center;
                            fragment.boxCollider.size   = unityMesh.bounds.extents;
                        }
                    }
                }

                if (mesh.option)
                {
                    mesh.option.DuplicateSettings(fragment.options);
                }

                fragment.Explode();

                var force = core.parameters.Force;
                if (mesh.option && mesh.option.UseLocalForce)
                {
                    force = mesh.option.Force;
                }

                // apply force to rigid body
                fragment.ApplyExplosion(mesh.transform, mesh.mesh.centroid, core.parameters.Position, core.parameters.FragmentOptions, core.parameters.UseForceVector,
                                        core.parameters.ForceVector, force, mesh.original, core.parameters.TargetFragments);

#if SHOW_DEBUG_LINES
                UnityEngine.Debug.DrawLine(settings.Position, forceVector * settings.Force, Color.yellow, 3);
#endif

                if (Watch.ElapsedMilliseconds > frameBudget)
                {
                    return(false);
                }
            }

            if (core.parameters.DestroyOriginalObject)
            {
                foreach (var mesh in core.postList)
                {
                    if (mesh.original && !mesh.original.GetComponent <Fragment>())
                    {
                        Object.Destroy(mesh.original);
                    }

                    if (mesh.skinnedOriginal)
                    {
                        Object.Destroy(mesh.skinnedOriginal);
                    }
                }
            }

            if (core.parameters.ExplodeSelf)
            {
                if (!core.parameters.DestroyOriginalObject)
                {
                    ExploderUtils.SetActiveRecursively(core.parameters.ExploderGameObject, false);
                }
            }

            if (core.parameters.HideSelf)
            {
                ExploderUtils.SetActiveRecursively(core.parameters.ExploderGameObject, false);
            }

#if DBG
            ExploderUtils.Log("Explosion finished! " + postList.Count + postList[0].original.transform.gameObject.name);
#endif
//            core.exploder.OnExplosionFinished(true);

            Watch.Stop();

            return(true);
        }
Ejemplo n.º 6
0
        protected override bool Cut(float frameBudget)
        {
            if (cutInitialized)
            {
                return(true);
            }

            localWatch.Start();

            cutInitialized = true;

            //
            // thread_max = <2, 4>
            //
            Debug.Assert(THREAD_MAX > 1, "At least one worker is required!");

            if (core.parameters.TargetFragments < 2 ||
                core.meshSet.Count == core.parameters.TargetFragments)
            {
                return(true);
            }

            //
            // cut object if necessary
            //
            var cuts = THREAD_MAX - 1 - core.meshSet.Count;

//            Debug.AssertFormat(cuts <= 2, "Invalid number of cuts: {0}", cuts);
//            var cutsTotal = cuts;

            if (cuts > core.parameters.TargetFragments - 1)
            {
                cuts = core.parameters.TargetFragments - 1;
            }

            var cycleCounter = 0;

            idCounter = core.targetFragments.Count + 1;

            while (cuts > 0)
            {
                newFragments.Clear();

                foreach (var mesh in core.meshSet)
                {
                    var meshes = CutSingleMesh(mesh);
                    cycleCounter++;

                    if (cycleCounter > core.parameters.TargetFragments)
                    {
                        ExploderUtils.Log("Explode Infinite loop!");
                        cuts = 0;
                        break;
                    }

                    if (meshes != null)
                    {
                        cuts--;

                        var ids = SplitMeshTargetFragments(mesh.id);
                        var ctr = 0;

                        foreach (var cutterMesh in meshes)
                        {
                            var fragment = new MeshObject
                            {
                                mesh = cutterMesh,

                                material        = mesh.material,
                                transform       = mesh.transform,
                                id              = mesh.id,
                                original        = mesh.original,
                                skinnedOriginal = mesh.skinnedOriginal,
                                bakeObject      = mesh.bakeObject,

                                parent     = mesh.transform.parent,
                                position   = mesh.transform.position,
                                rotation   = mesh.transform.rotation,
                                localScale = mesh.transform.localScale,

                                option = mesh.option,
                            };

                            fragment.id = ids[ctr++];
                            newFragments.Add(fragment);
                        }

                        meshToRemove.Add(mesh);
                        break;
                    }
                }

                core.meshSet.ExceptWith(meshToRemove);
                core.meshSet.UnionWith(newFragments);
            }

            if (core.meshSet.Count >= core.parameters.TargetFragments)
            {
                return(true);
            }

            //
            // assign meshes to workers
            //
            var meshPerThread = core.meshSet.Count / (THREAD_MAX - 1);
            var workerId      = 0;
            var meshCounter   = 0;

            foreach (var meshObject in core.meshSet)
            {
                workers[workerId].AddMesh(meshObject);
                meshCounter++;

                if (meshCounter >= meshPerThread && workerId < THREAD_MAX - 2)
                {
                    meshCounter = 0;
                    workerId++;
                }
            }

            core.meshSet.Clear();

            //
            // kick off workers
            //
            foreach (var worker in workers)
            {
                worker.Run();
            }

            localWatch.Stop();
//            Debug.Log("MeshesPerThread: " + meshPerThread + " workers: " + workers.Length + " cuts: " + cutsTotal + " time: " + localWatch.ElapsedMilliseconds);

            return(true);
        }
Ejemplo n.º 7
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);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// triangulate polygon, algorithm from wiki is fast enough
        /// http://wiki.unity3d.com/index.php?title=Triangulator
        /// </summary>
        /// <returns></returns>
        public bool Triangulate(Array <int> indicesArray)
        {
            // no holes supported
            if (holes.Count == 0)
            {
                indicesArray.Initialize(Points.Length * 3);

                int n = Points.Length;
                if (n < 3)
                {
                    return(true);
                }

                var V = new int[n];
                if (Area > 0)
                {
                    for (int v = 0; v < n; v++)
                    {
                        V[v] = v;
                    }
                }
                else
                {
                    for (int v = 0; v < n; v++)
                    {
                        V[v] = (n - 1) - v;
                    }
                }

                int nv    = n;
                int count = 2 * nv;
                for (int m = 0, v = nv - 1; nv > 2;)
                {
                    if ((count--) <= 0)
                    {
                        return(true);
                    }

                    int u = v;
                    if (nv <= u)
                    {
                        u = 0;
                    }
                    v = u + 1;
                    if (nv <= v)
                    {
                        v = 0;
                    }
                    int w = v + 1;
                    if (nv <= w)
                    {
                        w = 0;
                    }

                    if (Snip(u, v, w, nv, V))
                    {
                        int a, b, c, s, t;
                        a = V[u];
                        b = V[v];
                        c = V[w];

                        indicesArray.Add(a);
                        indicesArray.Add(b);
                        indicesArray.Add(c);

                        m++;
                        for (s = v, t = v + 1; t < nv; s++, t++)
                        {
                            V[s] = V[t];
                        }
                        nv--;
                        count = 2 * nv;
                    }
                }

                indicesArray.Reverse();
                return(true);
            }
            else
            {
                // use poly2tri library to triangulate mesh with holes

                var p2tPoints = new List <PrimitivesPro.ThirdParty.P2T.PolygonPoint>(Points.Length);

                foreach (var point in Points)
                {
                    p2tPoints.Add(new PrimitivesPro.ThirdParty.P2T.PolygonPoint(point.x, point.y));
                }

                // create p2t polygon
                var p2tPolygon = new PrimitivesPro.ThirdParty.P2T.Polygon(p2tPoints);

                // add holes
                foreach (var polygonHole in holes)
                {
                    var p2tHolePoints = new List <PrimitivesPro.ThirdParty.P2T.PolygonPoint>(polygonHole.Points.Length);

                    foreach (var polygonPoint in polygonHole.Points)
                    {
                        p2tHolePoints.Add(new PrimitivesPro.ThirdParty.P2T.PolygonPoint(polygonPoint.x, polygonPoint.y));
                    }

                    p2tPolygon.AddHole(new PrimitivesPro.ThirdParty.P2T.Polygon(p2tHolePoints));
                }

                try
                {
                    PrimitivesPro.ThirdParty.P2T.P2T.Triangulate(p2tPolygon);
                }
                catch (Exception ex)
                {
                    ExploderUtils.Log("P2T Exception: " + ex);
                    return(false);
                }

                var triangles = p2tPolygon.Triangles.Count;

                indicesArray.Initialize(triangles * 3);

                Points = new Vector2[triangles * 3];
                var j = 0;

                // recalc min max
                Min.x = float.MaxValue;
                Min.y = float.MaxValue;
                Max.x = float.MinValue;
                Max.y = float.MinValue;

                for (int i = 0; i < triangles; i++)
                {
                    indicesArray.Add((j + 0));
                    indicesArray.Add((j + 1));
                    indicesArray.Add((j + 2));

                    Points[j + 2].x = (float)p2tPolygon.Triangles[i].Points._0.X;
                    Points[j + 2].y = (float)p2tPolygon.Triangles[i].Points._0.Y;

                    Points[j + 1].x = (float)p2tPolygon.Triangles[i].Points._1.X;
                    Points[j + 1].y = (float)p2tPolygon.Triangles[i].Points._1.Y;

                    Points[j + 0].x = (float)p2tPolygon.Triangles[i].Points._2.X;
                    Points[j + 0].y = (float)p2tPolygon.Triangles[i].Points._2.Y;

                    // recalc min max
                    for (int k = 0; k < 3; k++)
                    {
                        if (Points[j + k].x < Min.x)
                        {
                            Min.x = Points[j + k].x;
                        }
                        if (Points[j + k].y < Min.y)
                        {
                            Min.y = Points[j + k].y;
                        }
                        if (Points[j + k].x > Max.x)
                        {
                            Max.x = Points[j + k].x;
                        }
                        if (Points[j + k].y > Max.y)
                        {
                            Max.y = Points[j + k].y;
                        }
                    }

                    j += 3;
                }

                return(true);
            }
        }
Ejemplo n.º 9
0
        private List <MeshObject> GetMeshList()
        {
            List <GameObject> objects = null;

            if (core.parameters.Targets != null)
            {
                objects = new List <GameObject>(core.parameters.Targets);
            }
            else
            {
                if (core.parameters.DontUseTag)
                {
                    var objs = Object.FindObjectsOfType(typeof(Explodable));
                    objects = new List <GameObject>(objs.Length);

                    foreach (var o in objs)
                    {
                        var ex = (Explodable)o;

                        if (ex)
                        {
                            objects.Add(ex.gameObject);
                        }
                    }
                }
                else
                {
                    objects = new List <GameObject>(GameObject.FindGameObjectsWithTag(ExploderObject.Tag));
                }
            }

            if (core.parameters.ExplodeSelf)
            {
                objects.Add(core.parameters.ExploderGameObject);
            }

            var list = new List <MeshObject>(objects.Count);

            int counter = 0;

            var ctr        = Vector3.zero;
            var ctrCounter = 0;

            foreach (var o in objects)
            {
                // in case of destroyed objects
                if (!o)
                {
                    continue;
                }

                // don't destroy the destroyer :)
                if (!core.parameters.ExplodeSelf && o == core.parameters.ExploderGameObject)
                {
                    continue;
                }

                // stop scanning for object is case of settings.ExplodeSelf
                if (o != core.parameters.ExploderGameObject && core.parameters.ExplodeSelf && core.parameters.DisableRadiusScan)
                {
                    continue;
                }

                if (core.parameters.Targets != null || IsInRadius(o))
                {
                    var meshData    = GetMeshData(o);
                    var meshDataLen = meshData.Count;

                    for (var i = 0; i < meshDataLen; i++)
                    {
                        var centroid = meshData[i].centroid;

                        // overwrite settings.Position in case of settings.Target
                        if (core.parameters.Targets != null)
                        {
                            core.parameters.Position = centroid;
                            ctr += centroid;
                            ctrCounter++;
                        }

                        var distance = (centroid - core.parameters.Position).magnitude;

                        //                    UnityEngine.Debug.Log("Distance: " + distance + " " + meshData[i].gameObject.name);

                        list.Add(new MeshObject
                        {
                            id        = counter++,
                            mesh      = new ExploderMesh(meshData[i].sharedMesh),
                            material  = meshData[i].sharedMaterial,
                            transform = new ExploderTransform(meshData[i].gameObject.transform),

                            parent     = meshData[i].gameObject.transform.parent,
                            position   = meshData[i].gameObject.transform.position,
                            rotation   = meshData[i].gameObject.transform.rotation,
                            localScale = meshData[i].gameObject.transform.localScale,
                            bakeObject = meshData[i].gameObject,

                            distanceRatio   = GetDistanceRatio(distance, core.parameters.Radius),
                            original        = meshData[i].parentObject,
                            skinnedOriginal = meshData[i].skinnedBakeOriginal,

                            option = o.GetComponent <ExploderOption>(),
                        });
                    }
                }
            }

            if (ctrCounter > 0)
            {
                ctr /= ctrCounter;
                core.parameters.Position = ctr;
            }

            if (list.Count == 0)
            {
                ExploderUtils.Log("No explodable objects found!");
                return(list);
            }

            if (core.parameters.UniformFragmentDistribution || core.parameters.Targets != null)
            {
                var fragmentPerObject = core.parameters.TargetFragments / list.Count;

                int cnt = core.parameters.TargetFragments;
                foreach (var meshObject in list)
                {
                    core.targetFragments[meshObject.id] = fragmentPerObject;
                    cnt -= fragmentPerObject;
                }

                while (cnt > 0)
                {
                    cnt--;

                    var randMeshObject = list[UnityEngine.Random.Range(0, list.Count - 1)];
                    core.targetFragments[randMeshObject.id] += 1;
                }
            }
            else
            {
                var sum          = 0.0f;
                var sumFragments = 0;

                foreach (var o in list)
                {
                    sum += o.distanceRatio;
                }

                foreach (var mesh in list)
                {
                    core.targetFragments[mesh.id] = (int)((mesh.distanceRatio / sum) * core.parameters.TargetFragments);
                    sumFragments += core.targetFragments[mesh.id];
                }

                if (sumFragments < core.parameters.TargetFragments)
                {
                    var diff = core.parameters.TargetFragments - sumFragments;

                    while (diff > 0)
                    {
                        foreach (var mesh in list)
                        {
                            core.targetFragments[mesh.id] += 1;
                            diff--;

                            if (diff == 0)
                            {
                                break;
                            }
                        }
                    }
                }
            }

            return(list);
        }
Ejemplo n.º 10
0
        private List <MeshData> GetMeshData(GameObject obj)
        {
            var renderers   = obj.GetComponentsInChildren <MeshRenderer>();
            var meshFilters = obj.GetComponentsInChildren <MeshFilter>();

            ExploderUtils.Warning(renderers.Length == meshFilters.Length, "Renderers and meshes don't match!");

            if (renderers.Length != meshFilters.Length)
            {
                return(new List <MeshData>());
            }

            var outList = new List <MeshData>(renderers.Length);

            for (int i = 0; i < renderers.Length; i++)
            {
                if (meshFilters[i].sharedMesh == null)
                {
                    ExploderUtils.Log("Missing shared mesh in " + meshFilters[i].name);
                    continue;
                }

                if (!meshFilters[i].sharedMesh || !meshFilters[i].sharedMesh.isReadable)
                {
                    UnityEngine.Debug.LogWarning("Mesh is not readable: " + meshFilters[i].name);
                    continue;
                }

                if (/*IsExplodable(meshFilters[i].gameObject)*/ true)
                {
                    outList.Add(new MeshData
                    {
                        sharedMesh     = meshFilters[i].sharedMesh,
                        sharedMaterial = renderers[i].sharedMaterial,
                        gameObject     = renderers[i].gameObject,
                        centroid       = renderers[i].bounds.center,
                        parentObject   = obj,
                    });
                }
            }

            // find skinned mesh
            var renderersSkinned = obj.GetComponentsInChildren <SkinnedMeshRenderer>();

            for (int i = 0; i < renderersSkinned.Length; i++)
            {
                var bakeMesh = new Mesh();
                renderersSkinned[i].BakeMesh(bakeMesh);
                var bakeObj    = core.bakeSkinManager.CreateBakeObject(obj.name);
                var meshFilter = bakeObj.AddComponent <MeshFilter>();
                meshFilter.sharedMesh = bakeMesh;
                var meshRenderer = bakeObj.AddComponent <MeshRenderer>();
                meshRenderer.sharedMaterial = renderersSkinned[i].material;
                bakeObj.transform.position  = renderersSkinned[i].gameObject.transform.position;
                bakeObj.transform.rotation  = renderersSkinned[i].gameObject.transform.rotation;
                ExploderUtils.SetVisible(bakeObj, false);

                outList.Add(new MeshData
                {
                    sharedMesh          = bakeMesh,
                    sharedMaterial      = meshRenderer.sharedMaterial,
                    gameObject          = bakeObj,
                    centroid            = meshRenderer.bounds.center,
                    parentObject        = bakeObj,
                    skinnedBakeOriginal = obj,
                });
            }

            return(outList);
        }
Ejemplo n.º 11
0
        public override bool Run(float frameBudget)
        {
            var count = core.postList.Count;

            while (core.poolIdx < count)
            {
                var mesh = core.postList[core.poolIdx];
                core.poolIdx++;

                var islandsFound = false;

                if (core.parameters.SplitMeshIslands || (mesh.option && mesh.option.SplitMeshIslands))
                {
                    var meshIslands = MeshUtils.IsolateMeshIslands(mesh.mesh);

                    if (meshIslands != null)
                    {
                        islandsFound = true;

                        foreach (var meshIsland in meshIslands)
                        {
                            islands.Add(new MeshObject
                            {
                                mesh = meshIsland,

                                material        = mesh.material,
                                transform       = mesh.transform,
                                original        = mesh.original,
                                skinnedOriginal = mesh.skinnedOriginal,

                                parent     = mesh.transform.parent,
                                position   = mesh.transform.position,
                                rotation   = mesh.transform.rotation,
                                localScale = mesh.transform.localScale,

                                option = mesh.option,
                            });
                        }
                    }
                }

                if (!islandsFound)
                {
                    islands.Add(mesh);
                }

                if (Watch.ElapsedMilliseconds > frameBudget)
                {
                    return(false);
                }
            }

#if DBG
            ExploderUtils.Log("Replacing fragments: " + postList.Count + " by islands: " + islands.Count);
#endif

            // replace postList by island list
            core.postList = islands;

            Watch.Stop();

            return(true);
        }
Ejemplo n.º 12
0
        public bool FindContours()
        {
            if (midPoints.Count == 0)
            {
                return(false);
            }

#if DEBUG_CONTOUR
            Utils.Log("MidPoint: " + midPoints.Count);

            foreach (var midPoint in midPoints)
            {
                if (midPoint.Value.idNext == HashType.MaxValue || midPoint.Value.idPrev == HashType.MaxValue)
                {
                    Utils.Log(midPoint.Value.id + " " + midPoint.Value.idNext + " " + midPoint.Value.idPrev);

                    var sphere = PrimitivesPro.GameObjects.Sphere.Create(0.1f, 10, 0, 0, NormalsType.Vertex,
                                                                         PivotPosition.Center);
                    sphere.transform.position            = midPoint.Value.position;
                    sphere.renderer.sharedMaterial.color = Color.red;
                }
            }
#endif

            var midContour = new Dictionary <int, int>(midPoints.Count);

            var loopsMax = midPoints.Count * 2;

            // find contour
            var pStart = midPoints.GetFirstValue();
            midContour.Add(pStart.id, pStart.vertexId);
            midPoints.Remove(pStart.id);
            var nextP = pStart.idNext;

            while (midPoints.Count > 0)
            {
                if (nextP == Int32.MaxValue)
                {
                    return(false);
                }

                MidPoint p;
                if (!midPoints.TryGetValue(nextP, out p))
                {
                    contour.Clear();
//                    throw new Exception("Contour failed");
                    return(false);
                }

                // add new point on contour
                midContour.Add(p.id, p.vertexId);
                midPoints.Remove(p.id);

                if (midContour.ContainsKey(p.idNext))
                {
                    if (midContour.ContainsKey(p.idPrev))
                    {
                        // closing the loop!
                        contour.Add(new Dictionary <int, int>(midContour));
                        midContour.Clear();

                        if (midPoints.Count == 0)
                        {
                            break;
                        }

                        pStart = midPoints.GetFirstValue();
                        midContour.Add(pStart.id, pStart.vertexId);
                        midPoints.Remove(pStart.id);
                        nextP = pStart.idNext;
                        continue;
                    }

                    nextP = p.idPrev;
                }
                else
                {
                    nextP = p.idNext;
                }

                loopsMax--;
                if (loopsMax == 0)
                {
//                    Utils.Assert(false, "ForeverLoop!");
                    ExploderUtils.Log("ForeverLoop!");
//                   throw new Exception("Contour failed");
                    contour.Clear();
                    return(false);
                }
            }

            return(true);
        }
Ejemplo n.º 13
0
        protected virtual bool Cut(float frameBudget)
        {
            bool cutting        = true;
            var  cycleCounter   = 0;
            bool timeBudgetStop = false;

            cutAttempt = 0;

            while (cutting)
            {
                cycleCounter++;

                if (cycleCounter > core.parameters.TargetFragments)
                {
                    ExploderUtils.Log("Explode Infinite loop!");
                    return(true);
                }

                newFragments.Clear();
                meshToRemove.Clear();

                cutting = false;

                foreach (var mesh in core.meshSet)
                {
                    if (!core.targetFragments.ContainsKey(mesh.id))
                    {
                        Debug.Assert(false);
                    }

                    if (core.targetFragments[mesh.id] > 1)
                    {
                        var meshes = CutSingleMesh(mesh);

                        cutting = true;

                        if (meshes != null)
                        {
                            foreach (var cutterMesh in meshes)
                            {
                                newFragments.Add(new MeshObject
                                {
                                    mesh = cutterMesh,

                                    material        = mesh.material,
                                    transform       = mesh.transform,
                                    id              = mesh.id,
                                    original        = mesh.original,
                                    skinnedOriginal = mesh.skinnedOriginal,
                                    bakeObject      = mesh.bakeObject,

                                    parent     = mesh.transform.parent,
                                    position   = mesh.transform.position,
                                    rotation   = mesh.transform.rotation,
                                    localScale = mesh.transform.localScale,

                                    option = mesh.option,
                                });
                            }

                            meshToRemove.Add(mesh);

                            core.targetFragments[mesh.id] -= 1;

                            // computation took more than settings.FrameBudget ...
                            if (Watch.ElapsedMilliseconds > frameBudget && cycleCounter > 2)
                            {
                                timeBudgetStop = true;
                                break;
                            }
                        }
                    }
                }

                core.meshSet.ExceptWith(meshToRemove);
                core.meshSet.UnionWith(newFragments);

                if (timeBudgetStop)
                {
                    break;
                }
            }

            // explosion is finished
            return(!timeBudgetStop);
        }