Exemple #1
0
    void Start()
    {
        // Enable fracturable object collider

        FracturedObject fracturedObject = GetComponent <FracturedObject>();

        pv = fracturedObject.GetComponent <PhotonView> ();
        // Disable chunk colliders
        k1 = GameObject.Find("k1").GetComponent <Text>();
        k2 = GameObject.Find("k2").GetComponent <Text>();
        k3 = GameObject.Find("k3").GetComponent <Text>();
        k4 = GameObject.Find("k4").GetComponent <Text>();
        if (fracturedObject != null)
        {
            if (fracturedObject.GetComponent <Collider>() != null)
            {
                fracturedObject.GetComponent <Collider>().enabled = true;
            }
            else
            {
                Debug.LogWarning("Fracturable Object " + gameObject.name + " has a dynamic rigidbody but no collider. Object will not be able to collide.");
            }

            for (int i = 0; i < fracturedObject.ListFracturedChunks.Count; i++)
            {
                EnableObjectColliders(fracturedObject.ListFracturedChunks[i].gameObject, false);
            }
        }
    }
        public static int ComputeHull(GameObject gameObject, FracturedObject fracturedObject)
        {
            int nTotalTriangles = 0;

            if (ComputeHull(gameObject, fracturedObject.ChunkColliderType == FracturedObject.ColliderType.Trigger, fracturedObject.ConcaveColliderAlgorithm, fracturedObject.ConcaveColliderMaxHulls, fracturedObject.ConcaveColliderMaxHullVertices, fracturedObject.ConcaveColliderLegacySteps, fracturedObject.Verbose, out nTotalTriangles) == false)
            {
                if (fracturedObject.ConcaveColliderAlgorithm == FracturedObject.ECCAlgorithm.Fast)
                {
                    // Fast failed. Try with normal.
                    if (fracturedObject.Verbose)
                    {
                        Debug.Log(gameObject.name + ": Falling back to normal convex decomposition algorithm");
                    }

                    if (ComputeHull(gameObject, fracturedObject.ChunkColliderType == FracturedObject.ColliderType.Trigger, FracturedObject.ECCAlgorithm.Normal, fracturedObject.ConcaveColliderMaxHulls, fracturedObject.ConcaveColliderMaxHullVertices, fracturedObject.ConcaveColliderLegacySteps, fracturedObject.Verbose, out nTotalTriangles) == false)
                    {
                        if (fracturedObject.Verbose)
                        {
                            Debug.Log(gameObject.name + ": Falling back to box collider");
                        }
                    }
                }
            }

            return(nTotalTriangles);
        }
        public static int ComputeHull(GameObject gameObject, FracturedObject fracturedObject)
        {
            int nTotalTriangles = 0;

            if(ComputeHull(gameObject, fracturedObject.ConcaveColliderAlgorithm, fracturedObject.ConcaveColliderMaxHulls, fracturedObject.ConcaveColliderMaxHullVertices, fracturedObject.ConcaveColliderLegacySteps, fracturedObject.Verbose, out nTotalTriangles) == false)
            {
                if(fracturedObject.ConcaveColliderAlgorithm == FracturedObject.ECCAlgorithm.Fast)
                {
                    // Fast failed. Try with normal.
                    if(fracturedObject.Verbose)
                    {
                        Debug.Log(gameObject.name + ": Falling back to normal convex decomposition algorithm");
                    }

                    if(ComputeHull(gameObject, FracturedObject.ECCAlgorithm.Normal, fracturedObject.ConcaveColliderMaxHulls, fracturedObject.ConcaveColliderMaxHullVertices, fracturedObject.ConcaveColliderLegacySteps, fracturedObject.Verbose, out nTotalTriangles) == false)
                    {
                        if(fracturedObject.Verbose)
                        {
                            Debug.Log(gameObject.name + ": Falling back to box collider");
                        }
                    }
                }
            }

            return nTotalTriangles;
	    }
 public void OnCreateFromFracturedObject(FracturedObject fracturedComponent, int nSplitSubMeshIndex)
 {
     FracturedObjectSource    = fracturedComponent;
     SplitSubMeshIndex        = nSplitSubMeshIndex;
     RandomMaterialColor      = new Color(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value, 0.7f);
     m_v3InitialLocalPosition = transform.localPosition;
 }
Exemple #5
0
    // Use this for initialization
    void Start()
    {
        fractureWall = gameObject.GetComponent <FracturedObject> ();

        fractureWall.TotalMass = Random.Range(2, 3);

        fractureWall.ChunkConnectionStrength = Random.Range(0.2f, 0.5f);
    }
Exemple #6
0
    public void ApplyFractures()
    {
        MeshFilter[] allChildren = GetComponentsInChildren <MeshFilter> ();
        List <float> floatlist   = new List <float> ();

        foreach (MeshFilter child in allChildren)
        {
            float volume = child.sharedMesh.bounds.size.x * child.sharedMesh.bounds.size.y * child.sharedMesh.bounds.size.z;
            floatlist.Add(volume);
        }

        floatlist.Sort();
        float listmin     = floatlist [0];
        float listmax     = floatlist [floatlist.Count - 1];
        float liststep    = (listmax - listmin) / (MaximumFracks - 2);
        int   liststepint = (int)liststep;

        foreach (MeshFilter child in allChildren)
        {
            fobj              = Instantiate(frack, PlaceForFractures);
            fobj.name         = child.name + "_frack";
            fobj.SourceObject = child.gameObject;
            fobj.RandomSeed   = Random.Range(0, 65536);
            //fobj.EventDetachMinMass = DetachValue;
            //fobj.EventDetachMinVelocity = DetachValue;
            fobj.SplitMaterial = InteriorMaterial;

            // Split Dimensions
            float dimsum = child.sharedMesh.bounds.size.x + child.sharedMesh.bounds.size.y + child.sharedMesh.bounds.size.z;
            fobj.SplitXProbability = child.sharedMesh.bounds.size.x / dimsum;
            fobj.SplitYProbability = child.sharedMesh.bounds.size.y / dimsum;
            fobj.SplitZProbability = child.sharedMesh.bounds.size.z / dimsum;
            fobj.SplitXVariation   = child.sharedMesh.bounds.size.x / dimsum;
            fobj.SplitYVariation   = child.sharedMesh.bounds.size.y / dimsum;
            fobj.SplitZVariation   = child.sharedMesh.bounds.size.z / dimsum;

            float volume = child.sharedMesh.bounds.size.x * child.sharedMesh.bounds.size.y * child.sharedMesh.bounds.size.z;
            fobj.TotalMass = volume * WeightMultiplier;
            //fobj.StartStatic = true;
            fobj.GenerateNumChunks = (int)(volume / liststepint) + 2;

            List <GameObject> listGameObjects;
            try
            {
                UltimateFracturing.Fracturer.FractureToChunks(fobj, true, out listGameObjects, Progress);
            }
            catch (System.Exception e)
            {
                Debug.LogError(string.Format("Exception computing chunks ({0}):\n{1}", e.Message, e.StackTrace));
            }

            EditorUtility.ClearProgressBar();
        }
    }
    void OnCollisionEnter(Collision collision)
    {
        if (collision.contacts == null)
        {
            return;
        }

        if (collision.contacts.Length == 0)
        {
            return;
        }

        // Was it a big enough hit?

        FracturedObject fracturedObject = gameObject.GetComponent <FracturedObject>();

        if (fracturedObject != null)
        {
            float fMass = collision.rigidbody != null ? collision.rigidbody.mass : Mathf.Infinity;

            if (collision.relativeVelocity.magnitude > fracturedObject.EventDetachMinVelocity && fMass > fracturedObject.EventDetachMinVelocity)
            {
                // Disable fracturable object collider

                fracturedObject.GetComponent <Collider>().enabled = false;

                Rigidbody fracturableRigidbody = fracturedObject.GetComponent <Rigidbody>();

                if (fracturableRigidbody != null)
                {
                    fracturableRigidbody.isKinematic = true;
                }

                // Enable chunk colliders

                for (int i = 0; i < fracturedObject.ListFracturedChunks.Count; i++)
                {
                    EnableObjectColliders(fracturedObject.ListFracturedChunks[i].gameObject, true);
                }

                // Explode

                fracturedObject.Explode(collision.contacts[0].point, collision.relativeVelocity.magnitude);
            }
        }
    }
Exemple #8
0
    public void ResetChunk(FracturedObject fracturedObjectSource)
    {
        transform.parent      = fracturedObjectSource.transform;
        rigidbody.isKinematic = true;
        IsNonSupportedChunk   = m_bNonSupportedChunkStored;

        FracturedObjectSource   = fracturedObjectSource;
        IsDetachedChunk         = false;
        transform.localPosition = m_v3InitialLocalPosition;

        if (m_bInitialLocalRotScaleInitialized)
        {
            transform.localRotation = m_qInitialLocalRotation;
            transform.localScale    = m_v3InitialLocalScale;
        }

        ListAdjacentChunks = new List <AdjacencyInfo>(ListAdjacentChunksCopy);
        m_fInvisibleTimer  = 0.0f;
    }
    public void OnSceneGUI()
    {
        FracturedChunk fracturedChunk = target as FracturedChunk;

        if (fracturedChunk == null)
        {
            return;
        }

        FracturedObject fracturedObject = fracturedChunk.FracturedObjectSource;

        // Chunk connections

        bool bDrawLines = true;

        if (fracturedObject != null)
        {
            bDrawLines = fracturedObject.ShowChunkConnectionLines;
        }

        if (bDrawLines)
        {
            Color handlesColor = Handles.color;
            Handles.color = new Color32(155, 89, 182, 255);

            if (fracturedChunk.ListAdjacentChunks.Count > 0)
            {
                Handles.DotHandleCap(0, fracturedChunk.transform.position, Quaternion.identity, HandleUtility.GetHandleSize(fracturedChunk.transform.position) * 0.03f, Event.current.type);
            }

            foreach (FracturedChunk.AdjacencyInfo chunkAdjacency in fracturedChunk.ListAdjacentChunks)
            {
                if (chunkAdjacency.chunk)
                {
                    Handles.DotHandleCap(0, chunkAdjacency.chunk.transform.position, Quaternion.identity, HandleUtility.GetHandleSize(chunkAdjacency.chunk.transform.position) * 0.03f, Event.current.type);
                    Handles.DrawLine(fracturedChunk.transform.position, chunkAdjacency.chunk.transform.position);
                }
            }

            Handles.color = handlesColor;
        }
    }
Exemple #10
0
    public override void updateLife(Damage d)
    {
        base.updateLife(d);

        if (lifeSlider != null)
        {
            lifeSlider.value = (float)(life) / maxLife;
        }

        if (isDead)
        {
            GetComponent <Collider>().enabled = false;
            FracturedObject f = transform.parent.GetComponentInChildren <FracturedObject>();
            if (f != null)
            {
                //Exploding the fractured object using Ultimate Game Tool fractured object
                f.SupportChunksAreIndestructible = false;
                f.Explode(new Vector3(transform.position.x, 0, transform.position.z), 100f, 100f, false, false, false, false);
            }
            Destroy(this.transform.parent.gameObject);
        }
    }
Exemple #11
0
    public void OnCreateFromFracturedObject(FracturedObject fracturedComponent, int nSplitSubMeshIndex)
    {
        FracturedObjectSource    = fracturedComponent;
        SplitSubMeshIndex        = nSplitSubMeshIndex;
        RandomMaterialColor      = new Color(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value, 0.7f);
        m_v3InitialLocalPosition = transform.localPosition;
        m_qInitialLocalRotation  = transform.localRotation;
        m_v3InitialLocalScale    = transform.localScale;

        m_bInitialLocalRotScaleInitialized = true;
    }
Exemple #12
0
    public void ResetChunk(FracturedObject fracturedObjectSource)
    {
        transform.parent      = fracturedObjectSource.transform;
        rigidbody.isKinematic = true;
        IsNonSupportedChunk   = m_bNonSupportedChunkStored;

        FracturedObjectSource   = fracturedObjectSource;
        IsDetachedChunk         = false;
        transform.localPosition = m_v3InitialLocalPosition;

        if(m_bInitialLocalRotScaleInitialized)
        {
            transform.localRotation = m_qInitialLocalRotation;
            transform.localScale    = m_v3InitialLocalScale;
        }

        ListAdjacentChunks      = new List<AdjacencyInfo>(ListAdjacentChunksCopy);
        m_fInvisibleTimer       = 0.0f;
    }
Exemple #13
0
    void OnCollisionEnter(Collision collision)
    {
        if (collision.contacts == null)
        {
            return;
        }

        if (collision.contacts.Length == 0)
        {
            return;
        }

        // Was it a big enough hit?

        FracturedObject fracturedObject = gameObject.GetComponent <FracturedObject>();

        if (fracturedObject != null)
        {
            float fMass = collision.rigidbody != null ? collision.rigidbody.mass : Mathf.Infinity;
            //Debug.Log (collision.gameObject.tag.ToString ());충돌체의 tag탐색
            //Debug.Log(collision.gameObject.GetComponent<FracturedObject>().EventDetachMinMass.ToString());
            if (collision.relativeVelocity.magnitude > fracturedObject.EventDetachMinVelocity && fMass > fracturedObject.EventDetachMinVelocity)
            {
                // Disable fracturable object collider
                if (collision.rigidbody != null)
                {
                    //SendKill (PhotonNetwork.player.ID);
                    fracturedObject.EventDetachMinMass -= collision.rigidbody.mass;
                }
                if (fracturedObject.EventDetachMinMass < 0)
                {
                    //Debug.Log (collision.gameObject.GetComponent<PhotonView> ().ownerId.ToString ());
                    //부순사람 카운트 업
                    SendKill(collision.gameObject.GetComponent <PhotonView> ().ownerId);
                    //부셔진돌 캔버스 제거
                    //DeleteName1 (fracturedObject,collision);
                    //fracturedObject.transform.Find("Canvas").GetComponent<Canvas>().enabled = false;
                    //Debug.Log (fracturedObject.name);
                    fracturedObject.GetComponent <Collider> ().enabled = false;

                    Rigidbody fracturableRigidbody = fracturedObject.GetComponent <Rigidbody> ();

                    if (fracturableRigidbody != null)
                    {
                        fracturableRigidbody.isKinematic = true;
                    }
                    for (int i = 0; i < fracturedObject.ListFracturedChunks.Count; i++)
                    {
                        EnableObjectColliders(fracturedObject.ListFracturedChunks[i].gameObject, true);
                    }

                    // Explode

                    fracturedObject.Explode(collision.contacts[0].point, collision.relativeVelocity.magnitude);
                    //죽은돌 삭제
                    GameObject delStone = GameObject.Find(fracturedObject.name);
                    Destroy(delStone);
                }
                // Enable chunk colliders
            }
        }
    }
 // Use this for initialization
 void Start()
 {
     mObject = GetComponent <FracturedObject>();
     GlobalEventManager.RegisterHandler("Bottle.Explode", ExplodeChunks);
 }
        private static bool ComputeHull(GameObject gameObject, FracturedObject.ECCAlgorithm eAlgorithm, int nMaxHulls, int nMaxHullVertices, int nLegacySteps, bool bVerbose, out int nTotalTrianglesOut)
        {
            MeshFilter theMesh = (MeshFilter)gameObject.GetComponent<MeshFilter>();

            DllInit(true);
            SetLogFunctionPointer(Marshal.GetFunctionPointerForDelegate(new LogDelegate(Log)));

            SConvexDecompositionInfoInOut info = new SConvexDecompositionInfoInOut();

            nTotalTrianglesOut = 0;

            if(theMesh)
            {
                if(theMesh.sharedMesh)
                {
                    uint uLegacySteps = (uint)(Mathf.Max(1, nLegacySteps));

                    info.uMaxHullVertices        = (uint)(Mathf.Max(3, nMaxHullVertices));
	                info.uMaxHulls               = (uint)nMaxHulls;
	                info.fPrecision              = 0.2f;
                    info.fBackFaceDistanceFactor = 0.2f;
                    info.uLegacyDepth            = eAlgorithm == FracturedObject.ECCAlgorithm.Legacy ? uLegacySteps : 0;
                    info.uNormalizeInputMesh     = 0;
                    info.uUseFastVersion         = eAlgorithm == FracturedObject.ECCAlgorithm.Fast ? (uint)1 : (uint)0;

	                info.uTriangleCount          = (uint)theMesh.sharedMesh.triangles.Length / 3;
                    info.uVertexCount            = (uint)theMesh.sharedMesh.vertexCount;

                    Vector3[] av3Vertices = theMesh.sharedMesh.vertices;

                    if(DoConvexDecomposition(ref info, av3Vertices, theMesh.sharedMesh.triangles))
                    {
                        for(int nHull = 0; nHull < info.nHullsOut; nHull++)
                        {
                            SConvexDecompositionHullInfo hullInfo = new SConvexDecompositionHullInfo();
                            GetHullInfo((uint)nHull, ref hullInfo);

                            if(hullInfo.nTriangleCount > 0)
                            {
							    Vector3[] hullVertices = new Vector3[hullInfo.nVertexCount];
                                int[]     hullIndices  = new int[hullInfo.nTriangleCount * 3];
							
							    float fHullVolume = -1.0f;

                                FillHullMeshData((uint)nHull, ref fHullVolume, hullIndices, hullVertices);

                                Mesh hullMesh = new Mesh();
                                hullMesh.vertices  = hullVertices;
                                hullMesh.triangles = hullIndices;
                                hullMesh.uv        = new Vector2[hullVertices.Length];
                                hullMesh.RecalculateNormals();

                                GameObject goNewHull = new GameObject("Hull " + (nHull + 1));
                                goNewHull.transform.position   = gameObject.transform.position;
                                goNewHull.transform.rotation   = gameObject.transform.rotation;
                                goNewHull.transform.localScale = gameObject.transform.localScale;
                                goNewHull.transform.parent     = gameObject.transform;
                                goNewHull.layer                = gameObject.layer;
                                MeshCollider meshCollider = goNewHull.AddComponent<MeshCollider>() as MeshCollider;

                                meshCollider.sharedMesh = null;
							    meshCollider.sharedMesh = hullMesh;
							    meshCollider.convex     = true;

                                nTotalTrianglesOut += hullInfo.nTriangleCount;
                            }
                            else
                            {
                                if(bVerbose)
                                {
                                    Debug.LogWarning(gameObject.name + ": Error generating collider. ComputeHull() returned 0 triangles.");
                                }
                            }
                        }

                        if(info.nHullsOut < 0 && bVerbose)
                        {
                            Debug.LogWarning(gameObject.name + ": Error generating collider. ComputeHull() returned no hulls.");
                        }
                    }
                    else
                    {
                        if(bVerbose)
                        {
                            Debug.LogWarning(gameObject.name + ": Error generating collider. ComputeHull() returned false.");
                        }
                    }
                }
            }

            DllClose();
            return nTotalTrianglesOut > 0;
        }
Exemple #16
0
        public SupportPlane(FracturedObject fracturedObject)
        {
            GUIExpanded    = true;
            GUIName        = "New Support Plane";
            GUIShowInScene = true;

            this.fracturedObject = fracturedObject;

            planeMesh = new Mesh();

            Vector3[] av3RectVerts = new Vector3[4];
            Vector3[] aRectNormals = new Vector3[4];
            Vector2[] aRectMapping = new Vector2[4];
            int[]     aRectIndices = { 0, 1, 2, 0, 2, 3 };

            av3RectVerts[0] = new Vector3(-1.0f, 0.0f, -1.0f);
            av3RectVerts[1] = new Vector3(-1.0f, 0.0f, +1.0f);
            av3RectVerts[2] = new Vector3(+1.0f, 0.0f, +1.0f);
            av3RectVerts[3] = new Vector3(+1.0f, 0.0f, -1.0f);

            aRectNormals[0] = new Vector3(0.0f, 1.0f, 0.0f);
            aRectNormals[1] = new Vector3(0.0f, 1.0f, 0.0f);
            aRectNormals[2] = new Vector3(0.0f, 1.0f, 0.0f);
            aRectNormals[3] = new Vector3(0.0f, 1.0f, 0.0f);

            bool  bHasRenderer = false;
            float fHeight      = 1.0f;

            if (fracturedObject.SourceObject)
            {
                if (fracturedObject.SourceObject.renderer)
                {
                    bHasRenderer = true;
                }
            }

            if (bHasRenderer)
            {
                Bounds bounds = fracturedObject.SourceObject.renderer.bounds;

                fHeight = bounds.extents.y;

                for (int i = 0; i < av3RectVerts.Length; i++)
                {
                    float fPlaneSize  = 1.3f;
                    float fMaxExtents = Mathf.Max(bounds.extents.z * fPlaneSize, bounds.extents.x * fPlaneSize);
                    av3RectVerts[i] = Vector3.Scale(av3RectVerts[i], new Vector3(fMaxExtents, fMaxExtents, fMaxExtents)) + fracturedObject.transform.position;
                    av3RectVerts[i] = fracturedObject.transform.InverseTransformPoint(av3RectVerts[i]);
                }

                v3PlanePosition = fracturedObject.transform.position - new Vector3(0.0f, fHeight - 0.05f, 0.0f);
                v3PlanePosition = fracturedObject.transform.InverseTransformPoint(v3PlanePosition);

                qPlaneRotation = Quaternion.identity;
            }
            else
            {
                for (int i = 0; i < av3RectVerts.Length; i++)
                {
                    av3RectVerts[i] += fracturedObject.transform.position;
                    av3RectVerts[i]  = fracturedObject.transform.InverseTransformPoint(av3RectVerts[i]);
                }

                v3PlanePosition = new Vector3(0.0f, (-fHeight * 0.5f) + 0.05f, 0.0f);
                qPlaneRotation  = Quaternion.identity;
            }

            v3PlaneScale = Vector3.one;

            planeMesh.vertices  = av3RectVerts;
            planeMesh.normals   = aRectNormals;
            planeMesh.uv        = aRectMapping;
            planeMesh.triangles = aRectIndices;
        }
        public static bool SplitMeshUsingPlane(GameObject gameObjectIn, FracturedObject fracturedComponent, SplitOptions splitOptions, Transform transformPlaneSplit, out List<GameObject> listGameObjectsPosOut, out List<GameObject> listGameObjectsNegOut, ProgressDelegate progress = null)
        {
            listGameObjectsPosOut = new List<GameObject>();
            listGameObjectsNegOut = new List<GameObject>();

            MeshFilter meshfIn = gameObjectIn.GetComponent<MeshFilter>();

            if(meshfIn == null)
            {
                return false;
            }

            foreach(FracturedChunk chunk in fracturedComponent.ListFracturedChunks)
            {
                if(chunk != null)
                {
                    UnityEngine.Object.DestroyImmediate(chunk.gameObject);
                }
            }

            fracturedComponent.ListFracturedChunks.Clear();
            fracturedComponent.DecomposeRadius = (meshfIn.sharedMesh.bounds.max - meshfIn.sharedMesh.bounds.min).magnitude;
            Random.seed = fracturedComponent.RandomSeed;

//            Debug.Log("In: " + gameObjectIn.name + ": " + meshfIn.sharedMesh.subMeshCount + " submeshes, " + ": " + (meshfIn.sharedMesh.triangles.Length / 3) + " triangles, " + meshfIn.sharedMesh.vertexCount + " vertices, " + (meshfIn.sharedMesh.uv != null ? meshfIn.sharedMesh.uv.Length : 0) + " uv1, " + (meshfIn.sharedMesh.uv2 != null ? meshfIn.sharedMesh.uv2.Length : 0) + " uv2");

            // Check if the input object already has been split, to get its split closing submesh

            FracturedChunk fracturedChunk = gameObjectIn.GetComponent<FracturedChunk>();

            int nSplitCloseSubMesh = fracturedChunk != null ? fracturedChunk.SplitSubMeshIndex : -1;

            if(nSplitCloseSubMesh == -1 && gameObjectIn.GetComponent<Renderer>())
            {
                // Check if its material is the same as the split material

                if(gameObjectIn.GetComponent<Renderer>().sharedMaterial == fracturedComponent.SplitMaterial)
                {
                    nSplitCloseSubMesh = 0;
                }
            }

            List<MeshData> listMeshDatasPos;
            List<MeshData> listMeshDatasNeg;

            Material[] aMaterials = fracturedComponent.gameObject.GetComponent<Renderer>() ? fracturedComponent.gameObject.GetComponent<Renderer>().sharedMaterials : null;

            MeshData meshDataIn = new MeshData(meshfIn.transform, meshfIn.sharedMesh, aMaterials, meshfIn.transform.localToWorldMatrix, !splitOptions.bVerticesAreLocal, nSplitCloseSubMesh, true);

            if(SplitMeshUsingPlane(meshDataIn, fracturedComponent, splitOptions, transformPlaneSplit.up, transformPlaneSplit.right, transformPlaneSplit.position, out listMeshDatasPos, out listMeshDatasNeg, progress) == false)
            {
                return false;
            }

            // Set the mesh properties and add objects to list

            if(listMeshDatasPos.Count > 0)
            {
                for(int nMeshCount = 0; nMeshCount < listMeshDatasPos.Count; nMeshCount++)
                {
                    GameObject goPos = CreateNewSplitGameObject(gameObjectIn, fracturedComponent, gameObjectIn.name + "0" + (listMeshDatasPos.Count > 1 ? ("(" + nMeshCount + ")") : ""), !splitOptions.bVerticesAreLocal, listMeshDatasPos[nMeshCount]);
                    listGameObjectsPosOut.Add(goPos);
                }
            }

            if(listMeshDatasNeg.Count > 0)
            {
                for(int nMeshCount = 0; nMeshCount < listMeshDatasNeg.Count; nMeshCount++)
                {
                    GameObject goNeg = CreateNewSplitGameObject(gameObjectIn, fracturedComponent, gameObjectIn.name + "1" + (listMeshDatasNeg.Count > 1 ? ("(" + nMeshCount + ")") : ""), !splitOptions.bVerticesAreLocal, listMeshDatasNeg[nMeshCount]);
                    listGameObjectsNegOut.Add(goNeg);
                }
            }

            return true;
        }
