Exemplo n.º 1
0
    public GameObject[] severByJoint(GameObject go, string jointName, float rootTipProgression, Vector3?planeNormal)
    {
        rootTipProgression = Mathf.Clamp01(rootTipProgression);

        //These here are in local space because they're only used to copy to the resultant meshes; they're not used
        //to transform the vertices. We expect a world-space slice input.

        Hackable hackable = null;

        {
            Hackable[] hackables = go.GetComponentsInChildren <Hackable>();

            if (hackables.Length > 0)
            {
                if (hackables.Length > 1)
                {
                    Debug.LogWarning("Limb Hacker found multiple slice configurations on object '" + go.name + "' in scene '" + Application.loadedLevelName + "'! Behavior is undefined.");
                }

                hackable = hackables[0];
            }
        }

        //We need information about which BONES are getting severed.

        var allBones = LimbHacker.FindBonesInTree(go);

        var childTransformByName = new Dictionary <string, Transform>();
        var parentKeyByKey       = new Dictionary <string, string>();

        foreach (Transform t in GetConcatenatedHierarchy(go.transform))
        {
            childTransformByName[t.name] = t;

            Transform parent = t.parent;

            if (t == go.transform)
            {
                parent = null;
            }

            parentKeyByKey[t.name] = parent == null ? null : parent.name;
        }

        var severedByChildName = new Dictionary <string, bool>();

        {
            foreach (string childName in childTransformByName.Keys)
            {
                severedByChildName[childName] = childName == jointName;
            }

            bool changesMade;
            do
            {
                changesMade = false;

                foreach (string childKey in childTransformByName.Keys)
                {
                    bool severed = severedByChildName[childKey];

                    if (severed)
                    {
                        continue;
                    }

                    string parentKey = parentKeyByKey[childKey];

                    bool parentSevered;

                    if (severedByChildName.TryGetValue(parentKey, out parentSevered) == false)
                    {
                        continue;
                    }

                    if (parentSevered)
                    {
                        severedByChildName[childKey] = true;

                        changesMade = true;
                    }
                }
            }while(changesMade);
        }

        GameObject frontObject, backObject;

        {
            var bonePresenceFront = new Dictionary <string, bool>();
            var bonePresenceBack  = new Dictionary <string, bool>();

            foreach (KeyValuePair <string, bool> kvp in severedByChildName)
            {
                bonePresenceFront[kvp.Key] = kvp.Value;
                bonePresenceBack[kvp.Key]  = !kvp.Value;
            }

            createResultObjects(go, hackable, childTransformByName, bonePresenceFront, bonePresenceBack, out frontObject, out backObject);
        }

        var skinnedMeshRenderers = go.GetComponentsInChildren <SkinnedMeshRenderer>(true);

        foreach (var smr in skinnedMeshRenderers)
        {
            var m = smr.sharedMesh;
            LoadSkinnedMeshRendererIntoCache(smr, true);

            var severedByBoneIndex   = new Dictionary <int, bool>();
            var mandatoryByBoneIndex = new bool[smr.bones.Length];

            string severedJointKey = jointName;

            Dictionary <string, int> boneIndexByName  = new Dictionary <string, int>();
            List <string>            orderedBoneNames = new List <string>();

            foreach (Transform bone in smr.bones)
            {
                boneIndexByName[bone.name] = orderedBoneNames.Count;
                orderedBoneNames.Add(bone.name);
            }

            for (int boneIndex = 0; boneIndex < orderedBoneNames.Count; boneIndex++)
            {
                string boneName = orderedBoneNames[boneIndex];

                severedByBoneIndex[boneIndex] = severedByChildName[boneName];
            }

            Vector4 plane = Vector4.zero;

            bool willSliceThisMesh = boneIndexByName.ContainsKey(severedJointKey);

            if (willSliceThisMesh)
            {
                //We need to create a slice plane in local space. We're going to do that by using the bind poses
                //from the SEVERED limb, its PARENT and its CHILDREN to create a position and normal.

                Matrix4x4[] orderedBindPoses = smr.sharedMesh.bindposes;

                int severedJointIndex = boneIndexByName[severedJointKey];

                Matrix4x4 severedJointMatrix = orderedBindPoses[severedJointIndex].inverse;

                Matrix4x4 severedJointParentMatrix = Matrix4x4.identity;

                if (parentKeyByKey.ContainsKey(severedJointKey))
                {
                    string severedJointParentKey = parentKeyByKey[severedJointKey];

                    if (boneIndexByName.ContainsKey(severedJointParentKey))
                    {
                        int severedJointParentIndex = boneIndexByName[severedJointParentKey];

                        severedJointParentMatrix = orderedBindPoses[severedJointParentIndex].inverse;
                    }
                }

                VectorAccumulator meanChildPosition = new VectorAccumulator();

                for (int i = 0; i < boneIndexByName.Count; i++)
                {
                    mandatoryByBoneIndex[i] = false;
                }

                if (parentKeyByKey.ContainsKey(severedJointKey))
                {
                    string parentKey = parentKeyByKey[severedJointKey];
                    if (boneIndexByName.ContainsKey(parentKey))
                    {
                        mandatoryByBoneIndex[boneIndexByName[parentKey]] = true;
                    }
                }

                if (rootTipProgression > 0f)
                {
                    mandatoryByBoneIndex[boneIndexByName[jointName]] = true;

                    List <string> childKeys = new List <string>();
                    foreach (KeyValuePair <string, string> kvp in parentKeyByKey)
                    {
                        if (kvp.Value == severedJointKey)
                        {
                            childKeys.Add(kvp.Key);
                        }
                    }

                    List <int> childIndices = new List <int>();
                    foreach (string key in childKeys)
                    {
                        int childIndex;

                        if (boneIndexByName.TryGetValue(key, out childIndex))
                        {
                            childIndices.Add(childIndex);
                        }
                    }

                    foreach (int index in childIndices)
                    {
                        Matrix4x4 childMatrix = orderedBindPoses[index].inverse;

                        Vector3 childPosition = childMatrix.MultiplyPoint3x4(Vector3.zero);

                        meanChildPosition.addFigure(childPosition);
                    }
                }

                Vector3 position0 = severedJointParentMatrix.MultiplyPoint3x4(Vector3.zero);
                Vector3 position1 = severedJointMatrix.MultiplyPoint3x4(Vector3.zero);
                Vector3 position2 = meanChildPosition.mean;

                Vector3 deltaParent   = position0 - position1;
                Vector3 deltaChildren = position1 - position2;

                Vector3 position = Vector3.Lerp(position1, position2, rootTipProgression);

                Vector3 normalFromParentToChild = -Vector3.Lerp(deltaParent, deltaChildren, rootTipProgression).normalized;

                if (planeNormal.HasValue)
                {
                    Matrix4x4 fromWorldToLocalSpaceOfBone = smr.bones[severedJointIndex].worldToLocalMatrix;

                    Vector3 v = planeNormal.Value;
                    v = fromWorldToLocalSpaceOfBone.MultiplyVector(v);
                    v = severedJointMatrix.MultiplyVector(v);
                    v.Normalize();

                    if (Vector3.Dot(v, normalFromParentToChild) < 0f)
                    {
                        v = -v;
                    }

                    v = MuffinSliceCommon.clampNormalToBicone(v, normalFromParentToChild, 30f);

                    planeNormal = v;
                }
                else
                {
                    planeNormal = normalFromParentToChild;
                }

                plane = (Vector4)planeNormal.Value;

                plane.w = -(plane.x * position.x + plane.y * position.y + plane.z * position.z);
            }

            //We're going to create two new tentative meshes which contain ALL original vertices in order,
            //plus room for new vertices. Not all of these copied vertices will be addressed, but copying them
            //over eliminates the need to remove doubles and do an On^2 search.

            int submeshCount = c.indices.Length;

            TurboList <int>[] _frontIndices = new TurboList <int> [submeshCount];
            TurboList <int>[] _backIndices  = new TurboList <int> [submeshCount];

            PlaneTriResult[] sidePlanes = new PlaneTriResult[c.vertices.Count];
            {
                BoneWeight[] weights  = c.weights.array;
                Vector3[]    vertices = c.vertices.array;
                int          count    = c.vertices.Count;

                bool[] whollySeveredByVertexIndex = new bool[count];
                bool[] severableByVertexIndex     = new bool[count];
                bool[] mandatoryByVertexIndex     = new bool[count];

                const float minimumWeightForRelevance = 0.1f;

                for (int i = 0; i < severableByVertexIndex.Length; i++)
                {
                    BoneWeight weight = weights[i];

                    bool whollySevered = true;
                    bool severable     = false;
                    bool mandatory     = false;

                    int[]   indices       = { weight.boneIndex0, weight.boneIndex1, weight.boneIndex2, weight.boneIndex3 };
                    float[] scalarWeights = { weight.weight0, weight.weight1, weight.weight2, weight.weight3 };

                    for (int j = 0; j < 4; j++)
                    {
                        if (scalarWeights[j] > minimumWeightForRelevance)
                        {
                            int  index      = indices[j];
                            bool _severable = severedByBoneIndex[index];
                            bool _mandatory = mandatoryByBoneIndex[index];
                            whollySevered &= _severable;
                            severable     |= _severable;
                            mandatory     |= _mandatory;
                        }
                    }

                    whollySeveredByVertexIndex[i] = whollySevered;
                    severableByVertexIndex[i]     = severable;
                    mandatoryByVertexIndex[i]     = mandatory;
                }

                for (int i = 0; i < sidePlanes.Length; i++)
                {
                    if (willSliceThisMesh && mandatoryByVertexIndex[i])
                    {
                        sidePlanes[i] = MuffinSliceCommon.getSidePlane(ref vertices[i], ref plane);
                    }
                    else if (whollySeveredByVertexIndex[i])
                    {
                        sidePlanes[i] = PlaneTriResult.PTR_FRONT;
                    }
                    else if (willSliceThisMesh && severableByVertexIndex[i])
                    {
                        sidePlanes[i] = MuffinSliceCommon.getSidePlane(ref vertices[i], ref plane);
                    }
                    else
                    {
                        sidePlanes[i] = PlaneTriResult.PTR_BACK;
                    }
                }
            }

            TurboList <int> frontInfill = null;
            TurboList <int> backInfill  = null;

            for (int j = 0; j < submeshCount; j++)
            {
                int initialCapacityIndices = Mathf.RoundToInt((float)c.indices[j].Length * factorOfSafetyIndices);

                _frontIndices[j] = new TurboList <int>(initialCapacityIndices);
                _backIndices[j]  = new TurboList <int>(initialCapacityIndices);

                if (hackable.infillMaterial != null && c.mats[j] == hackable.infillMaterial)
                {
                    frontInfill = _frontIndices[j];
                    backInfill  = _backIndices[j];
                }
            }

            if (hackable.infillMaterial != null && frontInfill == null)
            {
                frontInfill = new TurboList <int>(1024);
                backInfill  = new TurboList <int>(1024);
            }

            for (int j = 0; j < submeshCount; j++)
            {
                int initialCapacityIndices = Mathf.RoundToInt((float)c.indices[j].Length * factorOfSafetyIndices);

                int[] _indices = c.indices[j];

                TurboList <int> frontIndices = _frontIndices[j];
                TurboList <int> backIndices  = _backIndices[j];
                TurboList <int> splitPending = new TurboList <int>(initialCapacityIndices);

                int[] indices = new int[3];

                for (int i = 0; i < _indices.Length;)
                {
                    indices[0] = _indices[i++];
                    indices[1] = _indices[i++];
                    indices[2] = _indices[i++];

                    // compute the side of the plane each vertex is on
                    PlaneTriResult r1 = sidePlanes[indices[0]];
                    PlaneTriResult r2 = sidePlanes[indices[1]];
                    PlaneTriResult r3 = sidePlanes[indices[2]];

                    if (r1 == r2 && r1 == r3)                       // if all three vertices are on the same side of the plane.
                    {
                        if (r1 == PlaneTriResult.PTR_FRONT)         // if all three are in front of the plane, then copy to the 'front' output triangle.
                        {
                            frontIndices.AddArray(indices);
                        }
                        else
                        {
                            backIndices.AddArray(indices);
                        }
                    }
                    else if (willSliceThisMesh)
                    {
                        splitPending.AddArray(indices);
                    }
                }

                if (willSliceThisMesh)
                {
                    splitTrianglesLH(plane, c.vertices.array, sidePlanes, splitPending.ToArray(), c, frontIndices, backIndices, hackable.infillMode, frontInfill, backInfill);
                }
            }

            if (hackable.infillMaterial != null)
            {
                bool alreadyPresent = System.Array.IndexOf <Material>(c.mats, hackable.infillMaterial) >= 0;

                if (!alreadyPresent)
                {
                    int oldLength = c.mats.Length, newLength = c.mats.Length + 1;

                    Material[] newMats = new Material[newLength];
                    System.Array.Copy(c.mats, newMats, oldLength);
                    newMats[newLength - 1] = hackable.infillMaterial;
                    c.mats = newMats;

                    TurboList <int>[] indexArray;

                    indexArray = new TurboList <int> [newLength];
                    System.Array.Copy(_backIndices, indexArray, oldLength);
                    indexArray[newLength - 1] = backInfill;
                    _backIndices = indexArray;

                    indexArray = new TurboList <int> [newLength];
                    System.Array.Copy(_frontIndices, indexArray, oldLength);
                    indexArray[newLength - 1] = frontInfill;
                    _frontIndices             = indexArray;

                    submeshCount++;
                }
            }

            Vector3[]    geoSubsetOne, geoSubsetTwo;
            Vector3[]    normalsSubsetOne, normalsSubsetTwo;
            Vector2[]    uvSubsetOne, uvSubsetTwo;
            BoneWeight[] weightSubsetOne, weightSubsetTwo;
            int[][]      indexSubsetOne, indexSubsetTwo;

            indexSubsetOne = new int[submeshCount][];
            indexSubsetTwo = new int[submeshCount][];

            targetSubsetOne.Clear();
            targetSubsetTwo.Clear();

            int transferTableMaximumKey = c.vertices.Count;

            int[] transferTableOne = new int[transferTableMaximumKey];
            int[] transferTableTwo = new int[transferTableMaximumKey];

            for (int i = 0; i < transferTableOne.Length; i++)
            {
                transferTableOne[i] = -1;
            }
            for (int i = 0; i < transferTableTwo.Length; i++)
            {
                transferTableTwo[i] = -1;
            }

            for (int i = 0; i < submeshCount; i++)
            {
                perfectSubsetRD(_frontIndices[i], c.vertices, c.normals, c.UVs, c.weights, out indexSubsetOne[i], targetSubsetOne, ref transferTableOne);
            }

            for (int i = 0; i < submeshCount; i++)
            {
                perfectSubsetRD(_backIndices[i], c.vertices, c.normals, c.UVs, c.weights, out indexSubsetTwo[i], targetSubsetTwo, ref transferTableTwo);
            }

            //Note that we do not explicitly call recalculate bounds because (as per the manual) this is implicit in an
            //assignment to vertices whenever the vertex count changes from zero to non-zero.

            Mesh frontMesh = new Mesh();
            Mesh backMesh  = new Mesh();

            var frontSMR = GetSkinnedMeshRendererWithName(frontObject, smr.name);
            var backSMR  = GetSkinnedMeshRendererWithName(backObject, smr.name);

            if (targetSubsetOne.vertices.Count > 0)
            {
                frontSMR.materials     = c.mats;
                frontSMR.sharedMesh    = frontMesh;
                frontMesh.vertices     = targetSubsetOne.vertices.ToArray();
                frontMesh.normals      = targetSubsetOne.normals.ToArray();
                frontMesh.uv           = targetSubsetOne.UVs.ToArray();
                frontMesh.boneWeights  = targetSubsetOne.weights.ToArray();
                frontMesh.subMeshCount = submeshCount;
                frontMesh.bindposes    = m.bindposes;

                for (int i = 0; i < submeshCount; i++)
                {
                    frontMesh.SetTriangles(indexSubsetOne[i], i);
                }
            }
            else
            {
                GameObject.DestroyImmediate(frontSMR);
            }

            if (targetSubsetTwo.vertices.Count > 0)
            {
                backSMR.materials     = c.mats;
                backSMR.sharedMesh    = backMesh;
                backMesh.vertices     = targetSubsetTwo.vertices.ToArray();
                backMesh.normals      = targetSubsetTwo.normals.ToArray();
                backMesh.uv           = targetSubsetTwo.UVs.ToArray();
                backMesh.boneWeights  = targetSubsetTwo.weights.ToArray();
                backMesh.subMeshCount = submeshCount;
                backMesh.bindposes    = m.bindposes;

                for (int i = 0; i < submeshCount; i++)
                {
                    backMesh.SetTriangles(indexSubsetTwo[i], i);
                }
            }
            else
            {
                GameObject.DestroyImmediate(backSMR);
            }
        }

        var results = new GameObject[] {
            frontObject, backObject
        };

        hackable.handleSlice(results);

        return(results);
    }
