Exemplo 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);
        }
Exemplo n.º 2
0
        void Boom()
        {
            var centroid = ExploderUtils.GetCentroid(gameObject);

            // place the exploder object to centroid position
            exploder.transform.position = centroid;
            exploder.ExplodeSelf        = false;

            // adjust force vector to be in direction from shotgun
            exploder.ForceVector = ForceVector;
            //                Utils.Log("ForceVec: " + exploder.ForceVector);
            exploder.Force          = force;
            exploder.UseForceVector = true;

            // fragment pieces
            exploder.TargetFragments = targetFragments;

            // set explosion radius to 5 meters
            exploder.Radius = radius;

            // run explosion
            exploder.Explode();

            //Destroy (this);
        }
Exemplo n.º 3
0
 public ExploderParams(ExploderObject exploder)
 {
     this.Position                    = ExploderUtils.GetCentroid(((Component)exploder).get_gameObject());
     this.DontUseTag                  = exploder.DontUseTag;
     this.Radius                      = exploder.Radius;
     this.UseCubeRadius               = exploder.UseCubeRadius;
     this.CubeRadius                  = exploder.CubeRadius;
     this.ForceVector                 = exploder.ForceVector;
     this.UseForceVector              = exploder.UseForceVector;
     this.Force                       = exploder.Force;
     this.FrameBudget                 = exploder.FrameBudget;
     this.TargetFragments             = exploder.TargetFragments;
     this.ExplodeSelf                 = exploder.ExplodeSelf;
     this.HideSelf                    = exploder.HideSelf;
     this.ThreadOptions               = exploder.ThreadOption;
     this.DestroyOriginalObject       = exploder.DestroyOriginalObject;
     this.SplitMeshIslands            = exploder.SplitMeshIslands;
     this.FragmentOptions             = exploder.FragmentOptions.Clone();
     this.FragmentDeactivation        = exploder.FragmentDeactivation.Clone();
     this.FragmentSFX                 = exploder.FragmentSFX.Clone();
     this.Use2DCollision              = exploder.Use2DCollision;
     this.FragmentPoolSize            = exploder.FragmentPoolSize;
     this.DisableRadiusScan           = exploder.DisableRadiusScan;
     this.UniformFragmentDistribution = exploder.UniformFragmentDistribution;
     this.DisableTriangulation        = exploder.DisableTriangulation;
     this.ExploderGameObject          = ((Component)exploder).get_gameObject();
     this.CuttingStyle                = exploder.CuttingStyle;
 }
Exemplo n.º 4
0
 public ExploderParams(ExploderObject exploder)
 {
     Position                    = ExploderUtils.GetCentroid(exploder.gameObject);
     DontUseTag                  = exploder.DontUseTag;
     Radius                      = exploder.Radius;
     UseCubeRadius               = exploder.UseCubeRadius;
     CubeRadius                  = exploder.CubeRadius;
     ForceVector                 = exploder.ForceVector;
     UseForceVector              = exploder.UseForceVector;
     Force                       = exploder.Force;
     FrameBudget                 = exploder.FrameBudget;
     TargetFragments             = exploder.TargetFragments;
     ExplodeSelf                 = exploder.ExplodeSelf;
     HideSelf                    = exploder.HideSelf;
     ThreadOptions               = exploder.ThreadOption;
     DestroyOriginalObject       = exploder.DestroyOriginalObject;
     SplitMeshIslands            = exploder.SplitMeshIslands;
     FragmentOptions             = exploder.FragmentOptions.Clone();
     FragmentDeactivation        = exploder.FragmentDeactivation.Clone();
     FragmentSFX                 = exploder.FragmentSFX.Clone();
     Use2DCollision              = exploder.Use2DCollision;
     FragmentPoolSize            = exploder.FragmentPoolSize;
     DisableRadiusScan           = exploder.DisableRadiusScan;
     UniformFragmentDistribution = exploder.UniformFragmentDistribution;
     DisableTriangulation        = exploder.DisableTriangulation;
     ExploderGameObject          = exploder.gameObject;
     CuttingStyle                = exploder.CuttingStyle;
 }