Exemple #18
0
        static void TriangulateConstrainedDelaunay(List <List <Vector3> > listlistPointsConstrainedDelaunay, List <List <int> > listlistHashValuesConstrainedDelaunay, bool bForceVertexSoup, FracturedObject fracturedComponent,
                                                   bool bConnectivityPostprocess, MeshFaceConnectivity faceConnectivityPos, MeshFaceConnectivity faceConnectivityNeg, MeshDataConnectivity meshConnectivityPos, MeshDataConnectivity meshConnectivityNeg, int nForceMeshConnectivityHash,
                                                   int nSplitCloseSubMesh, Matrix4x4 mtxPlane, Matrix4x4 mtxToLocalPos, Matrix4x4 mtxToLocalNeg, Vector3 v3CenterPos, Vector3 v3CenterNeg,
                                                   List <int>[] aListIndicesPosInOut, List <VertexData> listVertexDataPosInOut, List <int>[] aListIndicesNegInOut, List <VertexData> listVertexDataNegInOut)
        {
            // Pass to two dimensional plane:

            Matrix4x4 mtxPlaneInverse = mtxPlane.inverse;
            List <List <Poly2Tri.Point2D> >      listlistCapPoints        = new List <List <Poly2Tri.Point2D> >();
            List <List <Poly2Tri.PolygonPoint> > listlistCapPolygonPoints = new List <List <Poly2Tri.PolygonPoint> >();
            List <Poly2Tri.Polygon> listCapPolygons = new List <Poly2Tri.Polygon>();

            for (int i = 0; i < listlistPointsConstrainedDelaunay.Count; i++)
            {
                List <Poly2Tri.Point2D>      listCapPoints         = new List <Poly2Tri.Point2D>();
                List <Poly2Tri.PolygonPoint> listCapPolygonsPoints = new List <Poly2Tri.PolygonPoint>();

                foreach (Vector3 v3Vertex in listlistPointsConstrainedDelaunay[i])
                {
                    Vector3 v3VertexInPlane = mtxPlaneInverse.MultiplyPoint3x4(v3Vertex);
                    listCapPoints.Add(new Poly2Tri.Point2D(v3VertexInPlane.x, v3VertexInPlane.z));
                    listCapPolygonsPoints.Add(new Poly2Tri.PolygonPoint(v3VertexInPlane.x, v3VertexInPlane.z));
                }

                listlistCapPoints.Add(listCapPoints);
                listlistCapPolygonPoints.Add(listCapPolygonsPoints);
                listCapPolygons.Add(new Poly2Tri.Polygon(listCapPolygonsPoints));
            }

            // Remove close vertices

            float fPrecisionFix = Mathf.Max(Parameters.EPSILONCAPPRECISIONMIN, fracturedComponent.CapPrecisionFix);

            if (fPrecisionFix > 0.0f)
            {
                for (int nCap = 0; nCap < listlistCapPolygonPoints.Count; nCap++)
                {
                    double lastX = listlistCapPolygonPoints[nCap][listlistCapPolygonPoints[nCap].Count - 1].X;
                    double lastY = listlistCapPolygonPoints[nCap][listlistCapPolygonPoints[nCap].Count - 1].Y;

                    bool bDeleteCap = false;

                    for (int nVertex = 0; nVertex < listlistCapPolygonPoints[nCap].Count; nVertex++)
                    {
                        double vecX = listlistCapPolygonPoints[nCap][nVertex].X - lastX;
                        double vecY = listlistCapPolygonPoints[nCap][nVertex].Y - lastY;

                        if (System.Math.Sqrt(vecX * vecX + vecY * vecY) < fPrecisionFix)
                        {
                            listlistCapPolygonPoints[nCap].RemoveAt(nVertex);
                            nVertex--;

                            if (listlistCapPolygonPoints[nCap].Count < 3)
                            {
                                bDeleteCap = true;
                                break;
                            }
                        }
                        else
                        {
                            lastX = listlistCapPolygonPoints[nCap][nVertex].X;
                            lastY = listlistCapPolygonPoints[nCap][nVertex].Y;
                        }
                    }

                    if (bDeleteCap)
                    {
                        listlistCapPolygonPoints.RemoveAt(nCap);
                        nCap--;
                    }
                }
            }

            if (listlistCapPolygonPoints.Count == 0)
            {
                return;
            }

            // Search if one of the caps is contained in the other. If this happens we will mark the big one as the polygon and the rest as holes

            int nSuperPolygon = -1;

            Poly2Tri.Polygon polygonContainer = null;

            if (bForceVertexSoup == false)
            {
                for (int i = 0; i < listlistCapPolygonPoints.Count; i++)
                {
                    for (int j = 0; j < listlistCapPolygonPoints.Count; j++)
                    {
                        if (i != j && listlistCapPoints[i].Count >= 3 && listlistCapPoints[j].Count >= 3)
                        {
                            if (Poly2Tri.PolygonUtil.PolygonContainsPolygon(listlistCapPoints[i], listCapPolygons[i].Bounds, listlistCapPoints[j], listCapPolygons[j].Bounds, true))
                            {
                                nSuperPolygon = i;
                                break;
                            }
                            else if (Poly2Tri.PolygonUtil.PolygonContainsPolygon(listlistCapPoints[j], listCapPolygons[j].Bounds, listlistCapPoints[i], listCapPolygons[i].Bounds, true))
                            {
                                nSuperPolygon = j;
                                break;
                            }
                        }
                    }
                }

                // Add holes if this is a cap with holes

                if (nSuperPolygon != -1)
                {
                    polygonContainer = listCapPolygons[nSuperPolygon];

                    for (int i = 0; i < listlistCapPolygonPoints.Count; i++)
                    {
                        if (i != nSuperPolygon && listCapPolygons[i].Count >= 3)
                        {
                            polygonContainer.AddHole(listCapPolygons[i]);
                        }
                    }
                }
            }

            // Triangulate

            bool bTriangulatedWithHoles = false;

            if (polygonContainer != null && bForceVertexSoup == false)
            {
                // Polygon with holes

                try
                {
                    Poly2Tri.P2T.Triangulate(polygonContainer);

                    if (polygonContainer.Triangles != null)
                    {
                        List <Vector3> listMeshVertices = new List <Vector3>();
                        List <int>     listMeshIndices  = new List <int>();

                        CreateIndexedMesh(polygonContainer.Triangles, listMeshVertices, listMeshIndices, mtxPlane, true);

                        Triangulate(listMeshVertices, listMeshIndices, fracturedComponent, listlistPointsConstrainedDelaunay, listlistHashValuesConstrainedDelaunay,
                                    bConnectivityPostprocess, faceConnectivityPos, faceConnectivityNeg, meshConnectivityPos, meshConnectivityNeg, nForceMeshConnectivityHash,
                                    nSplitCloseSubMesh, mtxPlane, mtxToLocalPos, mtxToLocalNeg, v3CenterPos, v3CenterNeg,
                                    aListIndicesPosInOut, listVertexDataPosInOut, aListIndicesNegInOut, listVertexDataNegInOut);
                    }

                    bTriangulatedWithHoles = true;
                }
                catch (System.Exception e)
                {
                    if (fracturedComponent.Verbose)
                    {
                        Debug.LogWarning("Exception (" + e.GetType() + ") using hole triangulation (holes = " + listlistCapPolygonPoints.Count + "). Trying to use constrained delaunay.");
                    }
                    bTriangulatedWithHoles = false;
                }
            }

            if (bTriangulatedWithHoles == false)
            {
                if (bForceVertexSoup)
                {
                    // Vertex soup

                    List <Poly2Tri.TriangulationPoint> listPoints = new List <Poly2Tri.TriangulationPoint>();

                    if (listlistCapPolygonPoints.Count > 0)
                    {
                        foreach (Poly2Tri.PolygonPoint polyPoint in listlistCapPolygonPoints[0])
                        {
                            listPoints.Add(polyPoint);
                        }

                        try
                        {
                            if (listPoints.Count >= 3)
                            {
                                Poly2Tri.PointSet ps = new Poly2Tri.PointSet(listPoints);
                                Poly2Tri.P2T.Triangulate(ps);

                                if (ps.Triangles != null)
                                {
                                    List <Vector3> listMeshVertices = new List <Vector3>();
                                    List <int>     listMeshIndices  = new List <int>();

                                    CreateIndexedMesh(ps.Triangles, listMeshVertices, listMeshIndices, mtxPlane, true);

                                    Triangulate(listMeshVertices, listMeshIndices, fracturedComponent, listlistPointsConstrainedDelaunay, listlistHashValuesConstrainedDelaunay,
                                                bConnectivityPostprocess, faceConnectivityPos, faceConnectivityNeg, meshConnectivityPos, meshConnectivityNeg, nForceMeshConnectivityHash,
                                                nSplitCloseSubMesh, mtxPlane, mtxToLocalPos, mtxToLocalNeg, v3CenterPos, v3CenterNeg,
                                                aListIndicesPosInOut, listVertexDataPosInOut, aListIndicesNegInOut, listVertexDataNegInOut);
                                }
                            }
                        }
                        catch (System.Exception e)
                        {
                            if (fracturedComponent.Verbose)
                            {
                                Debug.LogWarning("Exception (" + e.GetType() + ") using vertex soup triangulation.");
                            }
                        }
                    }
                }
                else
                {
                    // Use constrained delaunay triangulation

                    int nPoly = 0;

                    foreach (List <Poly2Tri.PolygonPoint> listPolyPoints in listlistCapPolygonPoints)
                    {
                        IList <Poly2Tri.DelaunayTriangle> listTriangles = null;

                        Poly2Tri.Polygon polygon = null;

                        try
                        {
                            if (listPolyPoints.Count >= 3)
                            {
                                polygon = new Poly2Tri.Polygon(listPolyPoints);
                                Poly2Tri.P2T.Triangulate(polygon);
                                listTriangles = polygon.Triangles;
                            }
                        }
                        catch (System.Exception e)
                        {
                            if (fracturedComponent.Verbose)
                            {
                                Debug.LogWarning("Exception (" + e.GetType() + ") using polygon triangulation of cap polygon " + nPoly + ". Trying to use non constrained");
                            }
                            listTriangles = null;
                        }

                        if (listTriangles == null)
                        {
                            List <Poly2Tri.TriangulationPoint> listPoints = new List <Poly2Tri.TriangulationPoint>();

                            foreach (Poly2Tri.PolygonPoint polyPoint in listPolyPoints)
                            {
                                listPoints.Add(polyPoint);
                            }

                            try
                            {
                                if (listPoints.Count >= 3)
                                {
                                    Poly2Tri.PointSet ps = new Poly2Tri.PointSet(listPoints);
                                    Poly2Tri.P2T.Triangulate(ps);
                                    listTriangles = ps.Triangles;
                                }
                            }
                            catch (System.Exception e)
                            {
                                if (fracturedComponent.Verbose)
                                {
                                    Debug.LogWarning("Exception (" + e.GetType() + ") using non constrained triangulation of cap polygon " + nPoly + ". Skipping");
                                }
                            }
                        }

                        if (listTriangles != null)
                        {
                            List <Vector3> listMeshVertices = new List <Vector3>();
                            List <int>     listMeshIndices  = new List <int>();

                            CreateIndexedMesh(listTriangles, listMeshVertices, listMeshIndices, mtxPlane, true);

                            Triangulate(listMeshVertices, listMeshIndices, fracturedComponent, listlistPointsConstrainedDelaunay, listlistHashValuesConstrainedDelaunay,
                                        bConnectivityPostprocess, faceConnectivityPos, faceConnectivityNeg, meshConnectivityPos, meshConnectivityNeg, nForceMeshConnectivityHash,
                                        nSplitCloseSubMesh, mtxPlane, mtxToLocalPos, mtxToLocalNeg, v3CenterPos, v3CenterNeg,
                                        aListIndicesPosInOut, listVertexDataPosInOut, aListIndicesNegInOut, listVertexDataNegInOut);
                        }

                        nPoly++;
                    }
                }
            }
        }
Exemple #19
0
            public static SpaceTreeNode BuildSpaceTree(MeshData meshDataIn, int nSubdivisionLevels, FracturedObject fracturedComponent, ProgressDelegate progress = null)
            {
                if(nSubdivisionLevels < 1)
                {
                    return null;
                }

                SplitOptions splitOptions = new SplitOptions();

                splitOptions.bForceNoIslandGeneration     = true;
                splitOptions.bForceNoChunkConnectionInfo  = true;            
                splitOptions.bForceNoIslandConnectionInfo = true;
                splitOptions.bForceNoCap                  = false;
                splitOptions.bVerticesAreLocal            = true;

                SpaceTreeNode nodeRoot = new SpaceTreeNode();

                nodeRoot.listMeshDatasSpace = new List<MeshData>();
                nodeRoot.listMeshDatasSpace.Add(meshDataIn);
                nodeRoot.nLevel   = 0;
                nodeRoot.nSplitsX = 0;
                nodeRoot.nSplitsY = 0;
                nodeRoot.nSplitsZ = 0;
                nodeRoot.v3Min    = meshDataIn.v3Min;
                nodeRoot.v3Max    = meshDataIn.v3Max;

                Queue<SpaceTreeNode> queueNodes = new Queue<SpaceTreeNode>();
                queueNodes.Enqueue(nodeRoot);

                int nTotalSubdivisions   = 0;
                int nCurrentSubdivisions = 0;
                int nSplitsX             = 0;
                int nSplitsY             = 0;
                int nSplitsZ             = 0;
                
                for(int i = 0; i < nSubdivisionLevels; i++)
                {
                    nTotalSubdivisions += Mathf.RoundToInt(Mathf.Pow(2, i));
                }

                while(queueNodes.Count > 0)
                {
                    SpaceTreeNode nodeCurrent = queueNodes.Dequeue();

                    List<MeshData> listMeshDataPos;
                    List<MeshData> listMeshDataNeg;

                    if(nodeCurrent.nLevel < nSubdivisionLevels)
                    {
                        if(progress != null)
                        {
                            progress("Fracturing", string.Format("Pre computing space volume (split {0}/{1}, Depth {2})", nCurrentSubdivisions + 1, nTotalSubdivisions, nodeCurrent.nLevel + 1), Mathf.Clamp01((float)nCurrentSubdivisions / (float)nTotalSubdivisions));
                        }

                        if(Fracturer.IsFracturingCancelled())
                        {
                            return null;
                        }

                        Vector3 v3Normal = Vector3.up;
                        Vector3 v3Right  = Vector3.right;
                        Vector3 v3Pos    = (nodeCurrent.v3Min + nodeCurrent.v3Max) * 0.5f;

                        float fSizeX = nodeCurrent.v3Max.x - nodeCurrent.v3Min.x;
                        float fSizeY = nodeCurrent.v3Max.y - nodeCurrent.v3Min.y;
                        float fSizeZ = nodeCurrent.v3Max.z - nodeCurrent.v3Min.z;

                        Vector3 v3MinNeg = nodeCurrent.v3Min;
                        Vector3 v3MaxNeg = nodeCurrent.v3Max;
                        Vector3 v3MinPos = nodeCurrent.v3Min;
                        Vector3 v3MaxPos = nodeCurrent.v3Max;

                        if(fSizeX >= fSizeY && fSizeX >= fSizeZ)
                        {
                            v3Normal = Vector3.right;
                            v3Right  = Vector3.forward;

                            v3MaxNeg.x = v3Pos.x;
                            v3MinPos.x = v3Pos.x;

                            nSplitsX++;
                        }
                        else if(fSizeY >= fSizeX && fSizeY >= fSizeZ)
                        {
                            v3Normal = Vector3.up;
                            v3Right  = Vector3.right;

                            v3MaxNeg.y = v3Pos.y;
                            v3MinPos.y = v3Pos.y;

                            nSplitsY++;
                        }
                        else
                        {
                            v3Normal = Vector3.forward;
                            v3Right  = Vector3.right;

                            v3MaxNeg.z = v3Pos.z;
                            v3MinPos.z = v3Pos.z;

                            nSplitsZ++;
                        }

                        foreach(MeshData meshData in nodeCurrent.listMeshDatasSpace)
                        {
                            if(SplitMeshUsingPlane(meshData, fracturedComponent, splitOptions, v3Normal, v3Right, v3Pos, out listMeshDataPos, out listMeshDataNeg, progress) == true)
                            {
                                nodeCurrent.nodeOneSide = new SpaceTreeNode();
                                nodeCurrent.nodeOneSide.listMeshDatasSpace = listMeshDataNeg;
                                nodeCurrent.nodeOneSide.v3Min    = v3MinNeg;
                                nodeCurrent.nodeOneSide.v3Max    = v3MaxNeg;
                                nodeCurrent.nodeOneSide.nLevel   = nodeCurrent.nLevel + 1;
                                nodeCurrent.nodeOneSide.nSplitsX = nSplitsX;
                                nodeCurrent.nodeOneSide.nSplitsY = nSplitsY;
                                nodeCurrent.nodeOneSide.nSplitsZ = nSplitsZ;

                                queueNodes.Enqueue(nodeCurrent.nodeOneSide);

                                nodeCurrent.nodeOtherSide = new SpaceTreeNode();
                                nodeCurrent.nodeOtherSide.listMeshDatasSpace = listMeshDataPos;
                                nodeCurrent.nodeOtherSide.v3Min    = v3MinPos;
                                nodeCurrent.nodeOtherSide.v3Max    = v3MaxPos;
                                nodeCurrent.nodeOtherSide.nLevel   = nodeCurrent.nLevel + 1;
                                nodeCurrent.nodeOtherSide.nSplitsX = nSplitsX;
                                nodeCurrent.nodeOtherSide.nSplitsY = nSplitsY;
                                nodeCurrent.nodeOtherSide.nSplitsZ = nSplitsZ;

                                queueNodes.Enqueue(nodeCurrent.nodeOtherSide);
                            }
                        }

                        nCurrentSubdivisions++;
                    }
                }

                return nodeRoot;
            }