Exemplo n.º 2
0
    private GameObject[] _splitByPlane(GameObject go, Vector4 planeInLocalSpace, bool destroyOriginal, bool callHandlers = true)
    {
        Sliceable sliceable = ensureSliceable(go);

        if(!sliceable.currentlySliceable)
        {
            GameObject[] result = { go };

            return result;
        }

        InfillConfiguration[] ourInfills = sliceable.infillers.Length > 0 ? sliceable.infillers : new InfillConfiguration[0];

        MeshCache c = null;
        do
        {
            Mesh m = getMesh(sliceable);

            if(m == null)
            {
                break;
            }

            if(meshCaches.ContainsKey(m))
            {
                c = meshCaches[m];
            }
            else
                c = cacheFromGameObject(sliceable, true);
        }
        while(false);
        if(c == null)
        {
            Debug.LogWarning("Turbo Slicer cannot find mesh filter in object '" + go.name + "' in scene '" + Application.loadedLevelName + "'! Only objects featuring a mesh filter can be sliced.");

            GameObject[] result = { go };

            return result;
        }

        int submeshCount = c.indices.Length;

        //We're going to create two new tentative meshes which contain ALL original vertices in order,
        //plus room for new vertices. Not all of these copied vertices will be addressed, but copying them
        //over eliminates the need to remove doubles and do an On^2 search.

        TurboList<int>[] _frontIndices = new TurboList<int>[ submeshCount ];
        TurboList<int>[] _backIndices = new TurboList<int>[ submeshCount ];

        PlaneTriResult[] sidePlanes = new PlaneTriResult[c.vertices.Count];
        {
            Vector3[] vertices = c.vertices.array;

            for(int i = 0; i < sidePlanes.Length; i++)
            {
                sidePlanes[i] = MuffinSliceCommon.getSidePlane(ref vertices[i], ref planeInLocalSpace);
            }
        }

        for(int j = 0; j < submeshCount; j++)
        {
            int initialCapacityIndices = Mathf.RoundToInt((float) c.indices[j].Length * factorOfSafetyIndices);

            _frontIndices[j] = new TurboList<int>(initialCapacityIndices);
            _backIndices[j] = new TurboList<int>(initialCapacityIndices);

            int[] _indices = c.indices[j];

            TurboList<int> frontIndices = _frontIndices[j];
            TurboList<int> backIndices = _backIndices[j];
            TurboList<int> splitPending = new TurboList<int>(initialCapacityIndices);

            int[] indices = new int[3];

            for(int i = 0; i < _indices.Length; )
            {
                indices[0] = _indices[i++];
                indices[1] = _indices[i++];
                indices[2] = _indices[i++];

                // compute the side of the plane each vertex is on
                PlaneTriResult r1 = sidePlanes[indices[0]];
                PlaneTriResult r2 = sidePlanes[indices[1]];
                PlaneTriResult r3 = sidePlanes[indices[2]];

                if ( r1 == r2 && r1 == r3 ) // if all three vertices are on the same side of the plane.
                {
                    if ( r1 == PlaneTriResult.PTR_FRONT ) // if all three are in front of the plane, then copy to the 'front' output triangle.
                    {
                        frontIndices.AddArray(indices);
                    }
                    else
                    {
                        backIndices.AddArray(indices);
                    }
                }
                else
                {
                    splitPending.AddArray(indices);
                }
            }

            InfillConfiguration ifc = null;

            if(j < c.mats.Length)
            {
                Material mat = c.mats[j];

                foreach(InfillConfiguration _ifc in ourInfills)
                {
                    if(_ifc.material == mat)
                    {
                        ifc = _ifc;
                    }
                }
            }

            if(splitPending.Count > 0)
            {
                splitTriangles(planeInLocalSpace, splitPending.ToArray(), c, ifc, frontIndices, backIndices);
            }
        }

        GameObject[] results;

        bool onlyHaveOne = true;

        for(int i = 0; i < c.indices.Length; i++)
        {
            onlyHaveOne &= _frontIndices[i].Count == 0 || _backIndices[i].Count == 0;
        }

        if(onlyHaveOne)
        {
            //Do nothing
            results = new GameObject[1];
            results[0] = go;
        }
        else
        {
            MeshCache frontCache = new MeshCache();
            frontCache.vertices = c.vertices;
            if(sliceable.channelNormals)
                frontCache.normals = c.normals;
            frontCache.coords = c.coords;
            frontCache.coords2 = c.coords2;
            frontCache.mats = c.mats;

            MeshCache backCache = new MeshCache();
            backCache.vertices = c.vertices;
            if(sliceable.channelNormals)
                backCache.normals = c.normals;
            backCache.coords = c.coords;
            backCache.coords2 = c.coords2;
            backCache.mats = c.mats;

            frontCache.indices = new int[submeshCount][];
            backCache.indices = new int[submeshCount][];
            for(int i = 0; i < submeshCount; i++)
            {
                frontCache.indices[i] = _frontIndices[i].ToArray();
                backCache.indices[i] = _backIndices[i].ToArray();
            }

            Vector3[] geoSubsetOne, geoSubsetTwo;
            Vector3[] normalsSubsetOne = null, normalsSubsetTwo = null;
            Vector2[] uvSubsetOne, uvSubsetTwo;
            Vector2[] uv2SubsetOne = null, uv2SubsetTwo = null;
            int[][] indexSubsetOne, indexSubsetTwo;

            indexSubsetOne = new int[submeshCount][];
            indexSubsetTwo = new int[submeshCount][];

            //Perfect subset will inflate the array list size if needed to the exact figure. So if we estimate 0,
            //and there is 1 submesh, than we will have 1 allocation, and this is optimal. Estimation can only help
            //if we have THREE or more submeshes, which is a silly scenario for anyone concerned about performance.
            int estimateOne = 0, estimateTwo = 0;

            TurboList<Vector3>
                _geoSubsetOne = null, _geoSubsetTwo = null,
                _normalSubsetOne = null, _normalSubsetTwo = null;

            TurboList<Vector2>
                _uvSubsetOne = null, _uvSubsetTwo = null;

            TurboList<Vector2>
                _uv2SubsetOne = null, _uv2SubsetTwo = null;

            _geoSubsetOne = new TurboList<Vector3>(estimateOne);
            _geoSubsetTwo = new TurboList<Vector3>(estimateTwo);

            if(sliceable.channelNormals)
            {
                _normalSubsetOne = new TurboList<Vector3>(estimateOne);
                _normalSubsetTwo = new TurboList<Vector3>(estimateTwo);
            }

            _uvSubsetOne = new TurboList<Vector2>(estimateOne);
            _uvSubsetTwo = new TurboList<Vector2>(estimateTwo);

            if(sliceable.channelUV2)
            {
                _uv2SubsetOne = new TurboList<Vector2>(estimateOne);
                _uv2SubsetTwo = new TurboList<Vector2>(estimateTwo);
            }

            int transferTableMaximumKey = c.vertices.Count;

            int[] transferTableOne = new int[transferTableMaximumKey];
            int[] transferTableTwo = new int[transferTableMaximumKey];

            for(int i = 0; i < transferTableOne.Length; i++) transferTableOne[i] = -1;
            for(int i = 0; i < transferTableTwo.Length; i++) transferTableTwo[i] = -1;

            for(int i = 0; i < submeshCount; i++)
                perfectSubset(_frontIndices[i], c.vertices, c.normals, c.coords, c.coords2, out indexSubsetOne[i], _geoSubsetOne, _normalSubsetOne, _uvSubsetOne, _uv2SubsetOne, ref transferTableOne );

            for(int i = 0; i < submeshCount; i++)
                perfectSubset(_backIndices[i], c.vertices, c.normals, c.coords, c.coords2, out indexSubsetTwo[i], _geoSubsetTwo, _normalSubsetTwo, _uvSubsetTwo, _uv2SubsetTwo, ref transferTableTwo );

            geoSubsetOne = _geoSubsetOne.ToArray();
            geoSubsetTwo = _geoSubsetTwo.ToArray();
            if(sliceable.channelNormals)
            {
                normalsSubsetOne = _normalSubsetOne.ToArray();
                normalsSubsetTwo = _normalSubsetTwo.ToArray();
            }
            uvSubsetOne = _uvSubsetOne.ToArray();
            uvSubsetTwo = _uvSubsetTwo.ToArray();

            if(sliceable.channelUV2)
            {
                uv2SubsetOne = _uv2SubsetOne.ToArray();
                uv2SubsetTwo = _uv2SubsetTwo.ToArray();
            }

            //Note that we do not explicitly call recalculate bounds because (as per the manual) this is implicit in an
            //assignment to vertices whenever the vertex count changes from zero to non-zero.

            Mesh frontMesh = new Mesh();
            Mesh backMesh = new Mesh();

            GameObject frontObject, backObject;

            createResultObjects(go, sliceable, false, planeInLocalSpace, out frontObject, out backObject);

            ensureSliceable(frontObject);
            ensureSliceable(backObject);

            setMesh(frontObject.GetComponent<Sliceable>(), frontMesh);
            setMesh(backObject.GetComponent<Sliceable>(), backMesh);

            frontMesh.vertices = geoSubsetOne;
            backMesh.vertices = geoSubsetTwo;

            if(sliceable.channelTangents)
            {
                Vector4[] tangentsOne, tangentsTwo;

                int[] concatenatedIndicesOne = concatenateIndexArrays(indexSubsetOne);
                int[] concatenatedIndicesTwo = concatenateIndexArrays(indexSubsetTwo);

                RealculateTangents(geoSubsetOne, normalsSubsetOne, uvSubsetOne, concatenatedIndicesOne, out tangentsOne);
                RealculateTangents(geoSubsetTwo, normalsSubsetTwo, uvSubsetTwo, concatenatedIndicesTwo, out tangentsTwo);

                frontMesh.tangents = tangentsOne;
                backMesh.tangents = tangentsTwo;
            }

            if(sliceable.channelNormals)
            {
                frontMesh.normals = normalsSubsetOne;
                backMesh.normals = normalsSubsetTwo;
            }
            frontMesh.uv = uvSubsetOne;
            backMesh.uv = uvSubsetTwo;

            if(sliceable.channelUV2)
            {
                frontMesh.uv2 = uv2SubsetOne;
                backMesh.uv2 = uv2SubsetTwo;
            }

            frontMesh.subMeshCount = submeshCount;
            backMesh.subMeshCount = submeshCount;

            for(int i = 0 ; i < submeshCount; i++)
            {
                frontMesh.SetTriangles(indexSubsetOne[i], i);
                backMesh.SetTriangles(indexSubsetTwo[i], i);
            }

            TSCallbackOnDestroy frontCallback = frontObject.GetComponent<TSCallbackOnDestroy>();
            TSCallbackOnDestroy backCallback = backObject.GetComponent<TSCallbackOnDestroy>();

            if(frontCallback == null)
            {
                frontCallback = frontObject.AddComponent<TSCallbackOnDestroy>();
            }

            if(backCallback == null)
            {
                backCallback = backObject.AddComponent<TSCallbackOnDestroy>();
            }

            frontCallback.callWithMeshOnDestroy = releaseMesh;
            frontCallback.mesh = frontMesh;

            backCallback.callWithMeshOnDestroy = releaseMesh;
            backCallback.mesh = backMesh;

            meshCaches[frontMesh] = frontCache;
            meshCaches[backMesh] = backCache;

            results = new GameObject[2];
            results[0] = frontObject;
            results[1] = backObject;

            if(sliceable != null && sliceable.refreshColliders)
            {
                foreach(GameObject r in results)
                {
                    Collider collider = r.collider;

                    if(collider != null)
                    {
                        bool isTrigger = collider.isTrigger;

                        if(collider is BoxCollider)
                        {
                            GameObject.DestroyImmediate(collider);
                            collider = r.AddComponent<BoxCollider>();
                        }
                        else if(collider is SphereCollider)
                        {
                            GameObject.DestroyImmediate(collider);
                            collider = r.AddComponent<SphereCollider>();
                        }
                        else if(collider is MeshCollider)
                        {
                            MeshCollider mc = (MeshCollider) collider;

                            bool isFront = r == frontObject;

                            Mesh mesh = isFront ? frontMesh : backMesh;

                            mc.sharedMesh = mesh;
                        }

                        collider.isTrigger = isTrigger;
                    }
                }
            }

            if(callHandlers && sliceable != null)
                sliceable.handleSlice(results);

            if(destroyOriginal)
                GameObject.Destroy(go);
        }

        return results;
    }