Exemplo n.º 5
0
        public void StartExplosionFromQueue(ExploderParams p)
        {
            ExploderUtils.Assert(currTaskType == TaskType.None, "Wrong task: " + currTaskType);
            this.parameters  = p;
            processingFrames = 1;
            explosionWatch.Reset();
            explosionWatch.Start();

            //
            // do preprocess right away
            //
            currTaskType = TaskType.Preprocess;
            InitTask(currTaskType);
            RunTask(currTaskType);

            if (parameters.ThreadOptions != ExploderObject.ThreadOptions.Disabled)
            {
                currTaskType = NextTask(currTaskType);

                if (currTaskType != TaskType.None)
                {
                    InitTask(currTaskType);
                    RunTask(currTaskType, parameters.FrameBudget);
                }
                else
                {
                    explosionWatch.Stop();
                    queue.OnExplosionFinished(parameters.id, explosionWatch.ElapsedMilliseconds);
                }
            }
        }
Exemplo n.º 6
0
        public void OnExplosionFinished(int id)
        {
            var explosion = queue.Dequeue();

            ExploderUtils.Assert(explosion.id == id, "Explosion id mismatch!");
            ProcessQueue();
        }
Exemplo n.º 7
0
        /// <summary>
        /// deactivate this fragment piece
        /// </summary>
        public void Deactivate()
        {
            if (activePlayback == audioSource)
            {
                activePlayback = null;
            }

            Sleep();
            ExploderUtils.SetActiveRecursively(gameObject, false);
            Visible  = false;
            IsActive = false;

            if (meshFilter && meshFilter.sharedMesh)
            {
                DestroyImmediate(meshFilter.sharedMesh, true);
            }

            // turn off particles
            if (particleSystems != null)
            {
                foreach (var psystem in particleSystems)
                {
                    psystem.Clear();
                }
            }
        }
Exemplo n.º 8
0
        public void Explode(ExploderObject.OnExplosion callback)
        {
            var settings = new ExploderSettings
            {
                Position              = ExploderUtils.GetCentroid(exploder.gameObject),
                DontUseTag            = exploder.DontUseTag,
                Radius                = exploder.Radius,
                ForceVector           = exploder.ForceVector,
                UseForceVector        = exploder.UseForceVector,
                Force                 = exploder.Force,
                FrameBudget           = exploder.FrameBudget,
                TargetFragments       = exploder.TargetFragments,
                DeactivateOptions     = exploder.DeactivateOptions,
                DeactivateTimeout     = exploder.DeactivateTimeout,
                MeshColliders         = exploder.MeshColliders,
                ExplodeSelf           = exploder.ExplodeSelf,
                HideSelf              = exploder.HideSelf,
                DestroyOriginalObject = exploder.DestroyOriginalObject,
                ExplodeFragments      = exploder.ExplodeFragments,
                SplitMeshIslands      = exploder.SplitMeshIslands,
                FragmentOptions       = exploder.FragmentOptions.Clone(),
                Callback              = callback,
                processing            = false,
            };

            queue.Enqueue(settings);
            ProcessQueue();
        }
Exemplo n.º 9
0
        public void StartExplosionFromQueue(ExploderParams p)
        {
            this.parameters       = p;
            this.processingFrames = 1;
            this.explosionWatch.Reset();
            this.explosionWatch.Start();
            AudioSource component = (AudioSource)p.ExploderGameObject.GetComponent <AudioSource>();

            if (Object.op_Implicit((Object)component))
            {
                ExploderUtils.CopyAudioSource(component, this.audioSource);
            }
            this.currTaskType = TaskType.Preprocess;
            this.InitTask(this.currTaskType);
            this.RunTask(this.currTaskType, 0.0f);
            if (this.parameters.ThreadOptions == ExploderObject.ThreadOptions.Disabled)
            {
                return;
            }
            this.currTaskType = this.NextTask(this.currTaskType);
            if (this.currTaskType != TaskType.None)
            {
                this.InitTask(this.currTaskType);
                this.RunTask(this.currTaskType, this.parameters.FrameBudget);
            }
            else
            {
                this.explosionWatch.Stop();
                this.queue.OnExplosionFinished(this.parameters.id, this.explosionWatch.ElapsedMilliseconds);
            }
        }