Exemple #20
0
        static void TriangulateConstrainedDelaunay( List<List<Vector3>> listlistPointsConstrainedDelaunay, List<List<int>> listlistHashValuesConstrainedDelaunay, bool bForceVertexSoup, FracturedObject fracturedComponent,
                                                    bool bConnectivityPostprocess, MeshFaceConnectivity faceConnectivityPos, MeshFaceConnectivity faceConnectivityNeg, MeshDataConnectivity meshConnectivityPos, MeshDataConnectivity meshConnectivityNeg, int nForceMeshConnectivityHash,
                                                    int nSplitCloseSubMesh, Matrix4x4 mtxPlane, Matrix4x4 mtxToLocalPos, Matrix4x4 mtxToLocalNeg, Vector3 v3CenterPos, Vector3 v3CenterNeg,
                                                    List<int>[] aListIndicesPosInOut, List<VertexData> listVertexDataPosInOut, List<int>[] aListIndicesNegInOut, List<VertexData> listVertexDataNegInOut)
        {
            // Pass to two dimensional plane:

            Matrix4x4 mtxPlaneInverse = mtxPlane.inverse;
            List<List<Poly2Tri.Point2D>>      listlistCapPoints        = new List<List<Poly2Tri.Point2D>>();
            List<List<Poly2Tri.PolygonPoint>> listlistCapPolygonPoints = new List<List<Poly2Tri.PolygonPoint>>();
            List<Poly2Tri.Polygon>            listCapPolygons          = new List<Poly2Tri.Polygon>();

            for(int i = 0; i < listlistPointsConstrainedDelaunay.Count; i++)
            {
                List<Poly2Tri.Point2D>      listCapPoints         = new List<Poly2Tri.Point2D>();
                List<Poly2Tri.PolygonPoint> listCapPolygonsPoints = new List<Poly2Tri.PolygonPoint>();

                foreach(Vector3 v3Vertex in listlistPointsConstrainedDelaunay[i])
                {
                    Vector3 v3VertexInPlane = mtxPlaneInverse.MultiplyPoint3x4(v3Vertex);
                    listCapPoints.Add        (new Poly2Tri.Point2D     (v3VertexInPlane.x, v3VertexInPlane.z));
                    listCapPolygonsPoints.Add(new Poly2Tri.PolygonPoint(v3VertexInPlane.x, v3VertexInPlane.z));
                }

                listlistCapPoints.Add(listCapPoints);
                listlistCapPolygonPoints.Add(listCapPolygonsPoints);
                listCapPolygons.Add(new Poly2Tri.Polygon(listCapPolygonsPoints));
            }

            // Remove close vertices

            float fPrecisionFix = Mathf.Max(Parameters.EPSILONCAPPRECISIONMIN, fracturedComponent.CapPrecisionFix);

            if(fPrecisionFix > 0.0f)
            {
                for(int nCap = 0; nCap < listlistCapPolygonPoints.Count; nCap++)
                {
                    double lastX = listlistCapPolygonPoints[nCap][listlistCapPolygonPoints[nCap].Count - 1].X;
                    double lastY = listlistCapPolygonPoints[nCap][listlistCapPolygonPoints[nCap].Count - 1].Y;

                    bool bDeleteCap = false;

                    for(int nVertex = 0; nVertex < listlistCapPolygonPoints[nCap].Count; nVertex++)
                    {
                        double vecX = listlistCapPolygonPoints[nCap][nVertex].X - lastX;
                        double vecY = listlistCapPolygonPoints[nCap][nVertex].Y - lastY;

                        if(System.Math.Sqrt(vecX * vecX + vecY * vecY) < fPrecisionFix)
                        {
                            listlistCapPolygonPoints[nCap].RemoveAt(nVertex);
                            nVertex--;

                            if(listlistCapPolygonPoints[nCap].Count < 3)
                            {
                                bDeleteCap = true;
                                break;
                            }
                        }
                        else
                        {
                            lastX = listlistCapPolygonPoints[nCap][nVertex].X;
                            lastY = listlistCapPolygonPoints[nCap][nVertex].Y;
                        }
                    }

                    if(bDeleteCap)
                    {
                        listlistCapPolygonPoints.RemoveAt(nCap);
                        nCap--;
                    }
                }
            }

            if(listlistCapPolygonPoints.Count == 0)
            {
                return;
            }

            // Search if one of the caps is contained in the other. If this happens we will mark the big one as the polygon and the rest as holes

            int nSuperPolygon = -1;
            Poly2Tri.Polygon polygonContainer = null;

            if(bForceVertexSoup == false)
            {
                for(int i = 0; i < listlistCapPolygonPoints.Count; i++)
                {
                    for(int j = 0; j < listlistCapPolygonPoints.Count; j++)
                    {
                        if(i != j && listlistCapPoints[i].Count >= 3 && listlistCapPoints[j].Count >= 3)
                        {
                            if(Poly2Tri.PolygonUtil.PolygonContainsPolygon(listlistCapPoints[i], listCapPolygons[i].Bounds, listlistCapPoints[j], listCapPolygons[j].Bounds, true))
                            {
                                nSuperPolygon = i;
                                break;
                            }
                            else if(Poly2Tri.PolygonUtil.PolygonContainsPolygon(listlistCapPoints[j], listCapPolygons[j].Bounds, listlistCapPoints[i], listCapPolygons[i].Bounds, true))
                            {
                                nSuperPolygon = j;
                                break;
                            }
                        }
                    }
                }

                // Add holes if this is a cap with holes

                if(nSuperPolygon != -1)
                {
                    polygonContainer = listCapPolygons[nSuperPolygon];

                    for(int i = 0; i < listlistCapPolygonPoints.Count; i++)
                    {
                        if(i != nSuperPolygon && listCapPolygons[i].Count >= 3)
                        {
                            polygonContainer.AddHole(listCapPolygons[i]);
                        }
                    }
                }
            }

            // Triangulate

            bool bTriangulatedWithHoles = false;

            if(polygonContainer != null && bForceVertexSoup == false)
            {
                // Polygon with holes

                try
                {
                    Poly2Tri.P2T.Triangulate(polygonContainer);

                    if(polygonContainer.Triangles != null)
                    {
                        List<Vector3> listMeshVertices = new List<Vector3>();
                        List<int>     listMeshIndices  = new List<int>();

                        CreateIndexedMesh(polygonContainer.Triangles, listMeshVertices, listMeshIndices, mtxPlane, true);

                        Triangulate(    listMeshVertices, listMeshIndices, fracturedComponent, listlistPointsConstrainedDelaunay, listlistHashValuesConstrainedDelaunay,
                                        bConnectivityPostprocess, faceConnectivityPos, faceConnectivityNeg, meshConnectivityPos, meshConnectivityNeg, nForceMeshConnectivityHash,
                                        nSplitCloseSubMesh, mtxPlane, mtxToLocalPos, mtxToLocalNeg, v3CenterPos, v3CenterNeg,
                                        aListIndicesPosInOut, listVertexDataPosInOut, aListIndicesNegInOut, listVertexDataNegInOut);
                    }

                    bTriangulatedWithHoles = true;
                }
                catch(System.Exception e)
                {
                    if(fracturedComponent.Verbose) Debug.LogWarning("Exception (" + e.GetType() + ") using hole triangulation (holes = " + listlistCapPolygonPoints.Count + "). Trying to use constrained delaunay.");
                    bTriangulatedWithHoles = false;
                }
            }

            if(bTriangulatedWithHoles == false)
            {
                if(bForceVertexSoup)
                {
                    // Vertex soup

                    List<Poly2Tri.TriangulationPoint> listPoints = new List<Poly2Tri.TriangulationPoint>();

                    if(listlistCapPolygonPoints.Count > 0)
                    {
                        foreach(Poly2Tri.PolygonPoint polyPoint in listlistCapPolygonPoints[0])
                        {
                            listPoints.Add(polyPoint);
                        }

                        try
                        {
                            if(listPoints.Count >= 3)
                            {
                                Poly2Tri.PointSet ps = new Poly2Tri.PointSet(listPoints);
                                Poly2Tri.P2T.Triangulate(ps);

                                if(ps.Triangles != null)
                                {
                                    List<Vector3> listMeshVertices = new List<Vector3>();
                                    List<int>     listMeshIndices  = new List<int>();

                                    CreateIndexedMesh(ps.Triangles, listMeshVertices, listMeshIndices, mtxPlane, true);

                                    Triangulate(    listMeshVertices, listMeshIndices, fracturedComponent, listlistPointsConstrainedDelaunay, listlistHashValuesConstrainedDelaunay,
                                                    bConnectivityPostprocess, faceConnectivityPos, faceConnectivityNeg, meshConnectivityPos, meshConnectivityNeg, nForceMeshConnectivityHash,
                                                    nSplitCloseSubMesh, mtxPlane, mtxToLocalPos, mtxToLocalNeg, v3CenterPos, v3CenterNeg,
                                                    aListIndicesPosInOut, listVertexDataPosInOut, aListIndicesNegInOut, listVertexDataNegInOut);
                                }
                            }
                        }
                        catch(System.Exception e)
                        {
                            if(fracturedComponent.Verbose) Debug.LogWarning("Exception (" + e.GetType() + ") using vertex soup triangulation.");
                        }
                    }
                }
                else
                {
                    // Use constrained delaunay triangulation

                    int nPoly = 0;

                    foreach(List<Poly2Tri.PolygonPoint> listPolyPoints in listlistCapPolygonPoints)
                    {
                        IList<Poly2Tri.DelaunayTriangle> listTriangles = null;

                        Poly2Tri.Polygon polygon = null;

                        try
                        {
                            if(listPolyPoints.Count >= 3)
                            {
                                polygon = new Poly2Tri.Polygon(listPolyPoints);
                                Poly2Tri.P2T.Triangulate(polygon);
                                listTriangles = polygon.Triangles;
                            }
                        }
                        catch(System.Exception e)
                        {
                            if(fracturedComponent.Verbose) Debug.LogWarning("Exception (" + e.GetType() + ") using polygon triangulation of cap polygon " + nPoly + ". Trying to use non constrained");
                            listTriangles = null;
                        }

                        if(listTriangles == null)
                        {
                            List<Poly2Tri.TriangulationPoint> listPoints = new List<Poly2Tri.TriangulationPoint>();

                            foreach(Poly2Tri.PolygonPoint polyPoint in listPolyPoints)
                            {
                                listPoints.Add(polyPoint);
                            }

                            try
                            {
                                if(listPoints.Count >= 3)
                                {
                                    Poly2Tri.PointSet ps = new Poly2Tri.PointSet(listPoints);
                                    Poly2Tri.P2T.Triangulate(ps);
                                    listTriangles = ps.Triangles;
                                }
                            }
                            catch(System.Exception e)
                            {
                                if(fracturedComponent.Verbose) Debug.LogWarning("Exception (" + e.GetType() + ") using non constrained triangulation of cap polygon " + nPoly + ". Skipping");
                            }
                        }

                        if(listTriangles != null)
                        {
                            List<Vector3> listMeshVertices = new List<Vector3>();
                            List<int>     listMeshIndices  = new List<int>();

                            CreateIndexedMesh(listTriangles, listMeshVertices, listMeshIndices, mtxPlane, true);

                            Triangulate(    listMeshVertices, listMeshIndices, fracturedComponent, listlistPointsConstrainedDelaunay, listlistHashValuesConstrainedDelaunay,
                                            bConnectivityPostprocess, faceConnectivityPos, faceConnectivityNeg, meshConnectivityPos, meshConnectivityNeg, nForceMeshConnectivityHash,
                                            nSplitCloseSubMesh, mtxPlane, mtxToLocalPos, mtxToLocalNeg, v3CenterPos, v3CenterNeg,
                                            aListIndicesPosInOut, listVertexDataPosInOut, aListIndicesNegInOut, listVertexDataNegInOut);
                        }

                        nPoly++;
                    }
                }
            }
        }
Exemple #21
0
        static bool ResolveCap(Dictionary<EdgeKeyByHash, CapEdge> dicCapEdges, List<List<Vector3>> listlistResolvedCapVertices, List<List<int>> listlistResolvedCapHashValues, FracturedObject fracturedComponent)
        {
	        if(dicCapEdges.Count < 3)
	        {
                if(fracturedComponent.Verbose) Debug.LogWarning("Cap has < 3 segments");
		        return false;
	        }

            listlistResolvedCapVertices.Clear();
            listlistResolvedCapHashValues.Clear();

            List<CapEdge> listResolvedCap   = new List<CapEdge>();
            List<CapEdge> listUnresolvedCap = new List<CapEdge>(dicCapEdges.Values);
            List<Vector3> newListVertices   = new List<Vector3>();
            List<int>     newListHashValues = new List<int>();

            int nTotalSegments = listUnresolvedCap.Count;

            listResolvedCap.Add(listUnresolvedCap[0]);
            newListVertices.Add(listUnresolvedCap[0].v1);
            newListVertices.Add(listUnresolvedCap[0].v2);
            newListHashValues.Add(listUnresolvedCap[0].nHash1);
            newListHashValues.Add(listUnresolvedCap[0].nHash2);
	        listUnresolvedCap.RemoveAt(0);

	        // Try to match all segments

	        while(listUnresolvedCap.Count > 0)
	        {
                // Search for a connected segment in the unresolved segment pool

                CapEdge CapEdgeLast  = listResolvedCap[listResolvedCap.Count - 1];
                CapEdge CapEdgeFirst = listResolvedCap[0];

                bool bFound = false;

		        for(int nSegmentUnresolved = 0; nSegmentUnresolved < listUnresolvedCap.Count; nSegmentUnresolved++)
		        {
                    CapEdge CapEdgeUnresolved = listUnresolvedCap[nSegmentUnresolved];

                    int nSharesVertexEnd   = CapEdgeLast.SharesVertex1Of (CapEdgeUnresolved);
                    int nSharesVertexStart = CapEdgeFirst.SharesVertex2Of(CapEdgeUnresolved);

                    if(nSharesVertexEnd == 2)
                    {
                        newListVertices.Add(CapEdgeUnresolved.v2);
                        newListHashValues.Add(CapEdgeUnresolved.nHash2);
                        listResolvedCap.Add(CapEdgeUnresolved);
                        listUnresolvedCap.RemoveAt(nSegmentUnresolved);
                        bFound = true;
                        break;
                    }
                    else if(nSharesVertexStart == 1)
                    {
                        newListVertices.Insert(0, CapEdgeUnresolved.v1);
                        newListHashValues.Insert(0, CapEdgeUnresolved.nHash1);
                        listResolvedCap.Insert(0, CapEdgeUnresolved);
                        listUnresolvedCap.RemoveAt(nSegmentUnresolved);
                        bFound = true;
                        break;
                    }
                }

                bool bFinish = bFound == false;

                if(listResolvedCap.Count >= 3)
                {
                    if(listResolvedCap[listResolvedCap.Count - 1].SharesVertex1Of(listResolvedCap[0]) == 2)
                    {
                        bFinish = true;
                    }
                }

                if(listUnresolvedCap.Count == 0)
                {
                    bFinish = true;
                }

		        if(bFinish)
		        {
                    // Finished, new cap vertex group

                    int nTotalAdd = newListVertices.Count;

                    if(Vector3.Distance(newListVertices[0], newListVertices[newListVertices.Count - 1]) < Parameters.EPSILONDISTANCEVERTEX)
                    {
                        nTotalAdd = newListVertices.Count - 1;
                    }

                    if(nTotalAdd > 2)
                    {
                        List<Vector3> listAddVertices = new List<Vector3>();
                        List<int>     listAddHash     = new List<int>();

                        for(int i = 0; i < nTotalAdd; i++)
                        {
                            listAddVertices.Add(newListVertices[i]);
                            listAddHash.Add(newListHashValues[i]);
                        }

                        listlistResolvedCapVertices.Add(listAddVertices);
                        listlistResolvedCapHashValues.Add(listAddHash);
                    }
                    else
                    {
                        if(fracturedComponent.Verbose) Debug.LogWarning("Cap group has less than 3 vertices (" + newListVertices.Count + ")");
                    }

                    if(listUnresolvedCap.Count > 0)
                    {
                        listResolvedCap.Clear();
                        listResolvedCap.Add(listUnresolvedCap[0]);
                        newListVertices.Clear();
                        newListHashValues.Clear();
                        newListVertices.Add(listUnresolvedCap[0].v1);
                        newListVertices.Add(listUnresolvedCap[0].v2);
                        newListHashValues.Add(listUnresolvedCap[0].nHash1);
                        newListHashValues.Add(listUnresolvedCap[0].nHash2);
                        listUnresolvedCap.RemoveAt(0);
                    }
		        }
	        }

	        if(listUnresolvedCap.Count > 0)
	        {
                if(fracturedComponent.Verbose) Debug.LogWarning(string.Format("Cap has {0}/{1} unresolved segments left", listUnresolvedCap.Count, nTotalSegments));
	        }

	        return true;
        }