Exemplo n.º 3
0
    public GameObject[] splitByPlane(GameObject go, Vector4 plane, bool destroyOriginal)
    {
        if(go.GetComponentInChildren<SkinnedMeshRenderer>() != null)
        {
            return splitByPlaneRD(go, plane, destroyOriginal);
        }

        Sliceable sliceable = ensureSliceable(go);

        if(!sliceable.currentlySliceable)
        {
            GameObject[] result = { go };

            return result;
        }

        InfillConfiguration[] ourInfills = sliceable.infillers.Length > 0 ? sliceable.infillers : infills;

        MeshCache c = null;
        do
        {
            MeshFilter filter = getMeshFilter(sliceable);

            Mesh m = filter.sharedMesh;

            if(m == null)
            {
                break;
            }

            if(meshCaches != null && meshCaches.ContainsKey(m))
            {
                c = meshCaches[m];

                //The mesh cache will be directly modified under the assumption that this will be discarded shortly
                //and thus picked up by the GC. It will grow in size; it will not shrink. Thus we do not want to
                //operate on the original, semi-persistent mesh caches that were preloaded on boot. Instead, we want
                //to make a clone.

                if(c.wasPreloaded)
                {
                    c = c.clone();
                }
            }
            else
                c = cacheFromGameObject(sliceable, true);
        }
        while(false);
        if(c == null)
        {
            Debug.LogWarning("Turbo Slicer cannot find mesh filter in object '" + go.name + "' in scene '" + Application.loadedLevelName + "'! Only objects featuring a mesh filter can be sliced.");

            GameObject[] result = { go };

            return result;
        }

        int submeshCount = c.indices.Length;

        //We're going to create two new tentative meshes which contain ALL original vertices in order,
        //plus room for new vertices. Not all of these copied vertices will be addressed, but copying them
        //over eliminates the need to remove doubles and do an On^2 search.

        TurboList<int>[] _frontIndices = new TurboList<int>[ submeshCount ];
        TurboList<int>[] _backIndices = new TurboList<int>[ submeshCount ];

        PlaneTriResult[] sidePlanes = new PlaneTriResult[c.vertices.Count];
        {
            Vector3[] vertices = c.vertices.array;

            for(int i = 0; i < sidePlanes.Length; i++)
            {
                sidePlanes[i] = getSidePlane(ref vertices[i], ref plane);
            }
        }

        for(int j = 0; j < submeshCount; j++)
        {
            int initialCapacityIndices = Mathf.RoundToInt((float) c.indices[j].Length * factorOfSafetyIndices);

            _frontIndices[j] = new TurboList<int>(initialCapacityIndices);
            _backIndices[j] = new TurboList<int>(initialCapacityIndices);

            int[] _indices = c.indices[j];

            TurboList<int> frontIndices = _frontIndices[j];
            TurboList<int> backIndices = _backIndices[j];
            TurboList<int> splitPending = new TurboList<int>(initialCapacityIndices);

            int[] indices = new int[3];

            for(int i = 0; i < _indices.Length; )
            {
                indices[0] = _indices[i++];
                indices[1] = _indices[i++];
                indices[2] = _indices[i++];

                // compute the side of the plane each vertex is on
                PlaneTriResult r1 = sidePlanes[indices[0]];
                PlaneTriResult r2 = sidePlanes[indices[1]];
                PlaneTriResult r3 = sidePlanes[indices[2]];

                if ( r1 == r2 && r1 == r3 ) // if all three vertices are on the same side of the plane.
                {
                    if ( r1 == PlaneTriResult.PTR_FRONT ) // if all three are in front of the plane, then copy to the 'front' output triangle.
                    {
                        frontIndices.AddArray(indices);
                    }
                    else
                    {
                        backIndices.AddArray(indices);
                    }
                }
                else
                {
                    splitPending.AddArray(indices);
                }
            }

            InfillConfiguration ifc = null;

            if(j < c.mats.Length)
            {
                Material mat = c.mats[j];

                foreach(InfillConfiguration _ifc in ourInfills)
                {
                    if(_ifc.material == mat)
                    {
                        ifc = _ifc;
                    }
                }
            }

            splitTriangles(plane, splitPending.ToArray(), c, ifc, frontIndices, backIndices);
        }

        GameObject[] results;

        bool onlyHaveOne = true;

        for(int i = 0; i < c.indices.Length; i++)
        {
            onlyHaveOne &= _frontIndices[i].Count == 0 || _backIndices[i].Count == 0;
        }

        if(onlyHaveOne)
        {
            //Do nothing
            results = new GameObject[1];
            results[0] = go;
        }
        else
        {
            MeshCache frontCache = new MeshCache();
            frontCache.vertices = c.vertices;
            if(sliceable.channelNormals)
                frontCache.normals = c.normals;
            frontCache.UVs = c.UVs;
            frontCache.mats = c.mats;

            MeshCache backCache = new MeshCache();
            backCache.vertices = c.vertices;
            if(sliceable.channelNormals)
                backCache.normals = c.normals;
            backCache.UVs = c.UVs;
            backCache.mats = c.mats;

            frontCache.indices = new int[submeshCount][];
            backCache.indices = new int[submeshCount][];
            for(int i = 0; i < submeshCount; i++)
            {
                frontCache.indices[i] = _frontIndices[i].ToArray();
                backCache.indices[i] = _backIndices[i].ToArray();
            }

            Vector3[] geoSubsetOne, geoSubsetTwo;
            Vector3[] normalsSubsetOne = null, normalsSubsetTwo = null;
            Vector2[] uvSubsetOne, uvSubsetTwo;
            int[][] indexSubsetOne, indexSubsetTwo;

            indexSubsetOne = new int[submeshCount][];
            indexSubsetTwo = new int[submeshCount][];

            //Perfect subset will inflate the array list size if needed to the exact figure. So if we estimate 0,
            //and there is 1 submesh, than we will have 1 allocation, and this is optimal. Estimation can only help
            //if we have THREE or more submeshes, which is a silly scenario for anyone concerned about performance.
            int estimateOne = 0, estimateTwo = 0;

            TurboList<Vector3>
                _geoSubsetOne = null, _geoSubsetTwo = null,
                _normalSubsetOne = null, _normalSubsetTwo = null;

            TurboList<Vector2>
                _uvSubsetOne = null, _uvSubsetTwo = null;

            _geoSubsetOne = new TurboList<Vector3>(estimateOne);
            _geoSubsetTwo = new TurboList<Vector3>(estimateTwo);

            if(sliceable.channelNormals)
            {
                _normalSubsetOne = new TurboList<Vector3>(estimateOne);
                _normalSubsetTwo = new TurboList<Vector3>(estimateTwo);
            }

            _uvSubsetOne = new TurboList<Vector2>(estimateOne);
            _uvSubsetTwo = new TurboList<Vector2>(estimateTwo);

            int transferTableMaximumKey = c.vertices.Count;

            int[] transferTableOne = new int[transferTableMaximumKey];
            int[] transferTableTwo = new int[transferTableMaximumKey];

            for(int i = 0; i < transferTableOne.Length; i++) transferTableOne[i] = -1;
            for(int i = 0; i < transferTableTwo.Length; i++) transferTableTwo[i] = -1;

            for(int i = 0; i < submeshCount; i++)
                perfectSubset(_frontIndices[i], c.vertices, c.normals, c.UVs, out indexSubsetOne[i], _geoSubsetOne, _normalSubsetOne, _uvSubsetOne, ref transferTableOne );

            for(int i = 0; i < submeshCount; i++)
                perfectSubset(_backIndices[i], c.vertices, c.normals, c.UVs, out indexSubsetTwo[i], _geoSubsetTwo, _normalSubsetTwo, _uvSubsetTwo, ref transferTableTwo );

            geoSubsetOne = _geoSubsetOne.ToArray();
            geoSubsetTwo = _geoSubsetTwo.ToArray();
            if(sliceable.channelNormals)
            {
                normalsSubsetOne = _normalSubsetOne.ToArray();
                normalsSubsetTwo = _normalSubsetTwo.ToArray();
            }
            uvSubsetOne = _uvSubsetOne.ToArray();
            uvSubsetTwo = _uvSubsetTwo.ToArray();

            //Note that we do not explicitly call recalculate bounds because (as per the manual) this is implicit in an
            //assignment to vertices whenever the vertex count changes from zero to non-zero.

            Mesh frontMesh = new Mesh();
            Mesh backMesh = new Mesh();

            GameObject frontObject, backObject;

            createResultObjects(go, sliceable, false, plane, out frontObject, out backObject);

            getMeshFilter(frontObject.GetComponent<Sliceable>()).mesh = frontMesh;
            getMeshFilter(backObject.GetComponent<Sliceable>()).mesh = backMesh;

            frontMesh.vertices = geoSubsetOne;
            backMesh.vertices = geoSubsetTwo;

            if(sliceable.channelNormals)
            {
                frontMesh.normals = normalsSubsetOne;
                backMesh.normals = normalsSubsetTwo;
            }
            frontMesh.uv = uvSubsetOne;
            backMesh.uv = uvSubsetTwo;

            frontMesh.subMeshCount = submeshCount;
            backMesh.subMeshCount = submeshCount;

            for(int i = 0 ; i < submeshCount; i++)
            {
                frontMesh.SetTriangles(indexSubsetOne[i], i);
                backMesh.SetTriangles(indexSubsetTwo[i], i);
            }

            if(meshCaches != null)
            {
                if(go.GetComponent<DeletionCallback>() == null)
                {
                    frontObject.AddComponent<DeletionCallback>();
                    backObject.AddComponent<DeletionCallback>();
                }

                DeletionCallback frontCallback = frontObject.GetComponent<DeletionCallback>();
                DeletionCallback backCallback = backObject.GetComponent<DeletionCallback>();

                frontCallback.deletionListener = new DeletionOccurred(this.releaseCacheByMesh);
                backCallback.deletionListener = new DeletionOccurred(this.releaseCacheByMesh);

                frontCallback.mesh = frontMesh;
                backCallback.mesh = backMesh;

                meshCaches[frontMesh] = frontCache;
                meshCaches[backMesh] = backCache;
            }
            else
            {
                DeletionCallback frontCallback = frontObject.GetComponent<DeletionCallback>();
                DeletionCallback backCallback = backObject.GetComponent<DeletionCallback>();

                if(frontCallback != null)
                    GameObject.DestroyImmediate(frontCallback);

                if(backCallback != null)
                    GameObject.DestroyImmediate(backCallback);
            }

            if(destroyOriginal)
                GameObject.Destroy(go);

            results = new GameObject[2];
            results[0] = frontObject;
            results[1] = backObject;

            if(sliceable != null && sliceable.refreshColliders)
            {
                foreach(GameObject r in results)
                {
                    Collider collider = r.GetComponent<Collider>();

                    if(collider != null)
                    {
                        if(collider is BoxCollider)
                        {
                            GameObject.DestroyImmediate(collider);
                            r.AddComponent<BoxCollider>();
                        }
                        else if(collider is SphereCollider)
                        {
                            GameObject.DestroyImmediate(collider);
                            r.AddComponent<SphereCollider>();
                        }
                        else if(collider is MeshCollider)
                        {
                            MeshCollider mc = (MeshCollider) collider;

                            bool isFront = r == frontObject;

                            Mesh mesh = isFront ? frontMesh : backMesh;

                            mc.sharedMesh = mesh;
                        }
                    }
                }
            }

            if(sliceable != null)
                sliceable.handleSlice(results);
        }

        return results;
    }