Exemplo n.º 10
0
 public ExploderSettings(ExploderObject exploder)
 {
     Position                    = ExploderUtils.GetCentroid(exploder.gameObject);
     DontUseTag                  = exploder.DontUseTag;
     Radius                      = exploder.Radius;
     UseCubeRadius               = exploder.UseCubeRadius;
     CubeRadius                  = exploder.CubeRadius;
     ForceVector                 = exploder.ForceVector;
     UseForceVector              = exploder.UseForceVector;
     Force                       = exploder.Force;
     FrameBudget                 = exploder.FrameBudget;
     TargetFragments             = exploder.TargetFragments;
     DeactivateOptions           = exploder.DeactivateOptions;
     DeactivateTimeout           = exploder.DeactivateTimeout;
     MeshColliders               = exploder.MeshColliders;
     ExplodeSelf                 = exploder.ExplodeSelf;
     HideSelf                    = exploder.HideSelf;
     DestroyOriginalObject       = exploder.DestroyOriginalObject;
     ExplodeFragments            = exploder.ExplodeFragments;
     SplitMeshIslands            = exploder.SplitMeshIslands;
     FragmentOptions             = exploder.FragmentOptions.Clone();
     SfxOptions                  = exploder.SFXOptions.Clone();
     Use2DCollision              = exploder.Use2DCollision;
     FragmentPoolSize            = exploder.FragmentPoolSize;
     FragmentPrefab              = exploder.FragmentPrefab;
     FadeoutOptions              = exploder.FadeoutOptions;
     SFXOptions                  = exploder.SFXOptions;
     DisableRadiusScan           = exploder.DisableRadiusScan;
     UniformFragmentDistribution = exploder.UniformFragmentDistribution;
     AllowOpenMeshCutting        = exploder.AllowOpenMeshCutting;
 }
Exemplo n.º 11
0
        private TaskType NextTask(TaskType taskType)
        {
            switch (taskType)
            {
            case TaskType.Preprocess:
            {
                if (meshSet.Count == 0)
                {
                    return(TaskType.None);
                }

                if (parameters.PartialExplosion)
                {
                    return(TaskType.PartialSeparator);
                }
                return(TaskType.ProcessCutter);
            }

            case TaskType.PartialSeparator:
                return(TaskType.ProcessCutter);

            case TaskType.ProcessCutter:
            {
                if (splitMeshIslands)
                {
                    return(TaskType.IsolateMeshIslands);
                }
                if (parameters.Crack)
                {
                    return(TaskType.PostprocessCrack);
                }

                return(TaskType.PostprocessExplode);
            }

            case TaskType.IsolateMeshIslands:
            {
                if (parameters.Crack)
                {
                    return(TaskType.PostprocessCrack);
                }

                return(TaskType.PostprocessExplode);
            }

            case TaskType.PostprocessExplode:
                return(TaskType.None);

            case TaskType.PostprocessCrack:
                return(TaskType.None);

            default:
                ExploderUtils.Assert(false, "Invalid task type!");
                break;
            }

            ExploderUtils.Assert(false, "Invalid task type!");
            return(TaskType.None);
        }
Exemplo n.º 12
0
        /// <summary>
        /// create pool (array) of fragment game objects with all necessary components
        /// </summary>
        /// <param name="poolSize">number of fragments</param>
        /// <param name="useMeshColliders">use mesh colliders</param>
        /// <param name="use2dCollision">enable Unity 2D collision system</param>
        public void Allocate(int poolSize, bool useMeshColliders, bool use2dCollision, bool useGravity)
        {
            ExploderUtils.Assert(poolSize > 0, "");

            if (pool == null || pool.Length < poolSize || useMeshColliders != this.meshColliders)
            {
                DestroyFragments();

                pool = new Fragment[poolSize];

                this.meshColliders = useMeshColliders;

                for (int i = 0; i < poolSize; i++)
                {
                    var fragment = new GameObject("fragment_" + i);
                    fragment.AddComponent <MeshFilter>();
                    fragment.AddComponent <MeshRenderer>();

                    if (use2dCollision)
                    {
#if PHYSICS_2D
                        fragment.AddComponent <PolygonCollider2D>();
                        fragment.AddComponent <Rigidbody2D>();
#endif
                    }
                    else
                    {
                        if (useMeshColliders)
                        {
                            var meshCollider = fragment.AddComponent <MeshCollider>();
                            meshCollider.convex = true;
                        }
                        else
                        {
                            fragment.AddComponent <BoxCollider>();
                        }

                        Rigidbody rb = fragment.AddComponent <Rigidbody>();
                        rb.useGravity = useGravity;
                    }

                    fragment.AddComponent <ExploderOption>();

                    var fragmentComponent = fragment.AddComponent <Fragment>();

                    fragment.transform.parent = gameObject.transform;

                    pool[i] = fragmentComponent;

                    ExploderUtils.SetActiveRecursively(fragment.gameObject, false);

                    fragmentComponent.RefreshComponentsCache();

                    fragmentComponent.Sleep();
                }
            }
        }