Exemple #22
0
        static void Triangulate(    List<Vector3> listVertices, List<int> listIndices, FracturedObject fracturedComponent, List<List<Vector3>> listlistPointsConstrainedDelaunay, List<List<int>> listlistHashValuesConstrainedDelaunay,
                                    bool bConnectivityPostprocess, MeshFaceConnectivity faceConnectivityPos, MeshFaceConnectivity faceConnectivityNeg, MeshDataConnectivity meshConnectivityPos, MeshDataConnectivity meshConnectivityNeg, int nForceMeshConnectivityHash,
                                    int nSplitCloseSubMesh, Matrix4x4 mtxPlane, Matrix4x4 mtxToLocalPos, Matrix4x4 mtxToLocalNeg, Vector3 v3CenterPos, Vector3 v3CenterNeg,
                                    List<int>[] aListIndicesPosInOut, List<VertexData> listVertexDataPosInOut, List<int>[] aListIndicesNegInOut, List<VertexData> listVertexDataNegInOut)
        {
            int nPositiveSideIndexStart = listVertexDataPosInOut.Count;
		    int nNegativeSideIndexStart = listVertexDataNegInOut.Count;

            if(listVertexDataPosInOut.Count < 1 || listVertexDataNegInOut.Count < 1)
            {
                return;
            }

            // Add vertex data

            VertexData[] aVtxDataCapPos = new VertexData[listVertices.Count];
            VertexData[] aVtxDataCapNeg = new VertexData[listVertices.Count];

            Vector3 v3PlaneNormal = mtxPlane.MultiplyVector(Vector3.up);

            float fReversedCapNormals = fracturedComponent.InvertCapNormals ? -1.0f : 1.0f;

            Vector3 v3CapNormalLocalPos = mtxToLocalPos.MultiplyVector(-v3PlaneNormal * fReversedCapNormals);
            Vector3 v3CapNormalLocalNeg = mtxToLocalNeg.MultiplyVector( v3PlaneNormal * fReversedCapNormals);

            Vector3 v3TangentPos = Vector3.right;
            v3TangentPos = mtxPlane.MultiplyVector(v3TangentPos);
            v3TangentPos = mtxToLocalPos.MultiplyVector(v3TangentPos);

            Vector3 v3TangentNeg = Vector3.right;
            v3TangentNeg = mtxPlane.MultiplyVector(v3TangentNeg);
            v3TangentNeg = mtxToLocalNeg.MultiplyVector(v3TangentNeg);

            Matrix4x4 mtxPlaneInverse = mtxPlane.inverse;

            Color32 colWhite  = new Color32(255, 255, 255, 255);
            Vector3 v2Mapping = Vector2.zero;

            for(int i = 0; i < listVertices.Count; i++)
            {
                Vector3 v3Local   = mtxPlaneInverse.MultiplyPoint3x4(listVertices[i]);
                v2Mapping.x = v3Local.x * fracturedComponent.SplitMappingTileU;
                v2Mapping.y = v3Local.z * fracturedComponent.SplitMappingTileV;

                int nVertexHash = ComputeVertexHash(listVertices[i], listlistPointsConstrainedDelaunay, listlistHashValuesConstrainedDelaunay);

                aVtxDataCapPos[i] = new VertexData(nVertexHash, listVertices[i], v3CapNormalLocalPos, v3TangentPos, colWhite, v2Mapping, v2Mapping, true, true, listVertexDataPosInOut[0].bHasColor32, listVertexDataPosInOut[0].bHasMapping1, listVertexDataPosInOut[0].bHasMapping2);
                aVtxDataCapNeg[i] = new VertexData(nVertexHash, listVertices[i], v3CapNormalLocalNeg, v3TangentNeg, colWhite, v2Mapping, v2Mapping, true, true, listVertexDataNegInOut[0].bHasColor32, listVertexDataNegInOut[0].bHasMapping1, listVertexDataNegInOut[0].bHasMapping2);
            }

            listVertexDataPosInOut.AddRange(aVtxDataCapPos);
            listVertexDataNegInOut.AddRange(aVtxDataCapNeg);

            // Add indices

            for(int i = 0; i < listIndices.Count / 3; i++)
		    {
                int nTriangleA = listIndices[i * 3 + 0];
                int nTriangleB = listIndices[i * 3 + 1];
                int nTriangleC = listIndices[i * 3 + 2];

                int nHashPosA  = listVertexDataPosInOut[nPositiveSideIndexStart + nTriangleA].nVertexHash;
                int nHashPosB  = listVertexDataPosInOut[nPositiveSideIndexStart + nTriangleB].nVertexHash;
                int nHashPosC  = listVertexDataPosInOut[nPositiveSideIndexStart + nTriangleC].nVertexHash;

                int nHashNegA  = listVertexDataNegInOut[nNegativeSideIndexStart + nTriangleA].nVertexHash;
                int nHashNegB  = listVertexDataNegInOut[nNegativeSideIndexStart + nTriangleB].nVertexHash;
                int nHashNegC  = listVertexDataNegInOut[nNegativeSideIndexStart + nTriangleC].nVertexHash;

                if(nHashPosA != -1 && nHashPosB != -1 && nHashPosC != -1 && nHashNegA != -1 && nHashNegB != -1 && nHashNegC != -1)
                {
                    int nMeshConnectivityHash = nForceMeshConnectivityHash == -1 ? MeshDataConnectivity.GetNewHash() : nForceMeshConnectivityHash; // New hash value to identify the 2 shared faces

                    if(fracturedComponent.GenerateChunkConnectionInfo)
                    {
                        meshConnectivityPos.NotifyNewCapFace(nMeshConnectivityHash, nSplitCloseSubMesh, aListIndicesPosInOut[nSplitCloseSubMesh].Count / 3);
                    }

                    aListIndicesPosInOut[nSplitCloseSubMesh].Add(nPositiveSideIndexStart + nTriangleA);
			        aListIndicesPosInOut[nSplitCloseSubMesh].Add(nPositiveSideIndexStart + nTriangleB);
			        aListIndicesPosInOut[nSplitCloseSubMesh].Add(nPositiveSideIndexStart + nTriangleC);

                    if(bConnectivityPostprocess)
                    {
                        faceConnectivityPos.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleA], listVertices[nTriangleB], nHashPosA, nHashPosB, nPositiveSideIndexStart + nTriangleA, nPositiveSideIndexStart + nTriangleB);
                        faceConnectivityPos.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleB], listVertices[nTriangleC], nHashPosB, nHashPosC, nPositiveSideIndexStart + nTriangleB, nPositiveSideIndexStart + nTriangleC);
                        faceConnectivityPos.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleC], listVertices[nTriangleA], nHashPosC, nHashPosA, nPositiveSideIndexStart + nTriangleC, nPositiveSideIndexStart + nTriangleA);
                    }

                    if(fracturedComponent.GenerateChunkConnectionInfo)
                    {
                        meshConnectivityNeg.NotifyNewCapFace(nMeshConnectivityHash, nSplitCloseSubMesh, aListIndicesNegInOut[nSplitCloseSubMesh].Count / 3);
                    }

			        aListIndicesNegInOut[nSplitCloseSubMesh].Add(nNegativeSideIndexStart + nTriangleA);
			        aListIndicesNegInOut[nSplitCloseSubMesh].Add(nNegativeSideIndexStart + nTriangleC);
			        aListIndicesNegInOut[nSplitCloseSubMesh].Add(nNegativeSideIndexStart + nTriangleB);

                    if(bConnectivityPostprocess)
                    {
                        faceConnectivityNeg.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleA], listVertices[nTriangleC], nHashNegA, nHashNegC, nNegativeSideIndexStart + nTriangleA, nNegativeSideIndexStart + nTriangleC);
                        faceConnectivityNeg.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleC], listVertices[nTriangleB], nHashNegC, nHashNegB, nNegativeSideIndexStart + nTriangleC, nNegativeSideIndexStart + nTriangleB);
                        faceConnectivityNeg.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleB], listVertices[nTriangleA], nHashNegB, nHashNegA, nNegativeSideIndexStart + nTriangleB, nNegativeSideIndexStart + nTriangleA);
                    }
                }
            }
        }
        public SupportPlane(FracturedObject fracturedObject)
        {
            GUIExpanded    = true;
            GUIName        = "New Support Plane";
            GUIShowInScene = true;

            this.fracturedObject = fracturedObject;

            planeMesh = new Mesh();

            Vector3[] av3RectVerts = new Vector3[4];
            Vector3[] aRectNormals = new Vector3[4];
            Vector2[] aRectMapping = new Vector2[4];
            int[]     aRectIndices = { 0, 1, 2, 0, 2, 3 };

            av3RectVerts[0] = new Vector3(-1.0f, 0.0f, -1.0f);
            av3RectVerts[1] = new Vector3(-1.0f, 0.0f, +1.0f);
            av3RectVerts[2] = new Vector3(+1.0f, 0.0f, +1.0f);
            av3RectVerts[3] = new Vector3(+1.0f, 0.0f, -1.0f);

            aRectNormals[0] = new Vector3(0.0f, 1.0f, 0.0f);
            aRectNormals[1] = new Vector3(0.0f, 1.0f, 0.0f);
            aRectNormals[2] = new Vector3(0.0f, 1.0f, 0.0f);
            aRectNormals[3] = new Vector3(0.0f, 1.0f, 0.0f);

            bool  bHasRenderer = false;
            float fHeight      = 1.0f;

            if(fracturedObject.SourceObject)
            {
                if(fracturedObject.SourceObject.GetComponent<Renderer>())
                {
                    bHasRenderer = true;
                }
            }
           
            if(bHasRenderer)
            {
                Bounds bounds = fracturedObject.SourceObject.GetComponent<Renderer>().bounds;

                fHeight = bounds.extents.y;

                for(int i = 0; i < av3RectVerts.Length; i++)
                {
                    float fPlaneSize  = 1.3f;
                    float fMaxExtents = Mathf.Max(bounds.extents.z * fPlaneSize, bounds.extents.x * fPlaneSize);
                    av3RectVerts[i]   = Vector3.Scale(av3RectVerts[i], new Vector3(fMaxExtents, fMaxExtents, fMaxExtents)) + fracturedObject.transform.position;
                    av3RectVerts[i]   = fracturedObject.transform.InverseTransformPoint(av3RectVerts[i]);
                }

                v3PlanePosition = fracturedObject.transform.position - new Vector3(0.0f, fHeight - 0.05f, 0.0f);
                v3PlanePosition = fracturedObject.transform.InverseTransformPoint(v3PlanePosition);

                qPlaneRotation  = Quaternion.identity;
            }
            else
            {
                for(int i = 0; i < av3RectVerts.Length; i++)
                {
                    av3RectVerts[i] += fracturedObject.transform.position;
                    av3RectVerts[i]  = fracturedObject.transform.InverseTransformPoint(av3RectVerts[i]);
                }

                v3PlanePosition = new Vector3(0.0f, (-fHeight * 0.5f) + 0.05f, 0.0f);
                qPlaneRotation   = Quaternion.identity;
            }

            v3PlaneScale = Vector3.one;

            planeMesh.vertices  = av3RectVerts;
            planeMesh.normals   = aRectNormals;
            planeMesh.uv        = aRectMapping;
            planeMesh.triangles = aRectIndices;
        }
        private static bool SplitMeshUsingPlane(MeshData meshDataIn, FracturedObject fracturedComponent, SplitOptions splitOptions, Vector3 v3PlaneNormal, Vector3 v3PlaneRight, Vector3 v3PlanePoint, out List<MeshData> listMeshDatasPosOut, out List<MeshData> listMeshDatasNegOut, ProgressDelegate progress = null)
        {
            Plane planeSplit = new Plane(v3PlaneNormal, v3PlanePoint);

            listMeshDatasPosOut = new List<MeshData>();
            listMeshDatasNegOut = new List<MeshData>();

            // Check if the input object already has been split, to get its split closing submesh

            bool bNeedsNewSplitSubMesh = meshDataIn.nSplitCloseSubMesh == -1;
            int  nSplitCloseSubMesh    = meshDataIn.nSplitCloseSubMesh;

            // Here we are going to store our output vertex/index data

            int nCurrentVertexHash = meshDataIn.nCurrentVertexHash; // We will use this to identify vertices with same coordinates but different vertex data. They will share the same vertex hash

            List<VertexData>     listVertexDataPos   = new List<VertexData>();
            List<VertexData>     listVertexDataNeg   = new List<VertexData>();
            List<int>[]          alistIndicesPos     = new List<int>[meshDataIn.nSubMeshCount + (meshDataIn.nSplitCloseSubMesh == -1 ? 1 : 0)];
            List<int>[]          alistIndicesNeg     = new List<int>[meshDataIn.nSubMeshCount + (meshDataIn.nSplitCloseSubMesh == -1 ? 1 : 0)];
            MeshFaceConnectivity faceConnectivityPos = new MeshFaceConnectivity();
            MeshFaceConnectivity faceConnectivityNeg = new MeshFaceConnectivity();
            MeshDataConnectivity meshConnectivityPos = new MeshDataConnectivity();
            MeshDataConnectivity meshConnectivityNeg = new MeshDataConnectivity();

            listVertexDataPos.Capacity = meshDataIn.aVertexData.Length / 2;
            listVertexDataNeg.Capacity = meshDataIn.aVertexData.Length / 2;

            if(bNeedsNewSplitSubMesh)
            {
                // Make room for the split closing submesh

                nSplitCloseSubMesh = meshDataIn.nSubMeshCount;

                alistIndicesPos[nSplitCloseSubMesh] = new List<int>();
                alistIndicesNeg[nSplitCloseSubMesh] = new List<int>();
            }

            // Our vertices that form the clipped cap

            Dictionary<EdgeKeyByHash, int>     dicClipVerticesHash = new Dictionary<EdgeKeyByHash, int>    (new EdgeKeyByHash.EqualityComparer());
            Dictionary<EdgeKeyByHash, CapEdge> dicCapEdges         = new Dictionary<EdgeKeyByHash, CapEdge>(new EdgeKeyByHash.EqualityComparer());

            // A hash table with our clipped edges, to reuse clipped vertices

            Dictionary<EdgeKeyByIndex, ClippedEdge> dicClippedEdgesPos = new Dictionary<EdgeKeyByIndex, ClippedEdge>(new EdgeKeyByIndex.EqualityComparer());
            Dictionary<EdgeKeyByIndex, ClippedEdge> dicClippedEdgesNeg = new Dictionary<EdgeKeyByIndex, ClippedEdge>(new EdgeKeyByIndex.EqualityComparer());

            int nClippedCacheHits   = 0;
            int nClippedCacheMisses = 0;

            // A hash table with the remapped indices, to reuse non-clipped vertices

            Dictionary<int, int> dicRemappedIndicesPos = new Dictionary<int, int>();
            Dictionary<int, int> dicRemappedIndicesNeg = new Dictionary<int, int>();

            for(int nSubMesh = 0; nSubMesh < meshDataIn.nSubMeshCount; nSubMesh++)
            {
                // Index list

                alistIndicesPos[nSubMesh] = new List<int>();
                alistIndicesNeg[nSubMesh] = new List<int>();
                List<int> listIndicesPos = alistIndicesPos[nSubMesh];
                List<int> listIndicesNeg = alistIndicesNeg[nSubMesh];

                alistIndicesPos[nSubMesh].Capacity = meshDataIn.aaIndices[nSubMesh].Length / 2;
                alistIndicesNeg[nSubMesh].Capacity = meshDataIn.aaIndices[nSubMesh].Length / 2;

                // A reference to the output arrays/lists (it will be switching between positive/negative side along the algorithm)

                List<VertexData>     plistVertexData    = listVertexDataPos;
                List<int>            plistObjectIndices = listIndicesPos;
                MeshFaceConnectivity pFaceConnectivity  = faceConnectivityPos;
                MeshDataConnectivity pMeshConnectivity  = meshConnectivityPos;

                Dictionary<EdgeKeyByIndex, ClippedEdge> pdicClippedEdges    = dicClippedEdgesPos;
                Dictionary<int, int>                    pdicRemappedIndices = dicRemappedIndicesPos;

                // Iterate through all submesh faces:

                for(int i = 0; i < meshDataIn.aaIndices[nSubMesh].Length / 3; i++)
	            {
                    plistVertexData     = listVertexDataPos;
                    plistObjectIndices  = listIndicesPos;
                    pFaceConnectivity   = faceConnectivityPos;
                    pMeshConnectivity   = meshConnectivityPos;
                    pdicClippedEdges    = dicClippedEdgesPos;
                    pdicRemappedIndices = dicRemappedIndicesPos;

		            int nIndex1 = meshDataIn.aaIndices[nSubMesh][i * 3 + 0];
		            int nIndex2 = meshDataIn.aaIndices[nSubMesh][i * 3 + 1];
		            int nIndex3 = meshDataIn.aaIndices[nSubMesh][i * 3 + 2];

                    int nHashV1 = meshDataIn.aVertexData[nIndex1].nVertexHash;
                    int nHashV2 = meshDataIn.aVertexData[nIndex2].nVertexHash;
                    int nHashV3 = meshDataIn.aVertexData[nIndex3].nVertexHash;

		            Vector3 v1 = meshDataIn.aVertexData[nIndex1].v3Vertex;
		            Vector3 v2 = meshDataIn.aVertexData[nIndex2].v3Vertex;
		            Vector3 v3 = meshDataIn.aVertexData[nIndex3].v3Vertex;

                    // Classify vertices depending on the side of the plane they lay on, then clip if necessary.

		            float fSide1 = v1.x * planeSplit.normal.x + v1.y * planeSplit.normal.y + v1.z * planeSplit.normal.z + planeSplit.distance;
		            float fSide2 = v2.x * planeSplit.normal.x + v2.y * planeSplit.normal.y + v2.z * planeSplit.normal.z + planeSplit.distance;
		            float fSide3 = v3.x * planeSplit.normal.x + v3.y * planeSplit.normal.y + v3.z * planeSplit.normal.z + planeSplit.distance;

                    bool  bForceSameSide  = false;
                    int   nAlmostInPlane  = 0;
                    bool  bAlmostInPlane1 = false;
                    bool  bAlmostInPlane2 = false;
                    bool  bAlmostInPlane3 = false;
                    float fFurthest       = 0.0f;

                    if(Mathf.Abs(fSide1) < UltimateFracturing.Parameters.EPSILONDISTANCEPLANE) { bAlmostInPlane1 = true; nAlmostInPlane++; }
                    if(Mathf.Abs(fSide2) < UltimateFracturing.Parameters.EPSILONDISTANCEPLANE) { bAlmostInPlane2 = true; nAlmostInPlane++; }
                    if(Mathf.Abs(fSide3) < UltimateFracturing.Parameters.EPSILONDISTANCEPLANE) { bAlmostInPlane3 = true; nAlmostInPlane++; }

                    if(Mathf.Abs(fSide1) > Mathf.Abs(fFurthest)) fFurthest = fSide1;
                    if(Mathf.Abs(fSide2) > Mathf.Abs(fFurthest)) fFurthest = fSide2;
                    if(Mathf.Abs(fSide3) > Mathf.Abs(fFurthest)) fFurthest = fSide3;

                    if(nAlmostInPlane == 1)
                    {
                        // Look if the other two vertices are on the same side. If so, we'll skip the clipping too.
                        if(bAlmostInPlane1 && (fSide2 * fSide3 > 0.0f)) bForceSameSide = true;
                        if(bAlmostInPlane2 && (fSide1 * fSide3 > 0.0f)) bForceSameSide = true;
                        if(bAlmostInPlane3 && (fSide1 * fSide2 > 0.0f)) bForceSameSide = true;
                    }
                    else if(nAlmostInPlane > 1)
                    {
                        bForceSameSide = true;

                        if(nAlmostInPlane == 3)
                        {
                            // Coplanar
                            continue;
                        }
                    }

		            if((fSide1 * fSide2 > 0.0f && fSide2 * fSide3 > 0.0f) || bForceSameSide)
		            {
			            // All on the same side, no clipping needed

			            if(fFurthest < 0.0f)
			            {
				            plistVertexData     = listVertexDataNeg;
				            plistObjectIndices  = listIndicesNeg;
                            pFaceConnectivity   = faceConnectivityNeg;
                            pMeshConnectivity   = meshConnectivityNeg;
                            pdicClippedEdges    = dicClippedEdgesNeg;
                            pdicRemappedIndices = dicRemappedIndicesNeg;
			            }

                        int nNewIndex1 = -1;
                        int nNewIndex2 = -1;
                        int nNewIndex3 = -1;

                        // Find vertices in remapped indices list and add vertex data if not present

                        if(pdicRemappedIndices.ContainsKey(nIndex1))
                        {
                            nNewIndex1 = pdicRemappedIndices[nIndex1];
                        }
                        if(nNewIndex1 == -1)
                        {
                            nNewIndex1 = plistVertexData.Count;
                            plistVertexData.Add(meshDataIn.aVertexData[nIndex1].Copy());
                            pdicRemappedIndices[nIndex1] = nNewIndex1;
                        }

                        if(pdicRemappedIndices.ContainsKey(nIndex2))
                        {
                            nNewIndex2 = pdicRemappedIndices[nIndex2];
                        }
                        if(nNewIndex2 == -1)
                        {
                            nNewIndex2 = plistVertexData.Count;
                            plistVertexData.Add(meshDataIn.aVertexData[nIndex2].Copy());
                            pdicRemappedIndices[nIndex2] = nNewIndex2;
                        }

                        if(pdicRemappedIndices.ContainsKey(nIndex3))
                        {
                            nNewIndex3 = pdicRemappedIndices[nIndex3];
                        }
                        if(nNewIndex3 == -1)
                        {
                            nNewIndex3 = plistVertexData.Count;
                            plistVertexData.Add(meshDataIn.aVertexData[nIndex3].Copy());
                            pdicRemappedIndices[nIndex3] = nNewIndex3;
                        }

                        // Add triangle indices

                        if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false)
                        {
                            pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3);
                        }

                        plistObjectIndices.Add(nNewIndex1);
                        plistObjectIndices.Add(nNewIndex2);
                        plistObjectIndices.Add(nNewIndex3);

                        if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false)
                        {
                            pFaceConnectivity.AddEdge(nSubMesh, v1, v2, nHashV1, nHashV2, nNewIndex1, nNewIndex2);
                            pFaceConnectivity.AddEdge(nSubMesh, v2, v3, nHashV2, nHashV3, nNewIndex2, nNewIndex3);
                            pFaceConnectivity.AddEdge(nSubMesh, v3, v1, nHashV3, nHashV1, nNewIndex3, nNewIndex1);
                        }

                        // Add cap edges only if an edge is lying on the plane

                        if(nAlmostInPlane == 2)
                        {
                            if(fFurthest > 0.0f)
                            {
                                if(bAlmostInPlane1 && bAlmostInPlane2 && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV1, nHashV2, v1, v2);
                                if(bAlmostInPlane2 && bAlmostInPlane3 && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV2, nHashV3, v2, v3);
                                if(bAlmostInPlane3 && bAlmostInPlane1 && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV3, nHashV1, v3, v1);
                            }
                            else
                            {
                                if(bAlmostInPlane1 && bAlmostInPlane2 && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV2, nHashV1, v2, v1);
                                if(bAlmostInPlane2 && bAlmostInPlane3 && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV3, nHashV2, v3, v2);
                                if(bAlmostInPlane3 && bAlmostInPlane1 && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV1, nHashV3, v1, v3);
                            }
                        }
		            }
                    else if(nAlmostInPlane == 1)
                    {
                        // Special treatment clipping for one vertex laying on the clipping plane and the other 2 on different sides

                        int  nNewIndex1 = -1;
                        int  nNewIndex2 = -1;
                        int  nNewIndex3 = -1;
                        int  nNewIndex4 = -1;
                        int  nHashV4    = -1;
                        bool bEdge      = false;

                        EdgeKeyByIndex clippedEdgeKey;

                        if(bAlmostInPlane1)
                        {
                            // v1 almost on the clipping plane

					        if(fSide2 < 0.0f)
					        {
						        plistVertexData     = listVertexDataNeg;
						        plistObjectIndices  = listIndicesNeg;
                                pFaceConnectivity   = faceConnectivityNeg;
                                pMeshConnectivity   = meshConnectivityNeg;
                                pdicClippedEdges    = dicClippedEdgesNeg;
                                pdicRemappedIndices = dicRemappedIndicesNeg;
					        }

                            clippedEdgeKey = new EdgeKeyByIndex(nIndex2, nIndex3);

                            if(pdicClippedEdges.ContainsKey(clippedEdgeKey))
                            {
                                nClippedCacheHits++;
                                bEdge = true;
                                nNewIndex2 = pdicClippedEdges[clippedEdgeKey].GetFirstIndex(nIndex2);
                                nNewIndex4 = pdicClippedEdges[clippedEdgeKey].nClippedIndex;
                            }
                            else
                            {
                                nClippedCacheMisses++;
                                if(pdicRemappedIndices.ContainsKey(nIndex2)) nNewIndex2 = pdicRemappedIndices[nIndex2];
                            }

                            // Clip if not present in clipped edge list

                            EdgeKeyByHash clippedEdgeKeyHash = new EdgeKeyByHash(nHashV2, nHashV3);

                            if(dicClipVerticesHash.ContainsKey(clippedEdgeKeyHash))
                            {
                                nHashV4 = dicClipVerticesHash[clippedEdgeKeyHash];
                            }
                            else
                            {
                                nHashV4 = nCurrentVertexHash++;
                                dicClipVerticesHash.Add(clippedEdgeKeyHash, nHashV4);
                            }

                            VertexData vd4 = new VertexData(nHashV4);

                            if(bEdge == false)
                            {
                                if(VertexData.ClipAgainstPlane(meshDataIn.aVertexData, nIndex2, nIndex3, v2, v3, planeSplit, ref vd4) == false)
                                {
                                    return false;
                                }
                            }

                            // Add geometry of one side

                            // Add vertex data for all data not present in remapped list

                            if(nNewIndex1 == -1)
                            {
                                if(pdicRemappedIndices.ContainsKey(nIndex1))
                                {
                                    nNewIndex1 = pdicRemappedIndices[nIndex1];
                                }
                            }
                            if(nNewIndex1 == -1)
                            {
                                nNewIndex1 = plistVertexData.Count;
                                plistVertexData.Add(meshDataIn.aVertexData[nIndex1].Copy());
                                pdicRemappedIndices[nIndex1] = nNewIndex1;
                            }

                            if(nNewIndex2 == -1)
                            {
                                nNewIndex2 = plistVertexData.Count;
                                plistVertexData.Add(meshDataIn.aVertexData[nIndex2].Copy());
                                pdicRemappedIndices[nIndex2] = nNewIndex2;
                            }

                            if(nNewIndex4 == -1)
                            {
                                nNewIndex4 = plistVertexData.Count;
                                plistVertexData.Add(vd4);
                            }

                            if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false)
                            {
                                pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3);
                            }

                            plistObjectIndices.Add(nNewIndex1);
                            plistObjectIndices.Add(nNewIndex2);
                            plistObjectIndices.Add(nNewIndex4);

                            Vector3 v4 = plistVertexData[nNewIndex4].v3Vertex;

                            if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false)
                            {
                                pFaceConnectivity.AddEdge(nSubMesh, v1, v2, nHashV1, nHashV2, nNewIndex1, nNewIndex2);
                                pFaceConnectivity.AddEdge(nSubMesh, v2, v4, nHashV2, nHashV4, nNewIndex2, nNewIndex4);
                                pFaceConnectivity.AddEdge(nSubMesh, v4, v1, nHashV4, nHashV1, nNewIndex4, nNewIndex1);
                            }

                            // Update cap edges and cache

                            if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV4, nHashV1, plistVertexData[nNewIndex4].v3Vertex, plistVertexData[nNewIndex1].v3Vertex);

                            if(bEdge == false) pdicClippedEdges.Add(clippedEdgeKey, new ClippedEdge(nIndex2, nIndex3, nNewIndex2, nNewIndex3, nNewIndex4));

                            // Add geometry of other side

					        if(fSide3 < 0.0f)
					        {
						        plistVertexData     = listVertexDataNeg;
                                plistObjectIndices  = listIndicesNeg;
                                pFaceConnectivity   = faceConnectivityNeg;
                                pMeshConnectivity   = meshConnectivityNeg;
                                pdicClippedEdges    = dicClippedEdgesNeg;
                                pdicRemappedIndices = dicRemappedIndicesNeg;
					        }
					        else
					        {
						        plistVertexData     = listVertexDataPos;
						        plistObjectIndices  = listIndicesPos;
                                pFaceConnectivity   = faceConnectivityPos;
                                pMeshConnectivity   = meshConnectivityPos;
                                pdicClippedEdges    = dicClippedEdgesPos;
                                pdicRemappedIndices = dicRemappedIndicesPos;
					        }

                            nNewIndex1 = -1;
                            nNewIndex2 = -1;
                            nNewIndex3 = -1;
                            nNewIndex4 = -1;
                            bEdge      = false;

                            // Find edges in cache

                            if(pdicClippedEdges.ContainsKey(clippedEdgeKey))
                            {
                                nClippedCacheHits++;
                                bEdge      = true;
                                nNewIndex3 = pdicClippedEdges[clippedEdgeKey].GetSecondIndex(nIndex3);
                                nNewIndex4 = pdicClippedEdges[clippedEdgeKey].nClippedIndex;
                            }
                            else
                            {
                                nClippedCacheMisses++;
                                if(pdicRemappedIndices.ContainsKey(nIndex3)) nNewIndex3 = pdicRemappedIndices[nIndex3];
                            }

                            // Add vertex data for all data not present in remapped list

                            if(nNewIndex1 == -1)
                            {
                                if(pdicRemappedIndices.ContainsKey(nIndex1))
                                {
                                    nNewIndex1 = pdicRemappedIndices[nIndex1];
                                }
                            }
                            if(nNewIndex1 == -1)
                            {
                                nNewIndex1 = plistVertexData.Count;
                                plistVertexData.Add(meshDataIn.aVertexData[nIndex1].Copy());
                                pdicRemappedIndices[nIndex1] = nNewIndex1;
                            }

                            if(nNewIndex3 == -1)
                            {
                                nNewIndex3 = plistVertexData.Count;
                                plistVertexData.Add(meshDataIn.aVertexData[nIndex3].Copy());
                                pdicRemappedIndices[nIndex3] = nNewIndex3;
                            }

                            if(nNewIndex4 == -1)
                            {
                                nNewIndex4 = plistVertexData.Count;
                                plistVertexData.Add(vd4);
                            }

                            if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false)
                            {
                                pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3);
                            }

                            plistObjectIndices.Add(nNewIndex1);
                            plistObjectIndices.Add(nNewIndex4);
                            plistObjectIndices.Add(nNewIndex3);

                            if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false)
                            {
                                pFaceConnectivity.AddEdge(nSubMesh, v1, v4, nHashV1, nHashV4, nNewIndex1, nNewIndex4);
                                pFaceConnectivity.AddEdge(nSubMesh, v4, v3, nHashV4, nHashV3, nNewIndex4, nNewIndex3);
                                pFaceConnectivity.AddEdge(nSubMesh, v3, v1, nHashV3, nHashV1, nNewIndex3, nNewIndex1);
                            }

                            // Update cap edges and cache

                            if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV1, nHashV4, plistVertexData[nNewIndex1].v3Vertex, plistVertexData[nNewIndex4].v3Vertex);

                            if(bEdge == false) pdicClippedEdges.Add(clippedEdgeKey, new ClippedEdge(nIndex2, nIndex3, nNewIndex2, nNewIndex3, nNewIndex4));
                        }
                        else if(bAlmostInPlane2)
                        {
                            // v2 almost on the clipping plane

					        if(fSide3 < 0.0f)
					        {
						        plistVertexData     = listVertexDataNeg;
						        plistObjectIndices  = listIndicesNeg;
                                pFaceConnectivity   = faceConnectivityNeg;
                                pMeshConnectivity   = meshConnectivityNeg;
                                pdicClippedEdges    = dicClippedEdgesNeg;
                                pdicRemappedIndices = dicRemappedIndicesNeg;
					        }

                            clippedEdgeKey = new EdgeKeyByIndex(nIndex3, nIndex1);

                            if(pdicClippedEdges.ContainsKey(clippedEdgeKey))
                            {
                                nClippedCacheHits++;
                                bEdge      = true;
                                nNewIndex3 = pdicClippedEdges[clippedEdgeKey].GetFirstIndex(nIndex3);
                                nNewIndex4 = pdicClippedEdges[clippedEdgeKey].nClippedIndex;
                            }
                            else
                            {
                                nClippedCacheMisses++;
                                if(pdicRemappedIndices.ContainsKey(nIndex3)) nNewIndex3 = pdicRemappedIndices[nIndex3];
                            }

                            // Clip if not present in clipped edge list

                            EdgeKeyByHash clippedEdgeKeyHash = new EdgeKeyByHash(nHashV3, nHashV1);

                            if(dicClipVerticesHash.ContainsKey(clippedEdgeKeyHash))
                            {
                                nHashV4 = dicClipVerticesHash[clippedEdgeKeyHash];
                            }
                            else
                            {
                                nHashV4 = nCurrentVertexHash++;
                                dicClipVerticesHash.Add(clippedEdgeKeyHash, nHashV4);
                            }

                            VertexData vd4 = new VertexData(nHashV4);

                            if(bEdge == false)
                            {
                                if(VertexData.ClipAgainstPlane(meshDataIn.aVertexData, nIndex3, nIndex1, v3, v1, planeSplit, ref vd4) == false)
                                {
                                    return false;
                                }
                            }

                            // Add geometry of one side

                            // Add vertex data for all data not present in remapped list

                            if(nNewIndex2 == -1)
                            {
                                if(pdicRemappedIndices.ContainsKey(nIndex2))
                                {
                                    nNewIndex2 = pdicRemappedIndices[nIndex2];
                                }
                            }
                            if(nNewIndex2 == -1)
                            {
                                nNewIndex2 = plistVertexData.Count;
                                plistVertexData.Add(meshDataIn.aVertexData[nIndex2].Copy());
                                pdicRemappedIndices[nIndex2] = nNewIndex2;
                            }

                            if(nNewIndex3 == -1)
                            {
                                nNewIndex3 = plistVertexData.Count;
                                plistVertexData.Add(meshDataIn.aVertexData[nIndex3].Copy());
                                pdicRemappedIndices[nIndex3] = nNewIndex3;
                            }

                            if(nNewIndex4 == -1)
                            {
                                nNewIndex4 = plistVertexData.Count;
                                plistVertexData.Add(vd4);
                            }

                            if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false)
                            {
                                pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3);
                            }

                            plistObjectIndices.Add(nNewIndex2);
                            plistObjectIndices.Add(nNewIndex3);
                            plistObjectIndices.Add(nNewIndex4);

                            Vector3 v4 = plistVertexData[nNewIndex4].v3Vertex;

                            if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false)
                            {
                                pFaceConnectivity.AddEdge(nSubMesh, v2, v3, nHashV2, nHashV3, nNewIndex2, nNewIndex3);
                                pFaceConnectivity.AddEdge(nSubMesh, v3, v4, nHashV3, nHashV4, nNewIndex3, nNewIndex4);
                                pFaceConnectivity.AddEdge(nSubMesh, v4, v2, nHashV4, nHashV2, nNewIndex4, nNewIndex2);
                            }

                            // Update cap edges and cache

                            if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV4, nHashV2, plistVertexData[nNewIndex4].v3Vertex, plistVertexData[nNewIndex2].v3Vertex);

                            if(bEdge == false) pdicClippedEdges.Add(clippedEdgeKey, new ClippedEdge(nIndex3, nIndex1, nNewIndex3, nNewIndex1, nNewIndex4));

                            // Add geometry of other side

					        if(fSide1 < 0.0f)
					        {
						        plistVertexData     = listVertexDataNeg;
                                plistObjectIndices  = listIndicesNeg;
                                pFaceConnectivity   = faceConnectivityNeg;
                                pMeshConnectivity   = meshConnectivityNeg;
                                pdicClippedEdges    = dicClippedEdgesNeg;
                                pdicRemappedIndices = dicRemappedIndicesNeg;
					        }
					        else
					        {
						        plistVertexData     = listVertexDataPos;
						        plistObjectIndices  = listIndicesPos;
                                pFaceConnectivity   = faceConnectivityPos;
                                pMeshConnectivity   = meshConnectivityPos;
                                pdicClippedEdges    = dicClippedEdgesPos;
                                pdicRemappedIndices = dicRemappedIndicesPos;
					        }

                            nNewIndex1 = -1;
                            nNewIndex2 = -1;
                            nNewIndex4 = -1;
                            bEdge      = false;

                            // Find edges in cache

                            if(pdicClippedEdges.ContainsKey(clippedEdgeKey))
                            {
                                nClippedCacheHits++;
                                bEdge      = true;
                                nNewIndex1 = pdicClippedEdges[clippedEdgeKey].GetSecondIndex(nIndex1);
                                nNewIndex4 = pdicClippedEdges[clippedEdgeKey].nClippedIndex;
                            }
                            else
                            {
                                nClippedCacheMisses++;
                                if(pdicRemappedIndices.ContainsKey(nIndex1)) nNewIndex1 = pdicRemappedIndices[nIndex1];
                            }

                            // Add vertex data for all data not present in remapped list

                            if(nNewIndex1 == -1)
                            {
                                nNewIndex1 = plistVertexData.Count;
                                plistVertexData.Add(meshDataIn.aVertexData[nIndex1].Copy());
                                pdicRemappedIndices[nIndex1] = nNewIndex1;
                            }

                            if(nNewIndex2 == -1)
                            {
                                if(pdicRemappedIndices.ContainsKey(nIndex2))
                                {
                                    nNewIndex2 = pdicRemappedIndices[nIndex2];
                                }
                            }
                            if(nNewIndex2 == -1)
                            {
                                nNewIndex2 = plistVertexData.Count;
                                plistVertexData.Add(meshDataIn.aVertexData[nIndex2].Copy());
                                pdicRemappedIndices[nIndex2] = nNewIndex2;
                            }

                            if(nNewIndex4 == -1)
                            {
                                nNewIndex4 = plistVertexData.Count;
                                plistVertexData.Add(vd4);
                            }

                            if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false)
                            {
                                pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3);
                            }

                            plistObjectIndices.Add(nNewIndex2);
                            plistObjectIndices.Add(nNewIndex4);
                            plistObjectIndices.Add(nNewIndex1);

                            if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false)
                            {
                                pFaceConnectivity.AddEdge(nSubMesh, v2, v4, nHashV2, nHashV4, nNewIndex2, nNewIndex4);
                                pFaceConnectivity.AddEdge(nSubMesh, v4, v1, nHashV4, nHashV1, nNewIndex4, nNewIndex1);
                                pFaceConnectivity.AddEdge(nSubMesh, v1, v2, nHashV1, nHashV2, nNewIndex1, nNewIndex2);
                            }

                            // Update cap edges and cache

                            if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV2, nHashV4, plistVertexData[nNewIndex2].v3Vertex, plistVertexData[nNewIndex4].v3Vertex);

                            if(bEdge == false) pdicClippedEdges.Add(clippedEdgeKey, new ClippedEdge(nIndex3, nIndex1, nNewIndex3, nNewIndex1, nNewIndex4));
                        }
                        else if(bAlmostInPlane3)
                        {
                            // v3 almost on the clipping plane

					        if(fSide1 < 0.0f)
					        {
						        plistVertexData     = listVertexDataNeg;
						        plistObjectIndices  = listIndicesNeg;
                                pFaceConnectivity   = faceConnectivityNeg;
                                pMeshConnectivity   = meshConnectivityNeg;
                                pdicClippedEdges    = dicClippedEdgesNeg;
                                pdicRemappedIndices = dicRemappedIndicesNeg;
					        }

                            clippedEdgeKey = new EdgeKeyByIndex(nIndex1, nIndex2);

                            if(pdicClippedEdges.ContainsKey(clippedEdgeKey))
                            {
                                nClippedCacheHits++;
                                bEdge      = true;
                                nNewIndex1 = pdicClippedEdges[clippedEdgeKey].GetFirstIndex(nIndex1);
                                nNewIndex4 = pdicClippedEdges[clippedEdgeKey].nClippedIndex;
                            }
                            else
                            {
                                nClippedCacheMisses++;
                                if(pdicRemappedIndices.ContainsKey(nIndex1)) nNewIndex1 = pdicRemappedIndices[nIndex1];
                            }

                            // Clip if not present in clipped edge list

                            EdgeKeyByHash clippedEdgeKeyHash = new EdgeKeyByHash(nHashV1, nHashV2);

                            if(dicClipVerticesHash.ContainsKey(clippedEdgeKeyHash))
                            {
                                nHashV4 = dicClipVerticesHash[clippedEdgeKeyHash];
                            }
                            else
                            {
                                nHashV4 = nCurrentVertexHash++;
                                dicClipVerticesHash.Add(clippedEdgeKeyHash, nHashV4);
                            }

                            VertexData vd4 = new VertexData(nHashV4);

                            if(bEdge == false)
                            {
                                if(VertexData.ClipAgainstPlane(meshDataIn.aVertexData, nIndex1, nIndex2, v1, v2, planeSplit, ref vd4) == false)
                                {
                                    return false;
                                }
                            }

                            // Add geometry of one side

                            // Add vertex data for all data not present in remapped list

                            if(nNewIndex1 == -1)
                            {
                                nNewIndex1 = plistVertexData.Count;
                                plistVertexData.Add(meshDataIn.aVertexData[nIndex1].Copy());
                                pdicRemappedIndices[nIndex1] = nNewIndex1;
                            }

                            if(nNewIndex3 == -1)
                            {
                                if(pdicRemappedIndices.ContainsKey(nIndex3))
                                {
                                    nNewIndex3 = pdicRemappedIndices[nIndex3];
                                }
                            }
                            if(nNewIndex3 == -1)
                            {
                                nNewIndex3 = plistVertexData.Count;
                                plistVertexData.Add(meshDataIn.aVertexData[nIndex3].Copy());
                                pdicRemappedIndices[nIndex3] = nNewIndex3;
                            }

                            if(nNewIndex4 == -1)
                            {
                                nNewIndex4 = plistVertexData.Count;
                                plistVertexData.Add(vd4);
                            }

                            if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false)
                            {
                                pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3);
                            }

                            plistObjectIndices.Add(nNewIndex1);
                            plistObjectIndices.Add(nNewIndex4);
                            plistObjectIndices.Add(nNewIndex3);

                            Vector3 v4 = plistVertexData[nNewIndex4].v3Vertex;

                            if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false)
                            {
                                pFaceConnectivity.AddEdge(nSubMesh, v1, v4, nHashV1, nHashV4, nNewIndex1, nNewIndex4);
                                pFaceConnectivity.AddEdge(nSubMesh, v4, v3, nHashV4, nHashV3, nNewIndex4, nNewIndex3);
                                pFaceConnectivity.AddEdge(nSubMesh, v3, v1, nHashV3, nHashV1, nNewIndex3, nNewIndex1);
                            }

                            // Update cap edges and cache

                            if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV4, nHashV3, plistVertexData[nNewIndex4].v3Vertex, plistVertexData[nNewIndex3].v3Vertex);

                            if(bEdge == false) pdicClippedEdges.Add(clippedEdgeKey, new ClippedEdge(nIndex1, nIndex2, nNewIndex1, nNewIndex2, nNewIndex4));

                            // Add geometry of other side

					        if(fSide2 < 0.0f)
					        {
						        plistVertexData     = listVertexDataNeg;
                                plistObjectIndices  = listIndicesNeg;
                                pFaceConnectivity   = faceConnectivityNeg;
                                pMeshConnectivity   = meshConnectivityNeg;
                                pdicClippedEdges    = dicClippedEdgesNeg;
                                pdicRemappedIndices = dicRemappedIndicesNeg;
					        }
					        else
					        {
						        plistVertexData     = listVertexDataPos;
						        plistObjectIndices  = listIndicesPos;
                                pFaceConnectivity   = faceConnectivityPos;
                                pMeshConnectivity   = meshConnectivityPos;
                                pdicClippedEdges    = dicClippedEdgesPos;
                                pdicRemappedIndices = dicRemappedIndicesPos;
					        }

                            nNewIndex2 = -1;
                            nNewIndex3 = -1;
                            nNewIndex4 = -1;
                            bEdge      = false;

                            // Find edges in cache

                            if(pdicClippedEdges.ContainsKey(clippedEdgeKey))
                            {
                                nClippedCacheHits++;
                                bEdge      = true;
                                nNewIndex2 = pdicClippedEdges[clippedEdgeKey].GetSecondIndex(nIndex2);
                                nNewIndex4 = pdicClippedEdges[clippedEdgeKey].nClippedIndex;
                            }
                            else
                            {
                                nClippedCacheMisses++;
                                if(pdicRemappedIndices.ContainsKey(nIndex2)) nNewIndex2 = pdicRemappedIndices[nIndex2];
                            }

                            // Add vertex data for all data not present in remapped list

                            if(nNewIndex2 == -1)
                            {
                                nNewIndex2 = plistVertexData.Count;
                                plistVertexData.Add(meshDataIn.aVertexData[nIndex2].Copy());
                                pdicRemappedIndices[nIndex2] = nNewIndex2;
                            }

                            if(nNewIndex3 == -1)
                            {
                                if(pdicRemappedIndices.ContainsKey(nIndex3))
                                {
                                    nNewIndex3 = pdicRemappedIndices[nIndex3];
                                }
                            }
                            if(nNewIndex3 == -1)
                            {
                                nNewIndex3 = plistVertexData.Count;
                                plistVertexData.Add(meshDataIn.aVertexData[nIndex3].Copy());
                                pdicRemappedIndices[nIndex3] = nNewIndex3;
                            }

                            if(nNewIndex4 == -1)
                            {
                                nNewIndex4 = plistVertexData.Count;
                                plistVertexData.Add(vd4);
                            }

                            if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false)
                            {
                                pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3);
                            }

                            plistObjectIndices.Add(nNewIndex2);
                            plistObjectIndices.Add(nNewIndex3);
                            plistObjectIndices.Add(nNewIndex4);

                            if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false)
                            {
                                pFaceConnectivity.AddEdge(nSubMesh, v2, v3, nHashV2, nHashV3, nNewIndex2, nNewIndex3);
                                pFaceConnectivity.AddEdge(nSubMesh, v3, v4, nHashV3, nHashV4, nNewIndex3, nNewIndex4);
                                pFaceConnectivity.AddEdge(nSubMesh, v4, v2, nHashV4, nHashV2, nNewIndex4, nNewIndex2);
                            }

                            // Update cap edges and cache

                            if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV3, nHashV4, plistVertexData[nNewIndex3].v3Vertex, plistVertexData[nNewIndex4].v3Vertex);

                            if(bEdge == false) pdicClippedEdges.Add(clippedEdgeKey, new ClippedEdge(nIndex1, nIndex2, nNewIndex1, nNewIndex2, nNewIndex4));
                        }
                    }
		            else
		            {
			            if(fSide1 * fSide2 < 0.0f)
			            {
				            // v1 and v2 on different sides

				            if(fSide2 * fSide3 < 0.0f)
				            {
					            // ... and v3 on same side as v1

					            if(fSide1 < 0.0f)
					            {
						            plistVertexData     = listVertexDataNeg;
						            plistObjectIndices  = listIndicesNeg;
                                    pFaceConnectivity   = faceConnectivityNeg;
                                    pMeshConnectivity   = meshConnectivityNeg;
                                    pdicClippedEdges    = dicClippedEdgesNeg;
                                    pdicRemappedIndices = dicRemappedIndicesNeg;
					            }

                                int  nNewIndex1 = -1;
                                int  nNewIndex2 = -1;
                                int  nNewIndex3 = -1;
                                int  nNewIndex4 = -1;
                                int  nNewIndex5 = -1;
                                int  nHashV4    = -1;
                                int  nHashV5    = -1;
                                bool bEdgeKey1  = false;
                                bool bEdgeKey2  = false;

                                EdgeKeyByIndex edgeKey1 = new EdgeKeyByIndex(nIndex1, nIndex2);
                                EdgeKeyByIndex edgeKey2 = new EdgeKeyByIndex(nIndex2, nIndex3);

                                // Find edges in cache

                                if(pdicClippedEdges.ContainsKey(edgeKey1))
                                {
                                    nClippedCacheHits++;
                                    bEdgeKey1  = true;
                                    nNewIndex1 = pdicClippedEdges[edgeKey1].GetFirstIndex(nIndex1);
                                    nNewIndex4 = pdicClippedEdges[edgeKey1].nClippedIndex;
                                }
                                else
                                {
                                    nClippedCacheMisses++;
                                    if(pdicRemappedIndices.ContainsKey(nIndex1)) nNewIndex1 = pdicRemappedIndices[nIndex1];
                                }

                                if(pdicClippedEdges.ContainsKey(edgeKey2))
                                {
                                    nClippedCacheHits++;
                                    bEdgeKey2  = true;
                                    nNewIndex3 = pdicClippedEdges[edgeKey2].GetSecondIndex(nIndex3);
                                    nNewIndex5 = pdicClippedEdges[edgeKey2].nClippedIndex;
                                }
                                else
                                {
                                    nClippedCacheMisses++;
                                    if(pdicRemappedIndices.ContainsKey(nIndex3)) nNewIndex3 = pdicRemappedIndices[nIndex3];
                                }

                                // Clip if not present in clipped edge list

                                EdgeKeyByHash clippedEdgeKeyHash = new EdgeKeyByHash(nHashV1, nHashV2);

                                if(dicClipVerticesHash.ContainsKey(clippedEdgeKeyHash))
                                {
                                    nHashV4 = dicClipVerticesHash[clippedEdgeKeyHash];
                                }
                                else
                                {
                                    nHashV4 = nCurrentVertexHash++;
                                    dicClipVerticesHash.Add(clippedEdgeKeyHash, nHashV4);
                                }

                                clippedEdgeKeyHash = new EdgeKeyByHash(nHashV2, nHashV3);

                                if(dicClipVerticesHash.ContainsKey(clippedEdgeKeyHash))
                                {
                                    nHashV5 = dicClipVerticesHash[clippedEdgeKeyHash];
                                }
                                else
                                {
                                    nHashV5 = nCurrentVertexHash++;
                                    dicClipVerticesHash.Add(clippedEdgeKeyHash, nHashV5);
                                }

                                VertexData vd4 = new VertexData(nHashV4), vd5 = new VertexData(nHashV5);

                                if(bEdgeKey1 == false)
                                {
                                    if(VertexData.ClipAgainstPlane(meshDataIn.aVertexData, nIndex1, nIndex2, v1, v2, planeSplit, ref vd4) == false)
                                    {
                                        return false;
                                    }
                                }

                                if(bEdgeKey2 == false)
                                {
                                    if(VertexData.ClipAgainstPlane(meshDataIn.aVertexData, nIndex2, nIndex3, v2, v3, planeSplit, ref vd5) == false)
                                    {
                                        return false;
                                    }
                                }

					            // Add geometry of one side

                                // Add vertex data for all data not present in remapped list

                                if(nNewIndex1 == -1)
                                {
                                    nNewIndex1 = plistVertexData.Count;
                                    plistVertexData.Add(meshDataIn.aVertexData[nIndex1].Copy());
                                    pdicRemappedIndices[nIndex1] = nNewIndex1;
                                }

                                if(nNewIndex3 == -1)
                                {
                                    nNewIndex3 = plistVertexData.Count;
                                    plistVertexData.Add(meshDataIn.aVertexData[nIndex3].Copy());
                                    pdicRemappedIndices[nIndex3] = nNewIndex3;
                                }

                                if(nNewIndex4 == -1)
                                {
                                    nNewIndex4 = plistVertexData.Count;
                                    plistVertexData.Add(vd4);
                                }

                                if(nNewIndex5 == -1)
                                {
                                    nNewIndex5 = plistVertexData.Count;
                                    plistVertexData.Add(vd5);
                                }

                                if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false)
                                {
                                    pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3);
                                }

                                plistObjectIndices.Add(nNewIndex1);
                                plistObjectIndices.Add(nNewIndex4);
                                plistObjectIndices.Add(nNewIndex5);

                                if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false)
                                {
                                    pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3);
                                }

                                plistObjectIndices.Add(nNewIndex1);
                                plistObjectIndices.Add(nNewIndex5);
                                plistObjectIndices.Add(nNewIndex3);

                                Vector3 v4 = plistVertexData[nNewIndex4].v3Vertex;
                                Vector3 v5 = plistVertexData[nNewIndex5].v3Vertex;

                                if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false)
                                {
                                    pFaceConnectivity.AddEdge(nSubMesh, v1, v4, nHashV1, nHashV4, nNewIndex1, nNewIndex4);
                                    pFaceConnectivity.AddEdge(nSubMesh, v4, v5, nHashV4, nHashV5, nNewIndex4, nNewIndex5);
                                    pFaceConnectivity.AddEdge(nSubMesh, v5, v1, nHashV5, nHashV1, nNewIndex5, nNewIndex1);
                                    pFaceConnectivity.AddEdge(nSubMesh, v1, v5, nHashV1, nHashV5, nNewIndex1, nNewIndex5);
                                    pFaceConnectivity.AddEdge(nSubMesh, v5, v3, nHashV5, nHashV3, nNewIndex5, nNewIndex3);
                                    pFaceConnectivity.AddEdge(nSubMesh, v3, v1, nHashV3, nHashV1, nNewIndex3, nNewIndex1);
                                }

                                // Update cap edges and cache

                                if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV4, nHashV5, plistVertexData[nNewIndex4].v3Vertex, plistVertexData[nNewIndex5].v3Vertex);

                                if(pdicClippedEdges.ContainsKey(edgeKey1) == false) pdicClippedEdges.Add(edgeKey1, new ClippedEdge(nIndex1, nIndex2, nNewIndex1, nNewIndex2, nNewIndex4));
                                if(pdicClippedEdges.ContainsKey(edgeKey2) == false) pdicClippedEdges.Add(edgeKey2, new ClippedEdge(nIndex2, nIndex3, nNewIndex2, nNewIndex3, nNewIndex5));

                                // Add geometry of other side

					            if(fSide2 < 0.0f)
					            {
						            plistVertexData     = listVertexDataNeg;
                                    plistObjectIndices  = listIndicesNeg;
                                    pFaceConnectivity   = faceConnectivityNeg;
                                    pMeshConnectivity   = meshConnectivityNeg;
                                    pdicClippedEdges    = dicClippedEdgesNeg;
                                    pdicRemappedIndices = dicRemappedIndicesNeg;
					            }
					            else
					            {
						            plistVertexData     = listVertexDataPos;
						            plistObjectIndices  = listIndicesPos;
                                    pFaceConnectivity   = faceConnectivityPos;
                                    pMeshConnectivity   = meshConnectivityPos;
                                    pdicClippedEdges    = dicClippedEdgesPos;
                                    pdicRemappedIndices = dicRemappedIndicesPos;
					            }

                                nNewIndex1 = -1;
                                nNewIndex2 = -1;
                                nNewIndex3 = -1;
                                nNewIndex4 = -1;
                                nNewIndex5 = -1;
                                bEdgeKey1  = false;
                                bEdgeKey2  = false;

                                // Find edges in cache

                                if(pdicClippedEdges.ContainsKey(edgeKey1))
                                {
                                    nClippedCacheHits++;
                                    bEdgeKey1  = true;
                                    nNewIndex2 = pdicClippedEdges[edgeKey1].GetSecondIndex(nIndex2);
                                    nNewIndex4 = pdicClippedEdges[edgeKey1].nClippedIndex;
                                }
                                else
                                {
                                    nClippedCacheMisses++;
                                    if(pdicRemappedIndices.ContainsKey(nIndex2)) nNewIndex2 = pdicRemappedIndices[nIndex2];
                                }

                                if(pdicClippedEdges.ContainsKey(edgeKey2))
                                {
                                    nClippedCacheHits++;
                                    bEdgeKey2  = true;
                                    nNewIndex2 = pdicClippedEdges[edgeKey2].GetFirstIndex(nIndex2);
                                    nNewIndex5 = pdicClippedEdges[edgeKey2].nClippedIndex;
                                }
                                else
                                {
                                    nClippedCacheMisses++;
                                    if(pdicRemappedIndices.ContainsKey(nIndex2)) nNewIndex2 = pdicRemappedIndices[nIndex2];
                                }

                                // Add vertex data for all data not present in remapped list

                                if(nNewIndex2 == -1)
                                {
                                    nNewIndex2 = plistVertexData.Count;
                                    plistVertexData.Add(meshDataIn.aVertexData[nIndex2].Copy());
                                    pdicRemappedIndices[nIndex2] = nNewIndex2;
                                }

                                if(nNewIndex4 == -1)
                                {
                                    nNewIndex4 = plistVertexData.Count;
                                    plistVertexData.Add(vd4);
                                }

                                if(nNewIndex5 == -1)
                                {
                                    nNewIndex5 = plistVertexData.Count;
                                    plistVertexData.Add(vd5);
                                }

                                if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false)
                                {
                                    pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3);
                                }

                                plistObjectIndices.Add(nNewIndex4);
                                plistObjectIndices.Add(nNewIndex2);
                                plistObjectIndices.Add(nNewIndex5);

                                if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false)
                                {
                                    pFaceConnectivity.AddEdge(nSubMesh, v4, v2, nHashV4, nHashV2, nNewIndex4, nNewIndex2);
                                    pFaceConnectivity.AddEdge(nSubMesh, v2, v5, nHashV2, nHashV5, nNewIndex2, nNewIndex5);
                                    pFaceConnectivity.AddEdge(nSubMesh, v5, v4, nHashV5, nHashV4, nNewIndex5, nNewIndex4);
                                }

                                // Update cap edges and cache

                                if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV5, nHashV4, plistVertexData[nNewIndex5].v3Vertex, plistVertexData[nNewIndex4].v3Vertex);

                                if(pdicClippedEdges.ContainsKey(edgeKey1) == false) pdicClippedEdges.Add(edgeKey1, new ClippedEdge(nIndex1, nIndex2, nNewIndex1, nNewIndex2, nNewIndex4));
                                if(pdicClippedEdges.ContainsKey(edgeKey2) == false) pdicClippedEdges.Add(edgeKey2, new ClippedEdge(nIndex2, nIndex3, nNewIndex2, nNewIndex3, nNewIndex5));
				            }
				            else
				            {
					            // ... and v3 on same side as v2

					            if(fSide1 < 0.0f)
					            {
						            plistVertexData     = listVertexDataNeg;
						            plistObjectIndices  = listIndicesNeg;
                                    pFaceConnectivity   = faceConnectivityNeg;
                                    pMeshConnectivity   = meshConnectivityNeg;
                                    pdicClippedEdges    = dicClippedEdgesNeg;
                                    pdicRemappedIndices = dicRemappedIndicesNeg;
					            }

                                int  nNewIndex1 = -1;
                                int  nNewIndex2 = -1;
                                int  nNewIndex3 = -1;
                                int  nNewIndex4 = -1;
                                int  nNewIndex5 = -1;
                                int  nHashV4    = -1;
                                int  nHashV5    = -1;
                                bool bEdgeKey1  = false;
                                bool bEdgeKey3  = false;

                                EdgeKeyByIndex edgeKey1 = new EdgeKeyByIndex(nIndex1, nIndex2);
                                EdgeKeyByIndex edgeKey3 = new EdgeKeyByIndex(nIndex1, nIndex3);

                                // Find edges in cache

                                if(pdicClippedEdges.ContainsKey(edgeKey1))
                                {
                                    nClippedCacheHits++;
                                    bEdgeKey1  = true;
                                    nNewIndex1 = pdicClippedEdges[edgeKey1].GetFirstIndex(nIndex1);
                                    nNewIndex4 = pdicClippedEdges[edgeKey1].nClippedIndex;
                                }
                                else
                                {
                                    nClippedCacheMisses++;
                                    if(pdicRemappedIndices.ContainsKey(nIndex1)) nNewIndex1 = pdicRemappedIndices[nIndex1];
                                }

                                if(pdicClippedEdges.ContainsKey(edgeKey3))
                                {
                                    nClippedCacheHits++;
                                    bEdgeKey3  = true;
                                    nNewIndex1 = pdicClippedEdges[edgeKey3].GetFirstIndex(nIndex1);
                                    nNewIndex5 = pdicClippedEdges[edgeKey3].nClippedIndex;
                                }
                                else
                                {
                                    nClippedCacheMisses++;
                                    if(pdicRemappedIndices.ContainsKey(nIndex1)) nNewIndex1 = pdicRemappedIndices[nIndex1];
                                }

                                // Clip if not present in clipped edge list

                                EdgeKeyByHash clippedEdgeKeyHash = new EdgeKeyByHash(nHashV1, nHashV2);

                                if(dicClipVerticesHash.ContainsKey(clippedEdgeKeyHash))
                                {
                                    nHashV4 = dicClipVerticesHash[clippedEdgeKeyHash];
                                }
                                else
                                {
                                    nHashV4 = nCurrentVertexHash++;
                                    dicClipVerticesHash.Add(clippedEdgeKeyHash, nHashV4);
                                }

                                clippedEdgeKeyHash = new EdgeKeyByHash(nHashV1, nHashV3);

                                if(dicClipVerticesHash.ContainsKey(clippedEdgeKeyHash))
                                {
                                    nHashV5 = dicClipVerticesHash[clippedEdgeKeyHash];
                                }
                                else
                                {
                                    nHashV5 = nCurrentVertexHash++;
                                    dicClipVerticesHash.Add(clippedEdgeKeyHash, nHashV5);
                                }

                                VertexData vd4 = new VertexData(nHashV4), vd5 = new VertexData(nHashV5);

                                if(bEdgeKey1 == false)
                                {
                                    if(VertexData.ClipAgainstPlane(meshDataIn.aVertexData, nIndex1, nIndex2, v1, v2, planeSplit, ref vd4) == false)
                                    {
                                        return false;
                                    }
                                }

                                if(bEdgeKey3 == false)
                                {
                                    if(VertexData.ClipAgainstPlane(meshDataIn.aVertexData, nIndex1, nIndex3, v1, v3, planeSplit, ref vd5) == false)
                                    {
                                        return false;
                                    }
                                }

					            // Add geometry of one side

                                // Add vertex data for all data not present in remapped list

                                if(nNewIndex1 == -1)
                                {
                                    nNewIndex1 = plistVertexData.Count;
                                    plistVertexData.Add(meshDataIn.aVertexData[nIndex1].Copy());
                                    pdicRemappedIndices[nIndex1] = nNewIndex1;
                                }

                                if(nNewIndex4 == -1)
                                {
                                    nNewIndex4 = plistVertexData.Count;
                                    plistVertexData.Add(vd4);
                                }

                                if(nNewIndex5 == -1)
                                {
                                    nNewIndex5 = plistVertexData.Count;
                                    plistVertexData.Add(vd5);
                                }

                                if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false)
                                {
                                    pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3);
                                }

                                plistObjectIndices.Add(nNewIndex1);
                                plistObjectIndices.Add(nNewIndex4);
                                plistObjectIndices.Add(nNewIndex5);

                                Vector3 v4 = plistVertexData[nNewIndex4].v3Vertex;
                                Vector3 v5 = plistVertexData[nNewIndex5].v3Vertex;

                                if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false)
                                {
                                    pFaceConnectivity.AddEdge(nSubMesh, v1, v4, nHashV1, nHashV4, nNewIndex1, nNewIndex4);
                                    pFaceConnectivity.AddEdge(nSubMesh, v4, v5, nHashV4, nHashV5, nNewIndex4, nNewIndex5);
                                    pFaceConnectivity.AddEdge(nSubMesh, v5, v1, nHashV5, nHashV1, nNewIndex5, nNewIndex1);
                                }

                                // Update cap edges and cache

                                if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV4, nHashV5, plistVertexData[nNewIndex4].v3Vertex, plistVertexData[nNewIndex5].v3Vertex);

                                if(pdicClippedEdges.ContainsKey(edgeKey1) == false) pdicClippedEdges.Add(edgeKey1, new ClippedEdge(nIndex1, nIndex2, nNewIndex1, nNewIndex2, nNewIndex4));
                                if(pdicClippedEdges.ContainsKey(edgeKey3) == false) pdicClippedEdges.Add(edgeKey3, new ClippedEdge(nIndex1, nIndex3, nNewIndex1, nNewIndex3, nNewIndex5));

                                // Add geometry of other side

					            if(fSide2 < 0.0f)
					            {
						            plistVertexData     = listVertexDataNeg;
                                    plistObjectIndices  = listIndicesNeg;
                                    pFaceConnectivity   = faceConnectivityNeg;
                                    pMeshConnectivity   = meshConnectivityNeg;
                                    pdicClippedEdges    = dicClippedEdgesNeg;
                                    pdicRemappedIndices = dicRemappedIndicesNeg;
					            }
					            else
					            {
						            plistVertexData     = listVertexDataPos;
						            plistObjectIndices  = listIndicesPos;
                                    pFaceConnectivity   = faceConnectivityPos;
                                    pMeshConnectivity   = meshConnectivityPos;
                                    pdicClippedEdges    = dicClippedEdgesPos;
                                    pdicRemappedIndices = dicRemappedIndicesPos;
					            }

                                nNewIndex1 = -1;
                                nNewIndex2 = -1;
                                nNewIndex3 = -1;
                                nNewIndex4 = -1;
                                nNewIndex5 = -1;
                                bEdgeKey1  = false;
                                bEdgeKey3  = false;

                                // Find edges in cache

                                if(pdicClippedEdges.ContainsKey(edgeKey1))
                                {
                                    nClippedCacheHits++;
                                    bEdgeKey1  = true;
                                    nNewIndex2 = pdicClippedEdges[edgeKey1].GetSecondIndex(nIndex2);
                                    nNewIndex4 = pdicClippedEdges[edgeKey1].nClippedIndex;
                                }
                                else
                                {
                                    nClippedCacheMisses++;
                                    if(pdicRemappedIndices.ContainsKey(nIndex2)) nNewIndex2 = pdicRemappedIndices[nIndex2];
                                }

                                if(pdicClippedEdges.ContainsKey(edgeKey3))
                                {
                                    nClippedCacheHits++;
                                    bEdgeKey3  = true;
                                    nNewIndex3 = pdicClippedEdges[edgeKey3].GetSecondIndex(nIndex3);
                                    nNewIndex5 = pdicClippedEdges[edgeKey3].nClippedIndex;
                                }
                                else
                                {
                                    nClippedCacheMisses++;
                                    if(pdicRemappedIndices.ContainsKey(nIndex3)) nNewIndex3 = pdicRemappedIndices[nIndex3];
                                }

                                // Add vertex data for all data not present in remapped list

                                if(nNewIndex2 == -1)
                                {
                                    nNewIndex2 = plistVertexData.Count;
                                    plistVertexData.Add(meshDataIn.aVertexData[nIndex2].Copy());
                                    pdicRemappedIndices[nIndex2] = nNewIndex2;
                                }

                                if(nNewIndex3 == -1)
                                {
                                    nNewIndex3 = plistVertexData.Count;
                                    plistVertexData.Add(meshDataIn.aVertexData[nIndex3].Copy());
                                    pdicRemappedIndices[nIndex3] = nNewIndex3;
                                }

                                if(nNewIndex4 == -1)
                                {
                                    nNewIndex4 = plistVertexData.Count;
                                    plistVertexData.Add(vd4);
                                }

                                if(nNewIndex5 == -1)
                                {
                                    nNewIndex5 = plistVertexData.Count;
                                    plistVertexData.Add(vd5);
                                }

                                if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false)
                                {
                                    pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3);
                                }

                                plistObjectIndices.Add(nNewIndex4);
                                plistObjectIndices.Add(nNewIndex2);
                                plistObjectIndices.Add(nNewIndex3);

                                if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false)
                                {
                                    pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3);
                                }

                                plistObjectIndices.Add(nNewIndex4);
                                plistObjectIndices.Add(nNewIndex3);
                                plistObjectIndices.Add(nNewIndex5);

                                if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false)
                                {
                                    pFaceConnectivity.AddEdge(nSubMesh, v4, v2, nHashV4, nHashV2, nNewIndex4, nNewIndex2);
                                    pFaceConnectivity.AddEdge(nSubMesh, v2, v3, nHashV2, nHashV3, nNewIndex2, nNewIndex3);
                                    pFaceConnectivity.AddEdge(nSubMesh, v3, v4, nHashV3, nHashV4, nNewIndex3, nNewIndex4);
                                    pFaceConnectivity.AddEdge(nSubMesh, v4, v3, nHashV4, nHashV3, nNewIndex4, nNewIndex3);
                                    pFaceConnectivity.AddEdge(nSubMesh, v3, v5, nHashV3, nHashV5, nNewIndex3, nNewIndex5);
                                    pFaceConnectivity.AddEdge(nSubMesh, v5, v4, nHashV5, nHashV4, nNewIndex5, nNewIndex4);
                                }

                                // Update cap edges and cache

                                if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV5, nHashV4, plistVertexData[nNewIndex5].v3Vertex, plistVertexData[nNewIndex4].v3Vertex);

                                if(pdicClippedEdges.ContainsKey(edgeKey1) == false) pdicClippedEdges.Add(edgeKey1, new ClippedEdge(nIndex1, nIndex2, nNewIndex1, nNewIndex2, nNewIndex4));
                                if(pdicClippedEdges.ContainsKey(edgeKey3) == false) pdicClippedEdges.Add(edgeKey3, new ClippedEdge(nIndex1, nIndex3, nNewIndex1, nNewIndex3, nNewIndex5));
				            }
			            }
			            else if(fSide2 * fSide3 < 0.0f)
			            {
				            // v1 and v2 on same side, and v3 on different side

					        if(fSide1 < 0.0f)
					        {
						        plistVertexData     = listVertexDataNeg;
						        plistObjectIndices  = listIndicesNeg;
                                pFaceConnectivity   = faceConnectivityNeg;
                                pMeshConnectivity   = meshConnectivityNeg;
                                pdicClippedEdges    = dicClippedEdgesNeg;
                                pdicRemappedIndices = dicRemappedIndicesNeg;
					        }

                            int  nNewIndex1 = -1;
                            int  nNewIndex2 = -1;
                            int  nNewIndex3 = -1;
                            int  nNewIndex4 = -1;
                            int  nNewIndex5 = -1;
                            int  nHashV4    = -1;
                            int  nHashV5    = -1;
                            bool bEdgeKey2  = false;
                            bool bEdgeKey3  = false;

                            EdgeKeyByIndex edgeKey2 = new EdgeKeyByIndex(nIndex2, nIndex3);
                            EdgeKeyByIndex edgeKey3 = new EdgeKeyByIndex(nIndex1, nIndex3);

                            // Find edges in cache

                            if(pdicClippedEdges.ContainsKey(edgeKey2))
                            {
                                nClippedCacheHits++;
                                bEdgeKey2  = true;
                                nNewIndex2 = pdicClippedEdges[edgeKey2].GetFirstIndex(nIndex2);
                                nNewIndex5 = pdicClippedEdges[edgeKey2].nClippedIndex;
                            }
                            else
                            {
                                nClippedCacheMisses++;
                                if(pdicRemappedIndices.ContainsKey(nIndex2)) nNewIndex2 = pdicRemappedIndices[nIndex2];
                            }

                            if(pdicClippedEdges.ContainsKey(edgeKey3))
                            {
                                nClippedCacheHits++;
                                bEdgeKey3  = true;
                                nNewIndex1 = pdicClippedEdges[edgeKey3].GetFirstIndex(nIndex1);
                                nNewIndex4 = pdicClippedEdges[edgeKey3].nClippedIndex;
                            }
                            else
                            {
                                nClippedCacheMisses++;
                                if(pdicRemappedIndices.ContainsKey(nIndex1)) nNewIndex1 = pdicRemappedIndices[nIndex1];
                            }

                            // Clip if not present in clipped edge list

                            EdgeKeyByHash clippedEdgeKeyHash = new EdgeKeyByHash(nHashV1, nHashV3);

                            if(dicClipVerticesHash.ContainsKey(clippedEdgeKeyHash))
                            {
                                nHashV4 = dicClipVerticesHash[clippedEdgeKeyHash];
                            }
                            else
                            {
                                nHashV4 = nCurrentVertexHash++;
                                dicClipVerticesHash.Add(clippedEdgeKeyHash, nHashV4);
                            }

                            clippedEdgeKeyHash = new EdgeKeyByHash(nHashV2, nHashV3);

                            if(dicClipVerticesHash.ContainsKey(clippedEdgeKeyHash))
                            {
                                nHashV5 = dicClipVerticesHash[clippedEdgeKeyHash];
                            }
                            else
                            {
                                nHashV5 = nCurrentVertexHash++;
                                dicClipVerticesHash.Add(clippedEdgeKeyHash, nHashV5);
                            }

                            VertexData vd4 = new VertexData(nHashV4), vd5 = new VertexData(nHashV5);

                            if(bEdgeKey2 == false)
                            {
                                if(VertexData.ClipAgainstPlane(meshDataIn.aVertexData, nIndex2, nIndex3, v2, v3, planeSplit, ref vd5) == false)
                                {
                                    return false;
                                }
                            }

                            if(bEdgeKey3 == false)
                            {
                                if(VertexData.ClipAgainstPlane(meshDataIn.aVertexData, nIndex1, nIndex3, v1, v3, planeSplit, ref vd4) == false)
                                {
                                    return false;
                                }
                            }

					        // Add geometry of one side

                            // Add vertex data for all data not present in remapped list

                            if(nNewIndex1 == -1)
                            {
                                nNewIndex1 = plistVertexData.Count;
                                plistVertexData.Add(meshDataIn.aVertexData[nIndex1].Copy());
                                pdicRemappedIndices[nIndex1] = nNewIndex1;
                            }

                            if(nNewIndex2 == -1)
                            {
                                nNewIndex2 = plistVertexData.Count;
                                plistVertexData.Add(meshDataIn.aVertexData[nIndex2].Copy());
                                pdicRemappedIndices[nIndex2] = nNewIndex2;
                            }

                            if(nNewIndex4 == -1)
                            {
                                nNewIndex4 = plistVertexData.Count;
                                plistVertexData.Add(vd4);
                            }

                            if(nNewIndex5 == -1)
                            {
                                nNewIndex5 = plistVertexData.Count;
                                plistVertexData.Add(vd5);
                            }

                            if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false)
                            {
                                pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3);
                            }

                            plistObjectIndices.Add(nNewIndex2);
                            plistObjectIndices.Add(nNewIndex5);
                            plistObjectIndices.Add(nNewIndex4);

                            if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false)
                            {
                                pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3);
                            }

                            plistObjectIndices.Add(nNewIndex2);
                            plistObjectIndices.Add(nNewIndex4);
                            plistObjectIndices.Add(nNewIndex1);

                            Vector3 v4 = plistVertexData[nNewIndex4].v3Vertex;
                            Vector3 v5 = plistVertexData[nNewIndex5].v3Vertex;

                            if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false)
                            {
                                pFaceConnectivity.AddEdge(nSubMesh, v2, v5, nHashV2, nHashV5, nNewIndex2, nNewIndex5);
                                pFaceConnectivity.AddEdge(nSubMesh, v5, v4, nHashV5, nHashV4, nNewIndex5, nNewIndex4);
                                pFaceConnectivity.AddEdge(nSubMesh, v4, v2, nHashV4, nHashV2, nNewIndex4, nNewIndex2);
                                pFaceConnectivity.AddEdge(nSubMesh, v2, v4, nHashV2, nHashV4, nNewIndex2, nNewIndex4);
                                pFaceConnectivity.AddEdge(nSubMesh, v4, v1, nHashV4, nHashV1, nNewIndex4, nNewIndex1);
                                pFaceConnectivity.AddEdge(nSubMesh, v1, v2, nHashV1, nHashV2, nNewIndex1, nNewIndex2);
                            }

                            // Update cap edges and cache

                            if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV5, nHashV4, plistVertexData[nNewIndex5].v3Vertex, plistVertexData[nNewIndex4].v3Vertex);

                            if(pdicClippedEdges.ContainsKey(edgeKey2) == false) pdicClippedEdges.Add(edgeKey2, new ClippedEdge(nIndex2, nIndex3, nNewIndex2, nNewIndex3, nNewIndex5));
                            if(pdicClippedEdges.ContainsKey(edgeKey3) == false) pdicClippedEdges.Add(edgeKey3, new ClippedEdge(nIndex1, nIndex3, nNewIndex1, nNewIndex3, nNewIndex4));

                            // Add geometry of other side

					        if(fSide3 < 0.0f)
					        {
						        plistVertexData     = listVertexDataNeg;
                                plistObjectIndices  = listIndicesNeg;
                                pFaceConnectivity   = faceConnectivityNeg;
                                pMeshConnectivity   = meshConnectivityNeg;
                                pdicClippedEdges    = dicClippedEdgesNeg;
                                pdicRemappedIndices = dicRemappedIndicesNeg;
					        }
					        else
					        {
						        plistVertexData     = listVertexDataPos;
						        plistObjectIndices  = listIndicesPos;
                                pFaceConnectivity   = faceConnectivityPos;
                                pMeshConnectivity   = meshConnectivityPos;
                                pdicClippedEdges    = dicClippedEdgesPos;
                                pdicRemappedIndices = dicRemappedIndicesPos;
					        }

                            nNewIndex1 = -1;
                            nNewIndex2 = -1;
                            nNewIndex3 = -1;
                            nNewIndex4 = -1;
                            nNewIndex5 = -1;
                            bEdgeKey2  = false;
                            bEdgeKey3  = false;

                            // Find edges in cache

                            if(pdicClippedEdges.ContainsKey(edgeKey2))
                            {
                                nClippedCacheHits++;
                                bEdgeKey2  = true;
                                nNewIndex3 = pdicClippedEdges[edgeKey2].GetSecondIndex(nIndex3);
                                nNewIndex5 = pdicClippedEdges[edgeKey2].nClippedIndex;
                            }
                            else
                            {
                                nClippedCacheMisses++;
                                if(pdicRemappedIndices.ContainsKey(nIndex3)) nNewIndex3 = pdicRemappedIndices[nIndex3];
                            }

                            if(pdicClippedEdges.ContainsKey(edgeKey3))
                            {
                                nClippedCacheHits++;
                                bEdgeKey3  = true;
                                nNewIndex3 = pdicClippedEdges[edgeKey3].GetSecondIndex(nIndex3);
                                nNewIndex4 = pdicClippedEdges[edgeKey3].nClippedIndex;
                            }
                            else
                            {
                                nClippedCacheMisses++;
                                if(pdicRemappedIndices.ContainsKey(nIndex3)) nNewIndex3 = pdicRemappedIndices[nIndex3];
                            }

                            // Add vertex data for all data not present in remapped list

                            if(nNewIndex3 == -1)
                            {
                                nNewIndex3 = plistVertexData.Count;
                                plistVertexData.Add(meshDataIn.aVertexData[nIndex3].Copy());
                                pdicRemappedIndices[nIndex3] = nNewIndex3;
                            }

                            if(nNewIndex4 == -1)
                            {
                                nNewIndex4 = plistVertexData.Count;
                                plistVertexData.Add(vd4);
                            }

                            if(nNewIndex5 == -1)
                            {
                                nNewIndex5 = plistVertexData.Count;
                                plistVertexData.Add(vd5);
                            }

                            if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoChunkConnectionInfo == false)
                            {
                                pMeshConnectivity.NotifyNewClippedFace(meshDataIn, nSubMesh, i, nSubMesh, plistObjectIndices.Count / 3);
                            }

                            plistObjectIndices.Add(nNewIndex5);
                            plistObjectIndices.Add(nNewIndex3);
                            plistObjectIndices.Add(nNewIndex4);

                            if(fracturedComponent.GenerateIslands && splitOptions.bForceNoIslandGeneration == false)
                            {
                                pFaceConnectivity.AddEdge(nSubMesh, v5, v3, nHashV5, nHashV3, nNewIndex5, nNewIndex3);
                                pFaceConnectivity.AddEdge(nSubMesh, v3, v4, nHashV3, nHashV4, nNewIndex3, nNewIndex4);
                                pFaceConnectivity.AddEdge(nSubMesh, v4, v5, nHashV4, nHashV5, nNewIndex4, nNewIndex5);
                            }

                            // Update cap edges and cache

                            if(plistVertexData == listVertexDataPos && splitOptions.bForceNoCap == false) AddCapEdge(dicCapEdges, nHashV4, nHashV5, plistVertexData[nNewIndex4].v3Vertex, plistVertexData[nNewIndex5].v3Vertex);

                            if(pdicClippedEdges.ContainsKey(edgeKey2) == false) pdicClippedEdges.Add(edgeKey2, new ClippedEdge(nIndex2, nIndex3, nNewIndex2, nNewIndex3, nNewIndex5));
                            if(pdicClippedEdges.ContainsKey(edgeKey3) == false) pdicClippedEdges.Add(edgeKey3, new ClippedEdge(nIndex1, nIndex3, nNewIndex1, nNewIndex3, nNewIndex4));
			            }
		            }
	            }
            }