Exemplo n.º 4
0
    public GameObject[] splitByPlane(GameObject go, Vector4 plane, bool destroyOriginal)
    {
        if (go.GetComponentInChildren <SkinnedMeshRenderer>() != null)
        {
            return(splitByPlaneRD(go, plane, destroyOriginal));
        }

        Sliceable sliceable = ensureSliceable(go);

        if (!sliceable.currentlySliceable)
        {
            GameObject[] result = { go };

            return(result);
        }

        InfillConfiguration[] ourInfills = sliceable.infillers.Length > 0 ? sliceable.infillers : infills;

        MeshCache c = null;

        do
        {
            MeshFilter filter = getMeshFilter(sliceable);

            Mesh m = filter.sharedMesh;

            if (m == null)
            {
                break;
            }

            if (meshCaches != null && meshCaches.ContainsKey(m))
            {
                c = meshCaches[m];

                //The mesh cache will be directly modified under the assumption that this will be discarded shortly
                //and thus picked up by the GC. It will grow in size; it will not shrink. Thus we do not want to
                //operate on the original, semi-persistent mesh caches that were preloaded on boot. Instead, we want
                //to make a clone.

                if (c.wasPreloaded)
                {
                    c = c.clone();
                }
            }
            else
            {
                c = cacheFromGameObject(sliceable, true);
            }
        }while(false);
        if (c == null)
        {
            Debug.LogWarning("Turbo Slicer cannot find mesh filter in object '" + go.name + "' in scene '" + Application.loadedLevelName + "'! Only objects featuring a mesh filter can be sliced.");

            GameObject[] result = { go };

            return(result);
        }

        int submeshCount = c.indices.Length;

        //We're going to create two new tentative meshes which contain ALL original vertices in order,
        //plus room for new vertices. Not all of these copied vertices will be addressed, but copying them
        //over eliminates the need to remove doubles and do an On^2 search.

        TurboList <int>[] _frontIndices = new TurboList <int> [submeshCount];
        TurboList <int>[] _backIndices  = new TurboList <int> [submeshCount];

        PlaneTriResult[] sidePlanes = new PlaneTriResult[c.vertices.Count];
        {
            Vector3[] vertices = c.vertices.array;

            for (int i = 0; i < sidePlanes.Length; i++)
            {
                sidePlanes[i] = getSidePlane(ref vertices[i], ref plane);
            }
        }

        for (int j = 0; j < submeshCount; j++)
        {
            int initialCapacityIndices = Mathf.RoundToInt((float)c.indices[j].Length * factorOfSafetyIndices);

            _frontIndices[j] = new TurboList <int>(initialCapacityIndices);
            _backIndices[j]  = new TurboList <int>(initialCapacityIndices);

            int[] _indices = c.indices[j];

            TurboList <int> frontIndices = _frontIndices[j];
            TurboList <int> backIndices  = _backIndices[j];
            TurboList <int> splitPending = new TurboList <int>(initialCapacityIndices);

            int[] indices = new int[3];

            for (int i = 0; i < _indices.Length;)
            {
                indices[0] = _indices[i++];
                indices[1] = _indices[i++];
                indices[2] = _indices[i++];

                // compute the side of the plane each vertex is on
                PlaneTriResult r1 = sidePlanes[indices[0]];
                PlaneTriResult r2 = sidePlanes[indices[1]];
                PlaneTriResult r3 = sidePlanes[indices[2]];

                if (r1 == r2 && r1 == r3)                   // if all three vertices are on the same side of the plane.
                {
                    if (r1 == PlaneTriResult.PTR_FRONT)     // if all three are in front of the plane, then copy to the 'front' output triangle.
                    {
                        frontIndices.AddArray(indices);
                    }
                    else
                    {
                        backIndices.AddArray(indices);
                    }
                }
                else
                {
                    splitPending.AddArray(indices);
                }
            }

            InfillConfiguration ifc = null;

            if (j < c.mats.Length)
            {
                Material mat = c.mats[j];

                foreach (InfillConfiguration _ifc in ourInfills)
                {
                    if (_ifc.material == mat)
                    {
                        ifc = _ifc;
                    }
                }
            }

            splitTriangles(plane, splitPending.ToArray(), c, ifc, frontIndices, backIndices);
        }

        GameObject[] results;

        bool onlyHaveOne = true;

        for (int i = 0; i < c.indices.Length; i++)
        {
            onlyHaveOne &= _frontIndices[i].Count == 0 || _backIndices[i].Count == 0;
        }

        if (onlyHaveOne)
        {
            //Do nothing
            results    = new GameObject[1];
            results[0] = go;
        }
        else
        {
            MeshCache frontCache = new MeshCache();
            frontCache.vertices = c.vertices;
            if (sliceable.channelNormals)
            {
                frontCache.normals = c.normals;
            }
            frontCache.UVs  = c.UVs;
            frontCache.mats = c.mats;

            MeshCache backCache = new MeshCache();
            backCache.vertices = c.vertices;
            if (sliceable.channelNormals)
            {
                backCache.normals = c.normals;
            }
            backCache.UVs  = c.UVs;
            backCache.mats = c.mats;

            frontCache.indices = new int[submeshCount][];
            backCache.indices  = new int[submeshCount][];
            for (int i = 0; i < submeshCount; i++)
            {
                frontCache.indices[i] = _frontIndices[i].ToArray();
                backCache.indices[i]  = _backIndices[i].ToArray();
            }

            Vector3[] geoSubsetOne, geoSubsetTwo;
            Vector3[] normalsSubsetOne = null, normalsSubsetTwo = null;
            Vector2[] uvSubsetOne, uvSubsetTwo;
            int[][]   indexSubsetOne, indexSubsetTwo;

            indexSubsetOne = new int[submeshCount][];
            indexSubsetTwo = new int[submeshCount][];

            //Perfect subset will inflate the array list size if needed to the exact figure. So if we estimate 0,
            //and there is 1 submesh, than we will have 1 allocation, and this is optimal. Estimation can only help
            //if we have THREE or more submeshes, which is a silly scenario for anyone concerned about performance.
            int estimateOne = 0, estimateTwo = 0;

            TurboList <Vector3>
            _geoSubsetOne = null, _geoSubsetTwo = null,
                _normalSubsetOne = null, _normalSubsetTwo = null;

            TurboList <Vector2>
            _uvSubsetOne = null, _uvSubsetTwo = null;

            _geoSubsetOne = new TurboList <Vector3>(estimateOne);
            _geoSubsetTwo = new TurboList <Vector3>(estimateTwo);

            if (sliceable.channelNormals)
            {
                _normalSubsetOne = new TurboList <Vector3>(estimateOne);
                _normalSubsetTwo = new TurboList <Vector3>(estimateTwo);
            }

            _uvSubsetOne = new TurboList <Vector2>(estimateOne);
            _uvSubsetTwo = new TurboList <Vector2>(estimateTwo);

            int transferTableMaximumKey = c.vertices.Count;

            int[] transferTableOne = new int[transferTableMaximumKey];
            int[] transferTableTwo = new int[transferTableMaximumKey];

            for (int i = 0; i < transferTableOne.Length; i++)
            {
                transferTableOne[i] = -1;
            }
            for (int i = 0; i < transferTableTwo.Length; i++)
            {
                transferTableTwo[i] = -1;
            }

            for (int i = 0; i < submeshCount; i++)
            {
                perfectSubset(_frontIndices[i], c.vertices, c.normals, c.UVs, out indexSubsetOne[i], _geoSubsetOne, _normalSubsetOne, _uvSubsetOne, ref transferTableOne);
            }

            for (int i = 0; i < submeshCount; i++)
            {
                perfectSubset(_backIndices[i], c.vertices, c.normals, c.UVs, out indexSubsetTwo[i], _geoSubsetTwo, _normalSubsetTwo, _uvSubsetTwo, ref transferTableTwo);
            }

            geoSubsetOne = _geoSubsetOne.ToArray();
            geoSubsetTwo = _geoSubsetTwo.ToArray();
            if (sliceable.channelNormals)
            {
                normalsSubsetOne = _normalSubsetOne.ToArray();
                normalsSubsetTwo = _normalSubsetTwo.ToArray();
            }
            uvSubsetOne = _uvSubsetOne.ToArray();
            uvSubsetTwo = _uvSubsetTwo.ToArray();

            //Note that we do not explicitly call recalculate bounds because (as per the manual) this is implicit in an
            //assignment to vertices whenever the vertex count changes from zero to non-zero.

            Mesh frontMesh = new Mesh();
            Mesh backMesh  = new Mesh();

            GameObject frontObject, backObject;

            createResultObjects(go, sliceable, false, plane, out frontObject, out backObject);

            getMeshFilter(frontObject.GetComponent <Sliceable>()).mesh = frontMesh;
            getMeshFilter(backObject.GetComponent <Sliceable>()).mesh  = backMesh;

            frontMesh.vertices = geoSubsetOne;
            backMesh.vertices  = geoSubsetTwo;

            if (sliceable.channelNormals)
            {
                frontMesh.normals = normalsSubsetOne;
                backMesh.normals  = normalsSubsetTwo;
            }
            frontMesh.uv = uvSubsetOne;
            backMesh.uv  = uvSubsetTwo;

            frontMesh.subMeshCount = submeshCount;
            backMesh.subMeshCount  = submeshCount;

            for (int i = 0; i < submeshCount; i++)
            {
                frontMesh.SetTriangles(indexSubsetOne[i], i);
                backMesh.SetTriangles(indexSubsetTwo[i], i);
            }

            if (meshCaches != null)
            {
                if (go.GetComponent <DeletionCallback>() == null)
                {
                    frontObject.AddComponent <DeletionCallback>();
                    backObject.AddComponent <DeletionCallback>();
                }

                DeletionCallback frontCallback = frontObject.GetComponent <DeletionCallback>();
                DeletionCallback backCallback  = backObject.GetComponent <DeletionCallback>();

                frontCallback.deletionListener = new DeletionOccurred(this.releaseCacheByMesh);
                backCallback.deletionListener  = new DeletionOccurred(this.releaseCacheByMesh);

                frontCallback.mesh = frontMesh;
                backCallback.mesh  = backMesh;

                meshCaches[frontMesh] = frontCache;
                meshCaches[backMesh]  = backCache;
            }
            else
            {
                DeletionCallback frontCallback = frontObject.GetComponent <DeletionCallback>();
                DeletionCallback backCallback  = backObject.GetComponent <DeletionCallback>();

                if (frontCallback != null)
                {
                    GameObject.DestroyImmediate(frontCallback);
                }

                if (backCallback != null)
                {
                    GameObject.DestroyImmediate(backCallback);
                }
            }

            if (destroyOriginal)
            {
                GameObject.Destroy(go);
            }

            results    = new GameObject[2];
            results[0] = frontObject;
            results[1] = backObject;

            if (sliceable != null && sliceable.refreshColliders)
            {
                foreach (GameObject r in results)
                {
                    Collider collider = r.collider;

                    if (collider != null)
                    {
                        if (collider is BoxCollider)
                        {
                            GameObject.DestroyImmediate(collider);
                            r.AddComponent <BoxCollider>();
                        }
                        else if (collider is SphereCollider)
                        {
                            GameObject.DestroyImmediate(collider);
                            r.AddComponent <SphereCollider>();
                        }
                        else if (collider is MeshCollider)
                        {
                            MeshCollider mc = (MeshCollider)collider;

                            bool isFront = r == frontObject;

                            Mesh mesh = isFront ? frontMesh : backMesh;

                            mc.sharedMesh = mesh;
                        }
                    }
                }
            }

            if (sliceable != null)
            {
                sliceable.handleSlice(results);
            }
        }

        return(results);
    }