Exemplo n.º 13
0
        /// <summary>
        /// c-tor
        /// </summary>
        /// <param name="pnts">points of the polygon</param>
        public Polygon(Vector2[] pnts)
        {
            ExploderUtils.Assert(pnts.Length >= 3, "Invalid polygon!");

            Points = pnts;
            Area   = GetArea();

            holes = new List <Polygon>();
        }
Exemplo n.º 14
0
        public long Explode()
        {
            int count = this.pool.Count;
            int index = 0;

            if (count == 0)
            {
                return(0);
            }
            this.watch.Start();
            if (this.parameters.Callback != null)
            {
                this.parameters.Callback(0.0f, ExploderObject.ExplosionState.ExplosionStarted);
            }
            Vector3    vector3    = Vector3.get_zero();
            Quaternion quaternion = Quaternion.get_identity();

            if (Object.op_Implicit((Object)this.originalObject))
            {
                vector3    = Vector3.op_Subtraction(this.originalObject.get_transform().get_position(), this.initPos);
                quaternion = Quaternion.op_Multiply(this.originalObject.get_transform().get_rotation(), Quaternion.Inverse(this.initRot));
            }
            while (index < count)
            {
                Fragment fragment = this.pool[index];
                ++index;
                if (Object.op_Inequality((Object)this.originalObject, (Object)this.parameters.ExploderGameObject))
                {
                    ExploderUtils.SetActiveRecursively(this.originalObject, false);
                }
                else
                {
                    ExploderUtils.EnableCollider(this.originalObject, false);
                    ExploderUtils.SetVisible(this.originalObject, false);
                }
                Transform transform1 = ((Component)fragment).get_transform();
                transform1.set_position(Vector3.op_Addition(transform1.get_position(), vector3));
                Transform transform2 = ((Component)fragment).get_transform();
                transform2.set_rotation(Quaternion.op_Multiply(transform2.get_rotation(), quaternion));
                fragment.Explode(this.parameters);
            }
            if (this.parameters.DestroyOriginalObject && Object.op_Implicit((Object)this.originalObject) && !Object.op_Implicit((Object)this.originalObject.GetComponent <Fragment>()))
            {
                Object.Destroy((Object)this.originalObject);
            }
            if (this.parameters.ExplodeSelf && !this.parameters.DestroyOriginalObject)
            {
                ExploderUtils.SetActiveRecursively(this.parameters.ExploderGameObject, false);
            }
            if (this.parameters.HideSelf)
            {
                ExploderUtils.SetActiveRecursively(this.parameters.ExploderGameObject, false);
            }
            this.watch.Stop();
            return(this.watch.ElapsedMilliseconds);
        }
Exemplo n.º 15
0
        public void OnExplosionFinished(int id, long ellapsedMS)
        {
            var explosion = queue.Dequeue();

            ExploderUtils.Assert(explosion.id == id, "Explosion id mismatch!");

            if (explosion.Callback != null)
            {
                explosion.Callback(ellapsedMS, explosion.Crack ? ExploderObject.ExplosionState.ObjectCracked : ExploderObject.ExplosionState.ExplosionFinished);
            }

            ProcessQueue();
        }
Exemplo n.º 16
0
        public static void SetActiveRecursively(GameObject obj, bool status)
        {
            if (!Object.op_Implicit((Object)obj))
            {
                return;
            }
            int childCount = obj.get_transform().get_childCount();

            for (int index = 0; index < childCount; ++index)
            {
                ExploderUtils.SetActiveRecursively(((Component)obj.get_transform().GetChild(index)).get_gameObject(), status);
            }
            obj.SetActive(status);
        }