//          Debug.Log("Clipped cache hits " + nClippedCacheHits + " clipped cache misses " + nClippedCacheMisses);

            // Compute transforms

            Vector3 v3CenterPos = Vector3.zero;

            if(listVertexDataPos.Count > 0)
            {
                Vector3 v3Min = Vector3.zero, v3Max = Vector3.zero;
                MeshData.ComputeMinMax(listVertexDataPos, ref v3Min, ref v3Max);
                v3CenterPos = (v3Min + v3Max) * 0.5f;
            }

            Matrix4x4 mtxToLocalPos = Matrix4x4.TRS(v3CenterPos, meshDataIn.qRotation, meshDataIn.v3Scale).inverse;

            if(splitOptions.bVerticesAreLocal)
            {
                mtxToLocalPos = Matrix4x4.TRS(v3CenterPos, Quaternion.identity, Vector3.one).inverse;
            }

            Vector3 v3CenterNeg = Vector3.zero;

            if(listVertexDataNeg.Count > 0)
            {
                Vector3 v3Min = Vector3.zero, v3Max = Vector3.zero;
                MeshData.ComputeMinMax(listVertexDataNeg, ref v3Min, ref v3Max);
                v3CenterNeg = (v3Min + v3Max) * 0.5f;
            }

            Matrix4x4 mtxToLocalNeg = Matrix4x4.TRS(v3CenterNeg, meshDataIn.qRotation, meshDataIn.v3Scale).inverse;

            if(splitOptions.bVerticesAreLocal)
            {
                mtxToLocalNeg = Matrix4x4.TRS(v3CenterNeg, Quaternion.identity, Vector3.one).inverse;
            }

            // Resolve cap outline and add its geometry

            List<List<Vector3>> listlistResolvedCapVertices   = new List<List<Vector3>>();
            List<List<int>>     listlistResolvedCapHashValues = new List<List<int>>();

            bool bNeedsConnectivityPostprocess = false;

            Matrix4x4 mtxPlane = Matrix4x4.TRS(v3PlanePoint, Quaternion.LookRotation(Vector3.Cross(v3PlaneNormal, v3PlaneRight), v3PlaneNormal), Vector3.one);

            if(dicCapEdges.Count > 0 && splitOptions.bForceNoCap == false)
            {
                if(ResolveCap(dicCapEdges, listlistResolvedCapVertices, listlistResolvedCapHashValues, fracturedComponent))
	            {
                    if(listlistResolvedCapVertices.Count > 1)
                    {
                        // There's more than one closed cap. We need to postprocess the mesh because there may be more than one object on a side of the plane as a result of the clipping.
                        bNeedsConnectivityPostprocess = (fracturedComponent.GenerateIslands && (splitOptions.bForceNoIslandGeneration == false)) ? true : false;
                    }

                    TriangulateConstrainedDelaunay( listlistResolvedCapVertices, listlistResolvedCapHashValues, splitOptions.bForceCapVertexSoup, fracturedComponent, bNeedsConnectivityPostprocess, faceConnectivityPos, faceConnectivityNeg,
                                                    meshConnectivityPos, meshConnectivityNeg, splitOptions.nForceMeshConnectivityHash, nSplitCloseSubMesh,
                                                    mtxPlane, mtxToLocalPos, mtxToLocalNeg, v3CenterPos, v3CenterNeg,
                                                    alistIndicesPos, listVertexDataPos, alistIndicesNeg, listVertexDataNeg);
                }
                else
                {
                    if(fracturedComponent.Verbose) Debug.LogWarning("Error resolving cap");
                }
            }

            // Postprocess if necessary
            if(bNeedsConnectivityPostprocess)
            {
                // Search for multiple objects inside each meshes

                List<MeshData> listIslandsPos = MeshData.PostProcessConnectivity(meshDataIn, faceConnectivityPos, meshConnectivityPos, alistIndicesPos, listVertexDataPos, nSplitCloseSubMesh, nCurrentVertexHash, false);
                List<MeshData> listIslandsNeg = new List<MeshData>();

                if(splitOptions.bIgnoreNegativeSide == false)
                {
                    listIslandsNeg = MeshData.PostProcessConnectivity(meshDataIn, faceConnectivityNeg, meshConnectivityNeg, alistIndicesNeg, listVertexDataNeg, nSplitCloseSubMesh, nCurrentVertexHash, false);
                }

                // Sometimes we are feed a mesh with multiple islands as input. If this is the case, compute connectivity between islands at this point.

                List<MeshData> listTotalIslands = new List<MeshData>();
                listTotalIslands.AddRange(listIslandsPos);
                listTotalIslands.AddRange(listIslandsNeg);

                if(fracturedComponent.GenerateChunkConnectionInfo && splitOptions.bForceNoIslandConnectionInfo == false)
                {
                    for(int i = 0; i < listTotalIslands.Count; i++)
                    {
                        if(progress != null && listTotalIslands.Count > 10 && splitOptions.bForceNoProgressInfo == false)
                        {
                            progress("Fracturing", "Processing island connectivity...", i / (float)listTotalIslands.Count);
                            if(Fracturer.IsFracturingCancelled()) return false;
                        }

                        for(int j = 0; j < listTotalIslands.Count; j++)
                        {
                            if(i != j)
                            {
                                ComputeIslandsMeshDataConnectivity(fracturedComponent, splitOptions.bVerticesAreLocal, listTotalIslands[i], listTotalIslands[j]);
                            }
                        }
                    }
                }

                listMeshDatasPosOut.AddRange(listIslandsPos);
                listMeshDatasNegOut.AddRange(listIslandsNeg);
            }
            else
            {
                // Create new MeshDatas

                if(listVertexDataPos.Count > 0 && alistIndicesPos.Length > 0)
                {
                    MeshData newMeshData = new MeshData(meshDataIn.aMaterials, alistIndicesPos, listVertexDataPos, nSplitCloseSubMesh, v3CenterPos, meshDataIn.qRotation, meshDataIn.v3Scale, mtxToLocalPos, false, false);
                    newMeshData.meshDataConnectivity = meshConnectivityPos;
                    newMeshData.nCurrentVertexHash   = nCurrentVertexHash;
                    listMeshDatasPosOut.Add(newMeshData);
                }

                if(listVertexDataNeg.Count > 0 && alistIndicesNeg.Length > 0 && splitOptions.bIgnoreNegativeSide == false)
                {
                    MeshData newMeshData = new MeshData(meshDataIn.aMaterials, alistIndicesNeg, listVertexDataNeg, nSplitCloseSubMesh, v3CenterNeg, meshDataIn.qRotation, meshDataIn.v3Scale, mtxToLocalNeg, false, false);
                    newMeshData.meshDataConnectivity = meshConnectivityNeg;
                    newMeshData.nCurrentVertexHash   = nCurrentVertexHash;
                    listMeshDatasNegOut.Add(newMeshData);
                }
            }

            return true;
        }
        private static bool ComputeIslandsMeshDataConnectivity(FracturedObject fracturedComponent, bool bVerticesAreLocal, MeshData meshData1, MeshData meshData2)
        {
            float fMargin = fracturedComponent.ChunkIslandConnectionMaxDistance;

            // Vertices and min/max may be in local space. We want distance checks to be in world space

            Vector3 v3Min1 = meshData1.v3Min; if(bVerticesAreLocal) v3Min1 = Vector3.Scale(v3Min1, meshData1.v3Scale);
            Vector3 v3Max1 = meshData1.v3Max; if(bVerticesAreLocal) v3Max1 = Vector3.Scale(v3Max1, meshData1.v3Scale);
            Vector3 v3Min2 = meshData2.v3Min; if(bVerticesAreLocal) v3Min2 = Vector3.Scale(v3Min2, meshData2.v3Scale);
            Vector3 v3Max2 = meshData2.v3Max; if(bVerticesAreLocal) v3Max2 = Vector3.Scale(v3Max2, meshData2.v3Scale);

            if((v3Min1.x > (v3Max2.x + fMargin)) || (v3Min1.y > (v3Max2.y + fMargin)) || (v3Min1.z > (v3Max2.z + fMargin)))
            {
                return false;
            }

            if((v3Min2.x > (v3Max1.x + fMargin)) || (v3Min2.y > (v3Max1.y + fMargin)) || (v3Min2.z > (v3Max1.z + fMargin)))
            {
                return false;
            }

            bool  bConnected    = false;
            float fDistPlaneMax = fracturedComponent.ChunkIslandConnectionMaxDistance;

            for(int nSubMesh1 = 0; nSubMesh1 < meshData1.aaIndices.Length; nSubMesh1++)
            {
                for(int nFace1 = 0; nFace1 < meshData1.aaIndices[nSubMesh1].Length / 3; nFace1++)
                {
                    Vector3 v1 = meshData1.aVertexData[meshData1.aaIndices[nSubMesh1][nFace1 * 3 + 0]].v3Vertex;
                    Vector3 v2 = meshData1.aVertexData[meshData1.aaIndices[nSubMesh1][nFace1 * 3 + 1]].v3Vertex;
                    Vector3 v3 = meshData1.aVertexData[meshData1.aaIndices[nSubMesh1][nFace1 * 3 + 2]].v3Vertex;

                    if(bVerticesAreLocal)
                    {
                        v1 = Vector3.Scale(v1, meshData1.v3Scale);
                        v2 = Vector3.Scale(v2, meshData1.v3Scale);
                        v3 = Vector3.Scale(v3, meshData1.v3Scale);
                    }

                    Vector3 v3Forward = -Vector3.Cross(v2 - v1, v3 - v1);
                    float   fArea1    = v3Forward.magnitude;

                    if(fArea1 < Parameters.EPSILONCROSSPRODUCT)
                    {
                        continue;
                    }

                    Quaternion qFace     = Quaternion.LookRotation(v3Forward.normalized, (v2 - v1).normalized);
                    Matrix4x4  mtxToFace = Matrix4x4.TRS(v1, qFace, Vector3.one).inverse;

                    Plane planeFace1 = new Plane(v1, v2, v3);

                    for(int nSubMesh2 = 0; nSubMesh2 < meshData2.aaIndices.Length; nSubMesh2++)
                    {
                        for(int nFace2 = 0; nFace2 < meshData2.aaIndices[nSubMesh2].Length / 3; nFace2++)
                        {
                            Vector3 v3Other1 = meshData2.aVertexData[meshData2.aaIndices[nSubMesh2][nFace2 * 3 + 0]].v3Vertex;
                            Vector3 v3Other2 = meshData2.aVertexData[meshData2.aaIndices[nSubMesh2][nFace2 * 3 + 1]].v3Vertex;
                            Vector3 v3Other3 = meshData2.aVertexData[meshData2.aaIndices[nSubMesh2][nFace2 * 3 + 2]].v3Vertex;

                            if(bVerticesAreLocal)
                            {
                                v3Other1 = Vector3.Scale(v3Other1, meshData2.v3Scale);
                                v3Other2 = Vector3.Scale(v3Other2, meshData2.v3Scale);
                                v3Other3 = Vector3.Scale(v3Other3, meshData2.v3Scale);
                            }

                            // Compute distance from face1 to face2

                            float fDist1 = Mathf.Abs(planeFace1.GetDistanceToPoint(v3Other1)); if(fDist1 > fDistPlaneMax) continue;
                            float fDist2 = Mathf.Abs(planeFace1.GetDistanceToPoint(v3Other2)); if(fDist2 > fDistPlaneMax) continue;
                            float fDist3 = Mathf.Abs(planeFace1.GetDistanceToPoint(v3Other3)); if(fDist3 > fDistPlaneMax) continue;

                            // See if they intersect in 2D (face 1 local coordinates)

                            Vector3 v3OtherCenterLocal = (v3Other1 + v3Other2 + v3Other3) / 3.0f;
                            v3OtherCenterLocal = mtxToFace.MultiplyPoint3x4(v3OtherCenterLocal);

                            Vector3 v3Local1 = mtxToFace.MultiplyPoint3x4(v1);
                            Vector3 v3Local2 = mtxToFace.MultiplyPoint3x4(v2);
                            Vector3 v3Local3 = mtxToFace.MultiplyPoint3x4(v3);
                            Vector3 v3Edge2  = v3Local3 - v3Local2;
                            Vector3 v3Edge3  = v3Local1 - v3Local3;

                            bool bFaceConnected = false;

                            // Test the center

                            if(v3OtherCenterLocal.x >= 0.0f)
                            {
                                if(Vector3.Cross(v3Edge2, v3OtherCenterLocal - v3Local2).z <= 0.0f)
                                {
                                    if(Vector3.Cross(v3Edge3, v3OtherCenterLocal - v3Local3).z <= 0.0f)
                                    {
                                        bFaceConnected = true;
                                    }
                                }
                            }

                            if(bFaceConnected == false)
                            {
                                // Try intersecting lines

                                Vector3 v3OtherLocal1 = mtxToFace.MultiplyPoint3x4(v3Other1);
                                Vector3 v3OtherLocal2 = mtxToFace.MultiplyPoint3x4(v3Other2);
                                Vector3 v3OtherLocal3 = mtxToFace.MultiplyPoint3x4(v3Other3);

                                if(bFaceConnected == false) if(IntersectEdges2D(v3OtherLocal1.x, v3OtherLocal1.y, v3OtherLocal2.x, v3OtherLocal2.y, v3Local1.x, v3Local1.y, v3Local2.x, v3Local2.y)) bFaceConnected = true;
                                if(bFaceConnected == false) if(IntersectEdges2D(v3OtherLocal1.x, v3OtherLocal1.y, v3OtherLocal2.x, v3OtherLocal2.y, v3Local2.x, v3Local2.y, v3Local3.x, v3Local3.y)) bFaceConnected = true;
                                if(bFaceConnected == false) if(IntersectEdges2D(v3OtherLocal1.x, v3OtherLocal1.y, v3OtherLocal2.x, v3OtherLocal2.y, v3Local3.x, v3Local3.y, v3Local1.x, v3Local1.y)) bFaceConnected = true;

                                if(bFaceConnected == false) if(IntersectEdges2D(v3OtherLocal2.x, v3OtherLocal2.y, v3OtherLocal3.x, v3OtherLocal3.y, v3Local1.x, v3Local1.y, v3Local2.x, v3Local2.y)) bFaceConnected = true;
                                if(bFaceConnected == false) if(IntersectEdges2D(v3OtherLocal2.x, v3OtherLocal2.y, v3OtherLocal3.x, v3OtherLocal3.y, v3Local2.x, v3Local2.y, v3Local3.x, v3Local3.y)) bFaceConnected = true;
                                if(bFaceConnected == false) if(IntersectEdges2D(v3OtherLocal2.x, v3OtherLocal2.y, v3OtherLocal3.x, v3OtherLocal3.y, v3Local3.x, v3Local3.y, v3Local1.x, v3Local1.y)) bFaceConnected = true;

                                if(bFaceConnected == false) if(IntersectEdges2D(v3OtherLocal3.x, v3OtherLocal3.y, v3OtherLocal1.x, v3OtherLocal1.y, v3Local1.x, v3Local1.y, v3Local2.x, v3Local2.y)) bFaceConnected = true;
                                if(bFaceConnected == false) if(IntersectEdges2D(v3OtherLocal3.x, v3OtherLocal3.y, v3OtherLocal1.x, v3OtherLocal1.y, v3Local2.x, v3Local2.y, v3Local3.x, v3Local3.y)) bFaceConnected = true;
                                if(bFaceConnected == false) if(IntersectEdges2D(v3OtherLocal3.x, v3OtherLocal3.y, v3OtherLocal1.x, v3OtherLocal1.y, v3Local3.x, v3Local3.y, v3Local1.x, v3Local1.y)) bFaceConnected = true;
                            }

                            if(bFaceConnected)
                            {
                                int nHash = MeshDataConnectivity.GetNewHash(); // New hash value to identify the 2 shared faces
                                meshData1.meshDataConnectivity.NotifyNewCapFace(nHash, nSubMesh1, nFace1);
                                meshData2.meshDataConnectivity.NotifyNewCapFace(nHash, nSubMesh2, nFace2);
                                bConnected = true;
                            }
                        }
                    }
                }
            }

            return bConnected;
        }
Exemple #26
0
    void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.tag == "Stone")
        {
            if (mujuk == false)
            {
                mujuk = true;
                if (collision.contacts == null)
                {
                    return;
                }

                if (collision.contacts.Length == 0)
                {
                    return;
                }

                // Was it a big enough hit?

                FracturedObject fracturedObject = gameObject.GetComponent <FracturedObject> ();

                if (fracturedObject != null)
                {
                    float fMass = collision.rigidbody != null ? collision.rigidbody.mass : Mathf.Infinity;
                    if (collision.relativeVelocity.magnitude > fracturedObject.EventDetachMinVelocity && fMass > fracturedObject.EventDetachMinVelocity)
                    {
                        // Disable fracturable object collider
                        if (collision.rigidbody != null)
                        {
                            fracturedObject.EventDetachMinMass -= collision.rigidbody.mass;
                        }
                        if (fracturedObject.EventDetachMinMass < 0)
                        {
                            //Debug.Log (collision.gameObject.GetComponent<PhotonView> ().ownerId.ToString ());
                            //부순사람 카운트 업
                            if (collision.gameObject.GetComponent <PhotonView> ().owner.ID == 1)
                            {
                                SendKill(collision.gameObject.GetComponent <PhotonView> ().owner.ID, k1.text);
                            }
                            if (collision.gameObject.GetComponent <PhotonView> ().owner.ID == 2)
                            {
                                SendKill(collision.gameObject.GetComponent <PhotonView> ().owner.ID, k2.text);
                            }
                            if (collision.gameObject.GetComponent <PhotonView> ().owner.ID == 3)
                            {
                                SendKill(collision.gameObject.GetComponent <PhotonView> ().owner.ID, k3.text);
                            }
                            if (collision.gameObject.GetComponent <PhotonView> ().owner.ID == 4)
                            {
                                SendKill(collision.gameObject.GetComponent <PhotonView> ().owner.ID, k4.text);
                            }
                            //부셔진돌 캔버스 제거
                            fracturedObject.GetComponent <Collider> ().enabled = false;

                            Rigidbody fracturableRigidbody = fracturedObject.GetComponent <Rigidbody> ();

                            if (fracturableRigidbody != null)
                            {
                                fracturableRigidbody.isKinematic = true;
                            }
                            for (int i = 0; i < fracturedObject.ListFracturedChunks.Count; i++)
                            {
                                EnableObjectColliders(fracturedObject.ListFracturedChunks [i].gameObject, true);
                            }

                            // Explode

                            fracturedObject.Explode(collision.contacts [0].point, collision.relativeVelocity.magnitude);
                            //죽은돌 삭제
                            GameObject delStone = GameObject.Find(fracturedObject.name);
                            Destroy(delStone);
                        }
                        // Enable chunk colliders
                    }
                }
            }
            StartCoroutine("divine");
        }
    }