Exemplo n.º 17
0
        /// <summary>
        /// this is called from exploder class to start the explosion
        /// </summary>
        public void Explode()
        {
            activeObj = true;
            ExploderUtils.SetActiveRecursively(gameObject, true);
            visibilityCheckTimer = 0.1f;
            visible         = true;
            deactivateTimer = deactivateTimeout;
            originalScale   = transform.localScale;

            if (explodable)
            {
                tag = ExploderObject.Tag;
            }
        }
Exemplo n.º 18
0
        /// <summary>
        /// deactivate this fragment piece
        /// </summary>
        public void Deactivate()
        {
            ExploderUtils.SetActive(gameObject, false);
            visible   = false;
            activeObj = false;

            // turn off particles
            if (emmiters != null)
            {
                foreach (var emitter in emmiters)
                {
                    emitter.ClearParticles();
                }
            }
        }
Exemplo n.º 19
0
        /// <summary>
        /// deactivate this fragment piece
        /// </summary>
        public void Deactivate()
        {
            ExploderUtils.SetActive(gameObject, false);
            visible   = false;
            activeObj = false;

            // turn off particles
            if (particleSystems != null)
            {
                foreach (var psystem in particleSystems)
                {
                    psystem.Clear();
                }
            }
        }
Exemplo n.º 20
0
        private bool IsInRadius(GameObject o)
        {
            var centroid = ExploderUtils.GetCentroid(o);

            if (core.parameters.UseCubeRadius)
            {
                var localP = core.parameters.ExploderGameObject.transform.InverseTransformPoint(centroid);
                var localC = core.parameters.ExploderGameObject.transform.InverseTransformPoint(core.parameters.Position);

                return(Mathf.Abs(localP.x - localC.x) < core.parameters.CubeRadius.x &&
                       Mathf.Abs(localP.y - localC.y) < core.parameters.CubeRadius.y &&
                       Mathf.Abs(localP.z - localC.z) < core.parameters.CubeRadius.z);
            }

            return(core.parameters.Radius * core.parameters.Radius > (centroid - core.parameters.Position).sqrMagnitude);
        }
Exemplo n.º 21
0
        public List <Fragment> GetActiveFragments()
        {
            if (this.pool == null)
            {
                return((List <Fragment>)null);
            }
            List <Fragment> fragmentList = new List <Fragment>(this.pool.Length);

            foreach (Fragment fragment in this.pool)
            {
                if (ExploderUtils.IsActive(((Component)fragment).get_gameObject()))
                {
                    fragmentList.Add(fragment);
                }
            }
            return(fragmentList);
        }
Exemplo n.º 22
0
 public void Explode(ExploderParams parameters)
 {
     this.settings = parameters;
     this.IsActive = true;
     ExploderUtils.SetActiveRecursively(((Component)this).get_gameObject(), true);
     this.visibilityCheckTimer = 0.1f;
     this.Visible         = true;
     this.Cracked         = false;
     this.collided        = false;
     this.deactivateTimer = this.settings.FragmentDeactivation.DeactivateTimeout;
     this.originalScale   = ((Component)this).get_transform().get_localScale();
     if (this.settings.FragmentOptions.ExplodeFragments)
     {
         ((Component)this).set_tag(ExploderObject.Tag);
     }
     this.Emit(true);
 }
Exemplo n.º 23
0
 private void OnDrawGizmos()
 {
     if (!((Behaviour)this).get_enabled() || this.ExplodeSelf && this.DisableRadiusScan)
     {
         return;
     }
     Gizmos.set_color(Color.get_red());
     if (this.UseCubeRadius)
     {
         Vector3 centroid = ExploderUtils.GetCentroid(((Component)this).get_gameObject());
         Gizmos.set_matrix(((Component)this).get_transform().get_localToWorldMatrix());
         Gizmos.DrawWireCube(((Component)this).get_transform().InverseTransformPoint(centroid), this.CubeRadius);
     }
     else
     {
         Gizmos.DrawWireSphere(ExploderUtils.GetCentroid(((Component)this).get_gameObject()), this.Radius);
     }
 }
Exemplo n.º 24
0
        void OnDrawGizmos()
        {
            if (enabled && !(ExplodeSelf && DisableRadiusScan))
            {
                Gizmos.color = Color.red;

                if (UseCubeRadius)
                {
                    var pos = ExploderUtils.GetCentroid(gameObject);
                    Gizmos.matrix = transform.localToWorldMatrix;
                    Gizmos.DrawWireCube(transform.InverseTransformPoint(pos), CubeRadius);
                }
                else
                {
                    Gizmos.DrawWireSphere(ExploderUtils.GetCentroid(gameObject), Radius);
                }
            }
        }
Exemplo n.º 25
0
        /// <summary>
        /// returns list of currently active (visible) fragments
        /// </summary>
        /// <returns></returns>
        public List <Fragment> GetActiveFragments()
        {
            if (pool != null)
            {
                var list = new List <Fragment>(pool.Length);

                foreach (var fragment in pool)
                {
                    if (ExploderUtils.IsActive(fragment.gameObject))
                    {
                        list.Add(fragment);
                    }
                }

                return(list);
            }

            return(null);
        }
Exemplo n.º 26
0
        /// <summary>
        /// this is called from exploder class to start the explosion
        /// </summary>
        public void Explode(ExploderParams parameters)
        {
            this.settings = parameters;

            IsActive = true;
            ExploderUtils.SetActiveRecursively(gameObject, true);
            visibilityCheckTimer = 0.1f;
            Visible         = true;
            Cracked         = false;
            collided        = false;
            deactivateTimer = settings.FragmentDeactivation.DeactivateTimeout;
            originalScale   = transform.localScale;

            if (settings.FragmentOptions.ExplodeFragments)
            {
                tag = ExploderObject.Tag;
            }

            Emit(true);
        }
Exemplo n.º 27
0
 public void Deactivate()
 {
     if (Object.op_Equality((Object)Fragment.activePlayback, (Object)this.audioSource))
     {
         Fragment.activePlayback = (AudioSource)null;
     }
     this.Sleep();
     ExploderUtils.SetActiveRecursively(((Component)this).get_gameObject(), false);
     this.Visible  = false;
     this.IsActive = false;
     if (Object.op_Implicit((Object)this.meshFilter) && Object.op_Implicit((Object)this.meshFilter.get_sharedMesh()))
     {
         Object.DestroyImmediate((Object)this.meshFilter.get_sharedMesh(), true);
     }
     if (this.particleSystems == null)
     {
         return;
     }
     foreach (ParticleSystem particleSystem in this.particleSystems)
     {
         particleSystem.Clear();
     }
 }
Exemplo n.º 28
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);
        }