Exemple #27
0
            public static SpaceTreeNode BuildSpaceTree(MeshData meshDataIn, int nSubdivisionLevels, FracturedObject fracturedComponent, ProgressDelegate progress = null)
            {
                if (nSubdivisionLevels < 1)
                {
                    return(null);
                }

                SplitOptions splitOptions = new SplitOptions();

                splitOptions.bForceNoIslandGeneration     = true;
                splitOptions.bForceNoChunkConnectionInfo  = true;
                splitOptions.bForceNoIslandConnectionInfo = true;
                splitOptions.bForceNoCap       = false;
                splitOptions.bVerticesAreLocal = true;

                SpaceTreeNode nodeRoot = new SpaceTreeNode();

                nodeRoot.listMeshDatasSpace = new List <MeshData>();
                nodeRoot.listMeshDatasSpace.Add(meshDataIn);
                nodeRoot.nLevel   = 0;
                nodeRoot.nSplitsX = 0;
                nodeRoot.nSplitsY = 0;
                nodeRoot.nSplitsZ = 0;
                nodeRoot.v3Min    = meshDataIn.v3Min;
                nodeRoot.v3Max    = meshDataIn.v3Max;

                Queue <SpaceTreeNode> queueNodes = new Queue <SpaceTreeNode>();

                queueNodes.Enqueue(nodeRoot);

                int nTotalSubdivisions   = 0;
                int nCurrentSubdivisions = 0;
                int nSplitsX             = 0;
                int nSplitsY             = 0;
                int nSplitsZ             = 0;

                for (int i = 0; i < nSubdivisionLevels; i++)
                {
                    nTotalSubdivisions += Mathf.RoundToInt(Mathf.Pow(2, i));
                }

                while (queueNodes.Count > 0)
                {
                    SpaceTreeNode nodeCurrent = queueNodes.Dequeue();

                    List <MeshData> listMeshDataPos;
                    List <MeshData> listMeshDataNeg;

                    if (nodeCurrent.nLevel < nSubdivisionLevels)
                    {
                        if (progress != null)
                        {
                            progress("Fracturing", string.Format("Pre computing space volume (split {0}/{1}, Depth {2})", nCurrentSubdivisions + 1, nTotalSubdivisions, nodeCurrent.nLevel + 1), Mathf.Clamp01((float)nCurrentSubdivisions / (float)nTotalSubdivisions));
                        }

                        if (Fracturer.IsFracturingCancelled())
                        {
                            return(null);
                        }

                        Vector3 v3Normal = Vector3.up;
                        Vector3 v3Right  = Vector3.right;
                        Vector3 v3Pos    = (nodeCurrent.v3Min + nodeCurrent.v3Max) * 0.5f;

                        float fSizeX = nodeCurrent.v3Max.x - nodeCurrent.v3Min.x;
                        float fSizeY = nodeCurrent.v3Max.y - nodeCurrent.v3Min.y;
                        float fSizeZ = nodeCurrent.v3Max.z - nodeCurrent.v3Min.z;

                        Vector3 v3MinNeg = nodeCurrent.v3Min;
                        Vector3 v3MaxNeg = nodeCurrent.v3Max;
                        Vector3 v3MinPos = nodeCurrent.v3Min;
                        Vector3 v3MaxPos = nodeCurrent.v3Max;

                        if (fSizeX >= fSizeY && fSizeX >= fSizeZ)
                        {
                            v3Normal = Vector3.right;
                            v3Right  = Vector3.forward;

                            v3MaxNeg.x = v3Pos.x;
                            v3MinPos.x = v3Pos.x;

                            nSplitsX++;
                        }
                        else if (fSizeY >= fSizeX && fSizeY >= fSizeZ)
                        {
                            v3Normal = Vector3.up;
                            v3Right  = Vector3.right;

                            v3MaxNeg.y = v3Pos.y;
                            v3MinPos.y = v3Pos.y;

                            nSplitsY++;
                        }
                        else
                        {
                            v3Normal = Vector3.forward;
                            v3Right  = Vector3.right;

                            v3MaxNeg.z = v3Pos.z;
                            v3MinPos.z = v3Pos.z;

                            nSplitsZ++;
                        }

                        foreach (MeshData meshData in nodeCurrent.listMeshDatasSpace)
                        {
                            if (SplitMeshUsingPlane(meshData, fracturedComponent, splitOptions, v3Normal, v3Right, v3Pos, out listMeshDataPos, out listMeshDataNeg, progress) == true)
                            {
                                nodeCurrent.nodeOneSide = new SpaceTreeNode();
                                nodeCurrent.nodeOneSide.listMeshDatasSpace = listMeshDataNeg;
                                nodeCurrent.nodeOneSide.v3Min    = v3MinNeg;
                                nodeCurrent.nodeOneSide.v3Max    = v3MaxNeg;
                                nodeCurrent.nodeOneSide.nLevel   = nodeCurrent.nLevel + 1;
                                nodeCurrent.nodeOneSide.nSplitsX = nSplitsX;
                                nodeCurrent.nodeOneSide.nSplitsY = nSplitsY;
                                nodeCurrent.nodeOneSide.nSplitsZ = nSplitsZ;

                                queueNodes.Enqueue(nodeCurrent.nodeOneSide);

                                nodeCurrent.nodeOtherSide = new SpaceTreeNode();
                                nodeCurrent.nodeOtherSide.listMeshDatasSpace = listMeshDataPos;
                                nodeCurrent.nodeOtherSide.v3Min    = v3MinPos;
                                nodeCurrent.nodeOtherSide.v3Max    = v3MaxPos;
                                nodeCurrent.nodeOtherSide.nLevel   = nodeCurrent.nLevel + 1;
                                nodeCurrent.nodeOtherSide.nSplitsX = nSplitsX;
                                nodeCurrent.nodeOtherSide.nSplitsY = nSplitsY;
                                nodeCurrent.nodeOtherSide.nSplitsZ = nSplitsZ;

                                queueNodes.Enqueue(nodeCurrent.nodeOtherSide);
                            }
                        }

                        nCurrentSubdivisions++;
                    }
                }

                return(nodeRoot);
            }