Exemplo n.º 29
0
        void Triangulate(List <Dictionary <int, int> > contours, Plane plane, List <Vector3>[] vertices, List <Vector3>[] normals, List <Vector2>[] uvs,
                         List <Vector4>[] tangents, List <Color32>[] colors, List <int>[] triangles, bool uvCutMesh, bool useTangents, bool useColors, bool useNormals)
        {
            if (contours.Count == 0 || contours[0].Count < 3)
            {
//                Utils.Log("Contour empty!: ");
                return;
            }

            // prepare plane matrix
            var m    = plane.GetPlaneMatrix();
            var mInv = m.inverse;

            var zShit = 0.0f;

            var polygons = new List <Polygon>(contours.Count);

            // construct polygons from contours
            Polygon highAreaPoly = null;

            foreach (var ctr in contours)
            {
                var polygonPoints = new Vector2[ctr.Count];
                var j             = 0;

                foreach (var i in ctr.Values)
                {
                    var p = mInv * vertices[0][i];
                    polygonPoints[j++] = p;

                    // save z-coordinate
                    zShit = p.z;
                }

                var polygon = new Polygon(polygonPoints);
                polygons.Add(polygon);

                if (highAreaPoly == null || Mathf.Abs(highAreaPoly.Area) < Mathf.Abs(polygon.Area))
                {
                    highAreaPoly = polygon;
                }
            }

            ExploderUtils.Assert(polygons.Count > 0, "Zero polygons!");

            // test for holes
            if (polygons.Count > 0)
            {
                var polyToRemove = new List <Polygon>();

                foreach (var polygon in polygons)
                {
                    if (polygon != highAreaPoly)
                    {
                        if (highAreaPoly.IsPointInside(polygon.Points[0]))
                        {
                            highAreaPoly.AddHole(polygon);
                            polyToRemove.Add(polygon);
                        }
                    }
                }

                foreach (var polygon in polyToRemove)
                {
                    polygons.Remove(polygon);
                }
            }

            var vertCounter0 = vertices[0].Count;
            var vertCounter1 = vertices[1].Count;

            foreach (var polygon in polygons)
            {
                if (!polygon.Triangulate(polygonIndicesArray))
                {
                    continue;
                }

//                ExploderUtils.Assert(indices.Count == polygonIndicesArray.Count, "Count mismatch!");
//
//                for (int i = 0; i < indices.Count; i++)
//                {
//                    ExploderUtils.Assert(polygonIndicesArray[i] == indices[i], "Indices not match: " + polygons.Count);
//
//                    if (indices[i] != polygonIndicesArray[i])
//                    {
//                        ExploderUtils.Assert(false, "");
//                    }
//                }

                // get polygon bounding square size
                var min         = Mathf.Min(polygon.Min.x, polygon.Min.y);
                var max         = Mathf.Max(polygon.Max.x, polygon.Max.y);
                var polygonSize = max - min;

//                Utils.Log("PolygonSize: " + polygonSize + " " + polygon.Min + " " + polygon.Max);

//                Utils.Log("Triangulate polygons: " + polygon.Points.Length);

                foreach (var polyPoint in polygon.Points)
                {
                    var p = m * new Vector3(polyPoint.x, polyPoint.y, zShit);

                    vertices[0].Add(p);
                    vertices[1].Add(p);

                    if (useNormals)
                    {
                        normals[0].Add(-plane.Normal);
                        normals[1].Add(plane.Normal);
                    }

                    if (uvCutMesh)
                    {
                        var uv0 = new Vector2((polyPoint.x - min) / polygonSize,
                                              (polyPoint.y - min) / polygonSize);
                        var uv1 = new Vector2((polyPoint.x - min) / polygonSize,
                                              (polyPoint.y - min) / polygonSize);

                        // normalize uv to fit cross-section uv area
                        var areaSizeX = crossSectionUV.z - crossSectionUV.x;
                        var areaSizeY = crossSectionUV.w - crossSectionUV.y;

                        uv0.x = crossSectionUV.x + uv0.x * areaSizeX;
                        uv0.y = crossSectionUV.y + uv0.y * areaSizeY;
                        uv1.x = crossSectionUV.x + uv1.x * areaSizeX;
                        uv1.y = crossSectionUV.y + uv1.y * areaSizeY;

                        uvs[0].Add(uv0);
                        uvs[1].Add(uv1);
                    }
                    else
                    {
                        uvs[0].Add(Vector2.zero);
                        uvs[1].Add(Vector2.zero);
                    }

                    if (useTangents)
                    {
                        // fast and dirty way to create tangents
                        var v0 = plane.Normal;
                        MeshUtils.Swap(ref v0.x, ref v0.y);
                        MeshUtils.Swap(ref v0.y, ref v0.z);

                        Vector4 tangent = Vector3.Cross(plane.Normal, v0);
                        tangent.w = 1.0f;

                        tangents[0].Add(tangent);

                        tangent.w = -1.0f;
                        tangents[1].Add(tangent);
                    }

                    if (useColors)
                    {
                        colors[0].Add(crossSectionVertexColour);
                        colors[1].Add(crossSectionVertexColour);
                    }
                }

                var indicesCount = polygonIndicesArray.Count;

                var j = indicesCount - 1;
                for (int i = 0; i < indicesCount; i++)
                {
                    triangles[0].Add(vertCounter0 + polygonIndicesArray[i]);
                    triangles[1].Add(vertCounter1 + polygonIndicesArray[j]);
                    j--;
                }

                vertCounter0 += polygon.Points.Length;
                vertCounter1 += polygon.Points.Length;
            }
        }
Exemplo n.º 30
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);
        }