Exemple #28
0
        static bool ResolveCap(Dictionary <EdgeKeyByHash, CapEdge> dicCapEdges, List <List <Vector3> > listlistResolvedCapVertices, List <List <int> > listlistResolvedCapHashValues, FracturedObject fracturedComponent)
        {
            if (dicCapEdges.Count < 3)
            {
                if (fracturedComponent.Verbose)
                {
                    Debug.LogWarning("Cap has < 3 segments");
                }
                return(false);
            }

            listlistResolvedCapVertices.Clear();
            listlistResolvedCapHashValues.Clear();

            List <CapEdge> listResolvedCap   = new List <CapEdge>();
            List <CapEdge> listUnresolvedCap = new List <CapEdge>(dicCapEdges.Values);
            List <Vector3> newListVertices   = new List <Vector3>();
            List <int>     newListHashValues = new List <int>();

            int nTotalSegments = listUnresolvedCap.Count;

            listResolvedCap.Add(listUnresolvedCap[0]);
            newListVertices.Add(listUnresolvedCap[0].v1);
            newListVertices.Add(listUnresolvedCap[0].v2);
            newListHashValues.Add(listUnresolvedCap[0].nHash1);
            newListHashValues.Add(listUnresolvedCap[0].nHash2);
            listUnresolvedCap.RemoveAt(0);

            // Try to match all segments

            while (listUnresolvedCap.Count > 0)
            {
                // Search for a connected segment in the unresolved segment pool

                CapEdge CapEdgeLast  = listResolvedCap[listResolvedCap.Count - 1];
                CapEdge CapEdgeFirst = listResolvedCap[0];

                bool bFound = false;

                for (int nSegmentUnresolved = 0; nSegmentUnresolved < listUnresolvedCap.Count; nSegmentUnresolved++)
                {
                    CapEdge CapEdgeUnresolved = listUnresolvedCap[nSegmentUnresolved];

                    int nSharesVertexEnd   = CapEdgeLast.SharesVertex1Of(CapEdgeUnresolved);
                    int nSharesVertexStart = CapEdgeFirst.SharesVertex2Of(CapEdgeUnresolved);

                    if (nSharesVertexEnd == 2)
                    {
                        newListVertices.Add(CapEdgeUnresolved.v2);
                        newListHashValues.Add(CapEdgeUnresolved.nHash2);
                        listResolvedCap.Add(CapEdgeUnresolved);
                        listUnresolvedCap.RemoveAt(nSegmentUnresolved);
                        bFound = true;
                        break;
                    }
                    else if (nSharesVertexStart == 1)
                    {
                        newListVertices.Insert(0, CapEdgeUnresolved.v1);
                        newListHashValues.Insert(0, CapEdgeUnresolved.nHash1);
                        listResolvedCap.Insert(0, CapEdgeUnresolved);
                        listUnresolvedCap.RemoveAt(nSegmentUnresolved);
                        bFound = true;
                        break;
                    }
                }

                bool bFinish = bFound == false;

                if (listResolvedCap.Count >= 3)
                {
                    if (listResolvedCap[listResolvedCap.Count - 1].SharesVertex1Of(listResolvedCap[0]) == 2)
                    {
                        bFinish = true;
                    }
                }

                if (listUnresolvedCap.Count == 0)
                {
                    bFinish = true;
                }

                if (bFinish)
                {
                    // Finished, new cap vertex group

                    int nTotalAdd = newListVertices.Count;

                    if (Vector3.Distance(newListVertices[0], newListVertices[newListVertices.Count - 1]) < Parameters.EPSILONDISTANCEVERTEX)
                    {
                        nTotalAdd = newListVertices.Count - 1;
                    }

                    if (nTotalAdd > 2)
                    {
                        List <Vector3> listAddVertices = new List <Vector3>();
                        List <int>     listAddHash     = new List <int>();

                        for (int i = 0; i < nTotalAdd; i++)
                        {
                            listAddVertices.Add(newListVertices[i]);
                            listAddHash.Add(newListHashValues[i]);
                        }

                        listlistResolvedCapVertices.Add(listAddVertices);
                        listlistResolvedCapHashValues.Add(listAddHash);
                    }
                    else
                    {
                        if (fracturedComponent.Verbose)
                        {
                            Debug.LogWarning("Cap group has less than 3 vertices (" + newListVertices.Count + ")");
                        }
                    }

                    if (listUnresolvedCap.Count > 0)
                    {
                        listResolvedCap.Clear();
                        listResolvedCap.Add(listUnresolvedCap[0]);
                        newListVertices.Clear();
                        newListHashValues.Clear();
                        newListVertices.Add(listUnresolvedCap[0].v1);
                        newListVertices.Add(listUnresolvedCap[0].v2);
                        newListHashValues.Add(listUnresolvedCap[0].nHash1);
                        newListHashValues.Add(listUnresolvedCap[0].nHash2);
                        listUnresolvedCap.RemoveAt(0);
                    }
                }
            }

            if (listUnresolvedCap.Count > 0)
            {
                if (fracturedComponent.Verbose)
                {
                    Debug.LogWarning(string.Format("Cap has {0}/{1} unresolved segments left", listUnresolvedCap.Count, nTotalSegments));
                }
            }

            return(true);
        }
Exemple #29
0
 // Use this for initialization
 void Awake()
 {
     fo = GetComponent <FracturedObject> ();
 }
Exemple #30
0
        static void Triangulate(List <Vector3> listVertices, List <int> listIndices, FracturedObject fracturedComponent, List <List <Vector3> > listlistPointsConstrainedDelaunay, List <List <int> > listlistHashValuesConstrainedDelaunay,
                                bool bConnectivityPostprocess, MeshFaceConnectivity faceConnectivityPos, MeshFaceConnectivity faceConnectivityNeg, MeshDataConnectivity meshConnectivityPos, MeshDataConnectivity meshConnectivityNeg, int nForceMeshConnectivityHash,
                                int nSplitCloseSubMesh, Matrix4x4 mtxPlane, Matrix4x4 mtxToLocalPos, Matrix4x4 mtxToLocalNeg, Vector3 v3CenterPos, Vector3 v3CenterNeg,
                                List <int>[] aListIndicesPosInOut, List <VertexData> listVertexDataPosInOut, List <int>[] aListIndicesNegInOut, List <VertexData> listVertexDataNegInOut)
        {
            int nPositiveSideIndexStart = listVertexDataPosInOut.Count;
            int nNegativeSideIndexStart = listVertexDataNegInOut.Count;

            if (listVertexDataPosInOut.Count < 1 || listVertexDataNegInOut.Count < 1)
            {
                return;
            }

            // Add vertex data

            VertexData[] aVtxDataCapPos = new VertexData[listVertices.Count];
            VertexData[] aVtxDataCapNeg = new VertexData[listVertices.Count];

            Vector3 v3PlaneNormal = mtxPlane.MultiplyVector(Vector3.up);

            float fReversedCapNormals = fracturedComponent.InvertCapNormals ? -1.0f : 1.0f;

            Vector3 v3CapNormalLocalPos = mtxToLocalPos.MultiplyVector(-v3PlaneNormal * fReversedCapNormals);
            Vector3 v3CapNormalLocalNeg = mtxToLocalNeg.MultiplyVector(v3PlaneNormal * fReversedCapNormals);

            Vector3 v3TangentPos = Vector3.right;

            v3TangentPos = mtxPlane.MultiplyVector(v3TangentPos);
            v3TangentPos = mtxToLocalPos.MultiplyVector(v3TangentPos);

            Vector3 v3TangentNeg = Vector3.right;

            v3TangentNeg = mtxPlane.MultiplyVector(v3TangentNeg);
            v3TangentNeg = mtxToLocalNeg.MultiplyVector(v3TangentNeg);

            Matrix4x4 mtxPlaneInverse = mtxPlane.inverse;

            Color32 colWhite  = new Color32(255, 255, 255, 255);
            Vector3 v2Mapping = Vector2.zero;

            for (int i = 0; i < listVertices.Count; i++)
            {
                Vector3 v3Local = mtxPlaneInverse.MultiplyPoint3x4(listVertices[i]);
                v2Mapping.x = v3Local.x * fracturedComponent.SplitMappingTileU;
                v2Mapping.y = v3Local.z * fracturedComponent.SplitMappingTileV;

                int nVertexHash = ComputeVertexHash(listVertices[i], listlistPointsConstrainedDelaunay, listlistHashValuesConstrainedDelaunay);

                aVtxDataCapPos[i] = new VertexData(nVertexHash, listVertices[i], v3CapNormalLocalPos, v3TangentPos, colWhite, v2Mapping, v2Mapping, true, true, listVertexDataPosInOut[0].bHasColor32, listVertexDataPosInOut[0].bHasMapping1, listVertexDataPosInOut[0].bHasMapping2);
                aVtxDataCapNeg[i] = new VertexData(nVertexHash, listVertices[i], v3CapNormalLocalNeg, v3TangentNeg, colWhite, v2Mapping, v2Mapping, true, true, listVertexDataNegInOut[0].bHasColor32, listVertexDataNegInOut[0].bHasMapping1, listVertexDataNegInOut[0].bHasMapping2);
            }

            listVertexDataPosInOut.AddRange(aVtxDataCapPos);
            listVertexDataNegInOut.AddRange(aVtxDataCapNeg);

            // Add indices

            for (int i = 0; i < listIndices.Count / 3; i++)
            {
                int nTriangleA = listIndices[i * 3 + 0];
                int nTriangleB = listIndices[i * 3 + 1];
                int nTriangleC = listIndices[i * 3 + 2];

                int nHashPosA = listVertexDataPosInOut[nPositiveSideIndexStart + nTriangleA].nVertexHash;
                int nHashPosB = listVertexDataPosInOut[nPositiveSideIndexStart + nTriangleB].nVertexHash;
                int nHashPosC = listVertexDataPosInOut[nPositiveSideIndexStart + nTriangleC].nVertexHash;

                int nHashNegA = listVertexDataNegInOut[nNegativeSideIndexStart + nTriangleA].nVertexHash;
                int nHashNegB = listVertexDataNegInOut[nNegativeSideIndexStart + nTriangleB].nVertexHash;
                int nHashNegC = listVertexDataNegInOut[nNegativeSideIndexStart + nTriangleC].nVertexHash;

                if (nHashPosA != -1 && nHashPosB != -1 && nHashPosC != -1 && nHashNegA != -1 && nHashNegB != -1 && nHashNegC != -1)
                {
                    int nMeshConnectivityHash = nForceMeshConnectivityHash == -1 ? MeshDataConnectivity.GetNewHash() : nForceMeshConnectivityHash; // New hash value to identify the 2 shared faces

                    if (fracturedComponent.GenerateChunkConnectionInfo)
                    {
                        meshConnectivityPos.NotifyNewCapFace(nMeshConnectivityHash, nSplitCloseSubMesh, aListIndicesPosInOut[nSplitCloseSubMesh].Count / 3);
                    }

                    aListIndicesPosInOut[nSplitCloseSubMesh].Add(nPositiveSideIndexStart + nTriangleA);
                    aListIndicesPosInOut[nSplitCloseSubMesh].Add(nPositiveSideIndexStart + nTriangleB);
                    aListIndicesPosInOut[nSplitCloseSubMesh].Add(nPositiveSideIndexStart + nTriangleC);

                    if (bConnectivityPostprocess)
                    {
                        faceConnectivityPos.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleA], listVertices[nTriangleB], nHashPosA, nHashPosB, nPositiveSideIndexStart + nTriangleA, nPositiveSideIndexStart + nTriangleB);
                        faceConnectivityPos.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleB], listVertices[nTriangleC], nHashPosB, nHashPosC, nPositiveSideIndexStart + nTriangleB, nPositiveSideIndexStart + nTriangleC);
                        faceConnectivityPos.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleC], listVertices[nTriangleA], nHashPosC, nHashPosA, nPositiveSideIndexStart + nTriangleC, nPositiveSideIndexStart + nTriangleA);
                    }

                    if (fracturedComponent.GenerateChunkConnectionInfo)
                    {
                        meshConnectivityNeg.NotifyNewCapFace(nMeshConnectivityHash, nSplitCloseSubMesh, aListIndicesNegInOut[nSplitCloseSubMesh].Count / 3);
                    }

                    aListIndicesNegInOut[nSplitCloseSubMesh].Add(nNegativeSideIndexStart + nTriangleA);
                    aListIndicesNegInOut[nSplitCloseSubMesh].Add(nNegativeSideIndexStart + nTriangleC);
                    aListIndicesNegInOut[nSplitCloseSubMesh].Add(nNegativeSideIndexStart + nTriangleB);

                    if (bConnectivityPostprocess)
                    {
                        faceConnectivityNeg.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleA], listVertices[nTriangleC], nHashNegA, nHashNegC, nNegativeSideIndexStart + nTriangleA, nNegativeSideIndexStart + nTriangleC);
                        faceConnectivityNeg.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleC], listVertices[nTriangleB], nHashNegC, nHashNegB, nNegativeSideIndexStart + nTriangleC, nNegativeSideIndexStart + nTriangleB);
                        faceConnectivityNeg.AddEdge(nSplitCloseSubMesh, listVertices[nTriangleB], listVertices[nTriangleA], nHashNegB, nHashNegA, nNegativeSideIndexStart + nTriangleB, nNegativeSideIndexStart + nTriangleA);
                    }
                }
            }
        }
Exemple #31
0
 void Awake()
 {
     _fracturedObject = GetComponentInChildren <FracturedObject>();
     _chunkList       = GetComponentsInChildren <FracturedChunk>().ToList();
     _changeColor     = GetComponent <ChangeColor>();
 }
Exemple #32
0
 // Use this for initialization
 void Start()
 {
     _fracturedObject = GetComponentInChildren <FracturedObject>();
     _chunkList       = GetComponentsInChildren <Transform>().Where(x => x.gameObject.layer != Layers.Radar.Index).ToList();
     _trailRenderer   = GetComponentInChildren <TrailRenderer>();
 }