Example #1
0
        /// <summary>
        /// Cut the specified victim, blade_plane and capMaterial.
        /// (指定された「victim」をカットする。ブレード(平面)とマテリアルから切断を実行する)
        /// </summary>
        /// <param name="victim">Victim.</param>
        /// <param name="blade_plane">Blade plane.</param>
        /// <param name="capMaterial">Cap material.</param>
        public static GameObject[] Cut(GameObject victim, Vector3 anchorPoint, Vector3 normalDirection, Material capMaterial)
        {
            // set the blade relative to victim
            // victimから相対的な平面(ブレード)をセット
            // 具体的には、対象オブジェクトのローカル座標での平面の法線と位置から平面を生成する
            blade = new Plane(
                victim.transform.InverseTransformDirection(-normalDirection),
                victim.transform.InverseTransformPoint(anchorPoint)
                );

            // get the victims mesh
            // 対象のメッシュを取得
            victim_mesh = victim.GetComponent <MeshFilter>().mesh;

            // reset values
            // 新しい頂点郡
            new_vertices.Clear();

            // 平面より左の頂点郡(MeshCutSide)
            left_side.ClearAll();

            //平面より右の頂点郡(MeshCutSide)
            right_side.ClearAll();

            // ここでの「3」はトライアングル?
            bool[] sides = new bool[3];
            int[]  indices;
            int    p1, p2, p3;

            // go throught the submeshes
            // サブメッシュの数だけループ
            for (int sub = 0; sub < victim_mesh.subMeshCount; sub++)
            {
                // サブメッシュのインデックス数を取得
                indices = victim_mesh.GetIndices(sub);

                // List<List<int>>型のリスト。サブメッシュ一つ分のインデックスリスト
                left_side.subIndices.Add(new List <int>());  // 左
                right_side.subIndices.Add(new List <int>()); // 右

                // サブメッシュのインデックス数分ループ
                for (int i = 0; i < indices.Length; i += 3)
                {
                    // p1 - p3のインデックスを取得。つまりトライアングル
                    p1 = indices[i + 0];
                    p2 = indices[i + 1];
                    p3 = indices[i + 2];

                    // それぞれ評価中のメッシュの頂点が、冒頭で定義された平面の左右どちらにあるかを評価。
                    // `GetSide` メソッドによりboolを得る。
                    sides[0] = blade.GetSide(victim_mesh.vertices[p1]);
                    sides[1] = blade.GetSide(victim_mesh.vertices[p2]);
                    sides[2] = blade.GetSide(victim_mesh.vertices[p3]);

                    // whole triangle
                    // 頂点0と頂点1および頂点2がどちらも同じ側にある場合はカットしない
                    if (sides[0] == sides[1] && sides[0] == sides[2])
                    {
                        if (sides[0])
                        { // left side
                          // GetSideメソッドでポジティブ(true)の場合は左側にあり
                            left_side.AddTriangle(p1, p2, p3, sub);
                        }
                        else
                        {
                            right_side.AddTriangle(p1, p2, p3, sub);
                        }
                    }
                    else
                    { // cut the triangle
                      // そうではなく、どちらかの点が平面の反対側にある場合はカットを実行する
                        Cut_this_Face(sub, sides, p1, p2, p3);
                    }
                }
            }

            // 設定されているマテリアル配列を取得
            Material[] mats = victim.GetComponent <MeshRenderer>().sharedMaterials;

            // 取得したマテリアル配列の最後のマテリアルが、カット面のマテリアルでない場合
            if (mats[mats.Length - 1].name != capMaterial.name)
            { // add cap indices
                // カット面用のインデックス配列を追加?
                left_side.subIndices.Add(new List <int>());
                right_side.subIndices.Add(new List <int>());

                // カット面分増やしたマテリアル配列を準備
                Material[] newMats = new Material[mats.Length + 1];

                // 既存のものを新しい配列にコピー
                mats.CopyTo(newMats, 0);

                // 新しいマテリアル配列の最後に、カット面用マテリアルを追加
                newMats[mats.Length] = capMaterial;

                // 生成したマテリアルリストを再設定
                mats = newMats;
            }

            // cap the opennings
            // カット開始
            Capping();


            // Left Mesh
            // 左側のメッシュを生成
            // MeshCutSideクラスのメンバから各値をコピー
            Mesh left_HalfMesh = new Mesh();

            left_HalfMesh.name      = "Split Mesh Left";
            left_HalfMesh.vertices  = left_side.vertices.ToArray();
            left_HalfMesh.triangles = left_side.triangles.ToArray();
            left_HalfMesh.normals   = left_side.normals.ToArray();
            left_HalfMesh.uv        = left_side.uvs.ToArray();

            left_HalfMesh.subMeshCount = left_side.subIndices.Count;
            for (int i = 0; i < left_side.subIndices.Count; i++)
            {
                left_HalfMesh.SetIndices(left_side.subIndices[i].ToArray(), MeshTopology.Triangles, i);
            }


            // Right Mesh
            // 右側のメッシュも同様に生成
            Mesh right_HalfMesh = new Mesh();

            right_HalfMesh.name      = "Split Mesh Right";
            right_HalfMesh.vertices  = right_side.vertices.ToArray();
            right_HalfMesh.triangles = right_side.triangles.ToArray();
            right_HalfMesh.normals   = right_side.normals.ToArray();
            right_HalfMesh.uv        = right_side.uvs.ToArray();

            right_HalfMesh.subMeshCount = right_side.subIndices.Count;
            for (int i = 0; i < right_side.subIndices.Count; i++)
            {
                right_HalfMesh.SetIndices(right_side.subIndices[i].ToArray(), MeshTopology.Triangles, i);
            }


            // assign the game objects

            // 元のオブジェクトを左側のオブジェクトに
            victim.name = "left side";
            victim.GetComponent <MeshFilter>().mesh = left_HalfMesh;


            // 右側のオブジェクトは新規作成
            GameObject leftSideObj = victim;

            GameObject rightSideObj = new GameObject("right side", typeof(MeshFilter), typeof(MeshRenderer));

            rightSideObj.transform.position = victim.transform.position;
            rightSideObj.transform.rotation = victim.transform.rotation;
            rightSideObj.GetComponent <MeshFilter>().mesh = right_HalfMesh;

            // assign mats
            // 新規生成したマテリアルリストをそれぞれのオブジェクトに適用する
            leftSideObj.GetComponent <MeshRenderer>().materials  = mats;
            rightSideObj.GetComponent <MeshRenderer>().materials = mats;

            // 左右のGameObjectの配列を返す
            return(new GameObject[] { leftSideObj, rightSideObj });
        }
        /// <summary>
        /// Cut the specified victim, blade_plane and capMaterial.
        /// </summary>
        /// <param name="victim">Victim.</param>
        /// <param name="blade_plane">Blade plane.</param>
        /// <param name="capMaterial">Cap material.</param>
        public static GameObject[] Cut(GameObject victim, Vector3 anchorPoint, Vector3 normalDirection, Material capMaterial)
        {
            Vector3 victimScale = victim.transform.localScale;

            // set the blade relative to victim
            blade = new Plane(victim.transform.InverseTransformDirection(-normalDirection),
                              victim.transform.InverseTransformPoint(anchorPoint));

            // get the victims mesh
            victim_mesh = victim.GetComponent <MeshFilter>().mesh;

            // reset values
            new_vertices.Clear();
            left_side.ClearAll();
            right_side.ClearAll();


            bool[] sides = new bool[3];
            int[]  indices;
            int    p1, p2, p3;

            // go throught the submeshes
            for (int sub = 0; sub < victim_mesh.subMeshCount; sub++)
            {
                indices = victim_mesh.GetIndices(sub);

                left_side.subIndices.Add(new List <int>());
                right_side.subIndices.Add(new List <int>());

                for (int i = 0; i < indices.Length; i += 3)
                {
                    p1 = indices[i];
                    p2 = indices[i + 1];
                    p3 = indices[i + 2];

                    sides[0] = blade.GetSide(victim_mesh.vertices[p1]);
                    sides[1] = blade.GetSide(victim_mesh.vertices[p2]);
                    sides[2] = blade.GetSide(victim_mesh.vertices[p3]);


                    // whole triangle
                    if (sides[0] == sides[1] && sides[0] == sides[2])
                    {
                        if (sides[0])                         // left side
                        {
                            left_side.AddTriangle(p1, p2, p3, sub);
                        }
                        else
                        {
                            right_side.AddTriangle(p1, p2, p3, sub);
                        }
                    }
                    else                       // cut the triangle

                    {
                        Cut_this_Face(sub, sides, p1, p2, p3);
                    }
                }
            }


            Material[] mats = victim.GetComponent <MeshRenderer>().sharedMaterials;

            if (mats[mats.Length - 1].name != capMaterial.name)           // add cap indices

            {
                left_side.subIndices.Add(new List <int>());
                right_side.subIndices.Add(new List <int>());

                Material[] newMats = new Material[mats.Length + 1];
                mats.CopyTo(newMats, 0);
                newMats[mats.Length] = capMaterial;
                mats = newMats;
            }



            // cap the opennings
            Capping();


            // Left Mesh

            Mesh left_HalfMesh = new Mesh();

            left_HalfMesh.name      = "Split Mesh Left";
            left_HalfMesh.vertices  = left_side.vertices.ToArray();
            left_HalfMesh.triangles = left_side.triangles.ToArray();
            left_HalfMesh.normals   = left_side.normals.ToArray();
            left_HalfMesh.uv        = left_side.uvs.ToArray();

            left_HalfMesh.subMeshCount = left_side.subIndices.Count;
            for (int i = 0; i < left_side.subIndices.Count; i++)
            {
                left_HalfMesh.SetIndices(left_side.subIndices[i].ToArray(), MeshTopology.Triangles, i);
            }

            // Right Mesh

            Mesh right_HalfMesh = new Mesh();

            right_HalfMesh.name      = "Split Mesh Right";
            right_HalfMesh.vertices  = right_side.vertices.ToArray();
            right_HalfMesh.triangles = right_side.triangles.ToArray();
            right_HalfMesh.normals   = right_side.normals.ToArray();
            right_HalfMesh.uv        = right_side.uvs.ToArray();

            right_HalfMesh.subMeshCount = right_side.subIndices.Count;
            for (int i = 0; i < right_side.subIndices.Count; i++)
            {
                right_HalfMesh.SetIndices(right_side.subIndices[i].ToArray(), MeshTopology.Triangles, i);
            }

            // assign the game objects

            victim.name = "left side";
            victim.GetComponent <MeshFilter>().mesh = left_HalfMesh;

            GameObject leftSideObj = victim;

            GameObject rightSideObj = new GameObject("right side", typeof(MeshFilter), typeof(MeshRenderer));

            rightSideObj.transform.position = victim.transform.position;
            rightSideObj.transform.rotation = victim.transform.rotation;
            rightSideObj.GetComponent <MeshFilter>().mesh = right_HalfMesh;


            // assign mats
            leftSideObj.GetComponent <MeshRenderer>().materials  = mats;
            rightSideObj.GetComponent <MeshRenderer>().materials = mats;

            //Correct Scale
            leftSideObj.transform.localScale  = victimScale;
            rightSideObj.transform.localScale = victimScale;

            return(new GameObject[] { leftSideObj, rightSideObj });
        }
Example #3
0
        static void FillCap(Plane blade, MeshCutSide leftSide, MeshCutSide rightSide, List <Vector3> vertices)
        {
            // center of the cap
            Vector3 center      = Vector3.zero;
            int     numVertices = vertices.Count;

            for (int i = 0; i < numVertices; ++i)
            {
                center += vertices[i];
            }

            center = center / vertices.Count;

            // you need an axis based on the cap
            Vector3 upward = Vector3.zero;

            // 90 degree turn
            upward.x = blade.normal.y;
            upward.y = -blade.normal.x;
            upward.z = blade.normal.z;
            Vector3 left = Vector3.Cross(blade.normal, upward);

            Vector3 displacement = Vector3.zero;
            Vector3 newUV1       = Vector3.zero;
            Vector3 newUV2       = Vector3.zero;
            Vector2 half         = new Vector2(0.5f, 0.5f);

            for (int i = 0; i < numVertices; ++i)
            {
                displacement = vertices[i] - center;
                newUV1       = Vector3.zero;
                newUV1.x     = 0.5f + Vector3.Dot(displacement, left);
                newUV1.y     = 0.5f + Vector3.Dot(displacement, upward);
                newUV1.z     = 0.5f + Vector3.Dot(displacement, blade.normal);

                displacement = vertices[(i + 1) % vertices.Count] - center;
                newUV2       = Vector3.zero;
                newUV2.x     = 0.5f + Vector3.Dot(displacement, left);
                newUV2.y     = 0.5f + Vector3.Dot(displacement, upward);
                newUV2.z     = 0.5f + Vector3.Dot(displacement, blade.normal);

                leftSide.AddTriangle(
                    new Vector3[] {
                    vertices[i], vertices[(i + 1) % vertices.Count], center
                },
                    new Vector3[] {
                    -blade.normal, -blade.normal, -blade.normal
                },
                    new Vector2[] {
                    newUV1, newUV2, half
                },
                    -blade.normal,
                    leftSide.subIndices.Count - 1
                    );

                rightSide.AddTriangle(
                    new Vector3[] {
                    vertices[i], vertices[(i + 1) % vertices.Count], center
                },
                    new Vector3[] {
                    blade.normal, blade.normal, blade.normal
                },
                    new Vector2[] {
                    newUV1, newUV2, half
                },
                    blade.normal,
                    rightSide.subIndices.Count - 1
                    );
            }
        }
Example #4
0
        private static void CutFace(
            Plane blade,
            MeshCutSide leftSide,
            MeshCutSide rightSide,
            List <Vector3> newVertices,
            Vector3[] targetMeshVertices,
            Vector3[] targetMeshNormals,
            Vector2[] targetMeshUVs,
            int submesh,
            bool[] sides,
            int index1,
            int index2,
            int index3)
        {
            Vector3[] leftPoints   = new Vector3[2];
            Vector3[] leftNormals  = new Vector3[2];
            Vector2[] leftUvs      = new Vector2[2];
            Vector3[] rightPoints  = new Vector3[2];
            Vector3[] rightNormals = new Vector3[2];
            Vector2[] rightUvs     = new Vector2[2];

            bool didset_left  = false;
            bool didset_right = false;

            int p = index1;

            for (int side = 0; side < 3; side++)
            {
                switch (side)
                {
                case 0: p = index1; break;

                case 1: p = index2; break;

                case 2: p = index3; break;
                }

                if (sides[side])
                {
                    if (!didset_left)
                    {
                        didset_left = true;

                        leftPoints[0]  = targetMeshVertices[p];
                        leftPoints[1]  = leftPoints[0];
                        leftUvs[0]     = targetMeshUVs[p];
                        leftUvs[1]     = leftUvs[0];
                        leftNormals[0] = targetMeshNormals[p];
                        leftNormals[1] = leftNormals[0];
                    }
                    else
                    {
                        leftPoints[1]  = targetMeshVertices[p];
                        leftUvs[1]     = targetMeshUVs[p];
                        leftNormals[1] = targetMeshNormals[p];
                    }
                }
                else
                {
                    if (!didset_right)
                    {
                        didset_right = true;

                        rightPoints[0]  = targetMeshVertices[p];
                        rightPoints[1]  = rightPoints[0];
                        rightUvs[0]     = targetMeshUVs[p];
                        rightUvs[1]     = rightUvs[0];
                        rightNormals[0] = targetMeshNormals[p];
                        rightNormals[1] = rightNormals[0];
                    }
                    else
                    {
                        rightPoints[1]  = targetMeshVertices[p];
                        rightUvs[1]     = targetMeshUVs[p];
                        rightNormals[1] = targetMeshNormals[p];
                    }
                }
            }

            float normalizedDistance = 0.0f;
            float distance           = 0;

            blade.Raycast(new Ray(leftPoints[0], (rightPoints[0] - leftPoints[0]).normalized), out distance);

            normalizedDistance = distance / (rightPoints[0] - leftPoints[0]).magnitude;
            Vector3 newVertex1 = Vector3.Lerp(leftPoints[0], rightPoints[0], normalizedDistance);
            Vector2 newUv1     = Vector2.Lerp(leftUvs[0], rightUvs[0], normalizedDistance);
            Vector3 newNormal1 = Vector3.Lerp(leftNormals[0], rightNormals[0], normalizedDistance);

            newVertices.Add(newVertex1);

            blade.Raycast(new Ray(leftPoints[1], (rightPoints[1] - leftPoints[1]).normalized), out distance);

            normalizedDistance = distance / (rightPoints[1] - leftPoints[1]).magnitude;
            Vector3 newVertex2 = Vector3.Lerp(leftPoints[1], rightPoints[1], normalizedDistance);
            Vector2 newUv2     = Vector2.Lerp(leftUvs[1], rightUvs[1], normalizedDistance);
            Vector3 newNormal2 = Vector3.Lerp(leftNormals[1], rightNormals[1], normalizedDistance);

            newVertices.Add(newVertex2);

            leftSide.AddTriangle(new Vector3[] { leftPoints[0], newVertex1, newVertex2 },
                                 new Vector3[] { leftNormals[0], newNormal1, newNormal2 },
                                 new Vector2[] { leftUvs[0], newUv1, newUv2 }, newNormal1,
                                 submesh);

            leftSide.AddTriangle(new Vector3[] { leftPoints[0], leftPoints[1], newVertex2 },
                                 new Vector3[] { leftNormals[0], leftNormals[1], newNormal2 },
                                 new Vector2[] { leftUvs[0], leftUvs[1], newUv2 }, newNormal2,
                                 submesh);

            rightSide.AddTriangle(new Vector3[] { rightPoints[0], newVertex1, newVertex2 },
                                  new Vector3[] { rightNormals[0], newNormal1, newNormal2 },
                                  new Vector2[] { rightUvs[0], newUv1, newUv2 }, newNormal1,
                                  submesh);

            rightSide.AddTriangle(new Vector3[] { rightPoints[0], rightPoints[1], newVertex2 },
                                  new Vector3[] { rightNormals[0], rightNormals[1], newNormal2 },
                                  new Vector2[] { rightUvs[0], rightUvs[1], newUv2 }, newNormal2,
                                  submesh);
        }
Example #5
0
        /// <summary>
        /// Cuts the specified target into two pieces and caps the sides with the specified Material.
        /// </summary>
        /// <param name="target">The target that is cut - must have a MeshFilter component.</param>
        /// <param name="anchorPoint">Anchor point of the blade i.e. the point where the blade cuts the object.</param>
        /// <param name="normalDirection">Normal direction of the blade plane.</param>
        /// <param name="capMaterial">Cap material - placed as material on the cutting surface of the two sides.</param>
        /// <param name="copyRigidbody">Should the rigidbody be copied to both of the two new pieces.</param>
        /// <param name="copyRigidbody">Should both of the new pieces have colliders.</param>
        public static IObservable <GameObject[]> Cut(GameObject target, Vector3 anchorPoint, Vector3 normalDirection, Material capMaterial, bool copyRigidbody = true, bool copyCollider = true)
        {
            // Set the blade relative to victim
            Plane blade = new Plane(target.transform.InverseTransformDirection(-normalDirection),
                                    target.transform.InverseTransformPoint(anchorPoint));

            // Get the target mesh
            Mesh targetMesh = target.GetComponent <MeshFilter>().mesh;

            Vector3[] targetMeshVertices = targetMesh.vertices;
            Vector3[] targetMeshNormals  = targetMesh.normals;
            Vector2[] targetMeshUVs      = targetMesh.uv;

            int          subMeshCount   = targetMesh.subMeshCount;
            List <int[]> subMeshIndices = new List <int[]>();

            for (int i = 0; i < subMeshCount; ++i)
            {
                subMeshIndices.Add(targetMesh.GetIndices(i));
            }

            // Material parameters
            Material[] mats            = target.GetComponent <MeshRenderer>().sharedMaterials;
            string[]   matsNames       = mats.Select(m => m.name).ToArray();
            string     capMaterialName = capMaterial.name;

            return(Observable.Start(() =>
            {
                if (targetMesh == null)
                {
                    Debug.LogError("MeshCut Cut: Target did not have a MeshFilter component");
                }

                // Left and right side mesh cuts
                MeshCutSide leftSide = new MeshCutSide(targetMeshVertices, targetMeshNormals, targetMeshUVs);
                MeshCutSide rightSide = new MeshCutSide(targetMeshVertices, targetMeshNormals, targetMeshUVs);

                // New vertices for capping the cutting surface
                List <Vector3> newVertices = new List <Vector3>();

                bool[] sides = new bool[3];
                int p1, p2, p3;

                for (int sub = 0; sub < subMeshCount; ++sub)
                {
                    int[] indices = subMeshIndices[sub];
                    leftSide.subIndices.Add(new List <int>());
                    rightSide.subIndices.Add(new List <int>());

                    for (int i = 0; i < indices.Length; i += 3)
                    {
                        p1 = indices[i];
                        p2 = indices[i + 1];
                        p3 = indices[i + 2];

                        sides[0] = blade.GetSide(targetMeshVertices[p1]);
                        sides[1] = blade.GetSide(targetMeshVertices[p2]);
                        sides[2] = blade.GetSide(targetMeshVertices[p3]);

                        // whole triangle
                        if (sides[0] == sides[1] && sides[0] == sides[2])
                        {
                            if (sides[0])
                            {
                                // left side
                                leftSide.AddTriangle(p1, p2, p3, sub);
                            }
                            else
                            {
                                rightSide.AddTriangle(p1, p2, p3, sub);
                            }
                        }
                        else
                        {
                            // Cut the triangle
                            CutFace(
                                blade,
                                leftSide,
                                rightSide,
                                newVertices,
                                targetMeshVertices,
                                targetMeshNormals,
                                targetMeshUVs,
                                sub,
                                sides,
                                p1,
                                p2,
                                p3
                                );
                        }
                    }
                }

                if (matsNames[mats.Length - 1] != capMaterialName)
                {
                    // Add cap indices
                    leftSide.subIndices.Add(new List <int>());
                    rightSide.subIndices.Add(new List <int>());

                    Material[] newMats = new Material[mats.Length + 1];
                    mats.CopyTo(newMats, 0);
                    newMats[mats.Length] = capMaterial;
                    mats = newMats;
                }

                // Cap the openings
                Capping(blade, leftSide, rightSide, newVertices);

                return new MeshCutSide[] { leftSide, rightSide };
            },
                                    Scheduler.ThreadPool)
                   .ObserveOnMainThread()
                   .Select(results => {
                MeshCutSide leftSide = results[0];
                MeshCutSide rightSide = results[1];

                // Left Mesh
                Mesh leftHalfMesh = new Mesh();
                leftHalfMesh.name = "Split Mesh Left";
                leftHalfMesh.vertices = leftSide.vertices.ToArray();
                leftHalfMesh.triangles = leftSide.triangles.ToArray();
                leftHalfMesh.normals = leftSide.normals.ToArray();
                leftHalfMesh.uv = leftSide.uvs.ToArray();

                leftHalfMesh.subMeshCount = leftSide.subIndices.Count;
                int leftHalfMeshSubMeshCount = leftHalfMesh.subMeshCount;

                for (int i = 0; i < leftHalfMeshSubMeshCount; ++i)
                {
                    leftHalfMesh.SetIndices(leftSide.subIndices[i].ToArray(), MeshTopology.Triangles, i);
                }

                // Right Mesh
                Mesh rightHalfMesh = new Mesh();
                rightHalfMesh.name = "Split Mesh Right";
                rightHalfMesh.vertices = rightSide.vertices.ToArray();
                rightHalfMesh.triangles = rightSide.triangles.ToArray();
                rightHalfMesh.normals = rightSide.normals.ToArray();
                rightHalfMesh.uv = rightSide.uvs.ToArray();

                rightHalfMesh.subMeshCount = rightSide.subIndices.Count;
                int rightHalfSubMeshCount = rightHalfMesh.subMeshCount;

                for (int i = 0; i < rightHalfSubMeshCount; ++i)
                {
                    rightHalfMesh.SetIndices(rightSide.subIndices[i].ToArray(), MeshTopology.Triangles, i);
                }

                // Assign the game objects
                target.GetComponent <MeshFilter>().mesh = leftHalfMesh;
                GameObject leftSideObj = target;

                GameObject rightSideObj = new GameObject(target.name, typeof(MeshFilter), typeof(MeshRenderer));
                rightSideObj.transform.position = target.transform.position;
                rightSideObj.transform.rotation = target.transform.rotation;
                rightSideObj.transform.localScale = target.transform.localScale;
                rightSideObj.GetComponent <MeshFilter>().mesh = rightHalfMesh;

                // Maintain colliders and rigidbodies on both pieces i.e. populate the right piece
                Rigidbody leftSideRigidbody = leftSideObj.GetComponent <Rigidbody>();
                MeshCollider leftSideCollider = leftSideObj.GetComponent <MeshCollider>();

                if (copyRigidbody && leftSideRigidbody != null)
                {
                    Rigidbody rigidbody = rightSideObj.AddComponent <Rigidbody>();
                    rigidbody.useGravity = leftSideRigidbody.useGravity;
                    rigidbody.interpolation = leftSideRigidbody.interpolation;
                    rigidbody.collisionDetectionMode = leftSideRigidbody.collisionDetectionMode;
                }

                if (copyCollider && leftSideCollider != null)
                {
                    MeshCollider meshCollider = rightSideObj.AddComponent <MeshCollider>();
                    meshCollider.convex = true;
                }

                // Assign mats
                leftSideObj.GetComponent <MeshRenderer>().materials = mats;
                rightSideObj.GetComponent <MeshRenderer>().materials = mats;

                return new GameObject[] { leftSideObj, rightSideObj };
            }));
        }
Example #6
0
        /// <summary>
        /// Cut the specified victim, blade_plane and capMaterial.
        /// </summary>
        /// <param name="victim">Victim.</param>
        /// <param name="blade_plane">Blade plane.</param>
        /// <param name="capMaterial">Cap material.</param>
        public static Mesh[] Cut(GameObject victim, Vector3 anchorPoint, Vector3 normalDirection, float distanceLimit = Mathf.Infinity, bool colliderMode = false)
        {
            if (colliderMode && victim.GetComponent <MeshCollider>() == null)
            {
                return(null);
            }

            timer = Time.realtimeSinceStartup;
            Vector3 invAnchorPoint = victim.transform.InverseTransformPoint(anchorPoint);

            // set the blade relative to victim
            blade = new Plane(victim.transform.InverseTransformDirection(-normalDirection), invAnchorPoint);

            // get the victims mesh
            victim_mesh  = colliderMode ? victim.GetComponent <MeshCollider>().sharedMesh : victim.GetComponent <MeshFilter>().sharedMesh;
            victim_verts = victim_mesh.vertices;
            victim_norms = victim_mesh.normals;

            // reset values
            new_vertices.Clear();
            left_side.ClearAll();
            right_side.ClearAll();

            bool[] sides = new bool[3];
            int[]  indices;
            int    p1, p2, p3;

            int minCut = int.MaxValue, maxCut = int.MinValue;

            // go throught the submeshes
            indices = victim_mesh.GetIndices(0);

            left_side.indices  = new List <int>();
            right_side.indices = new List <int>();

            int cutVerts = 0;

            for (int i = 0; i < indices.Length; i += 3)
            {
                if (RequiresCut(ref sides, indices[i], indices[i + 1], indices[i + 2]))
                {
                    cutVerts += 3;

                    float distance = Vector3.Distance(victim_verts[indices[i]], invAnchorPoint);
                    if (distance < distanceLimit)
                    {
                        minCut = MinInt(MinInt(MinInt(minCut, indices[i]), indices[i + 1]), indices[i + 2]);
                        maxCut = MaxInt(MaxInt(MaxInt(minCut, indices[i]), indices[i + 1]), indices[i + 2]);
                    }
                    else if (distance < distanceLimit * 1.1f)
                    {
                        return(null);
                    }
                }
            }

            left_side.AddBlanks(cutVerts);

            bool checkDir = blade.GetSide(victim.transform.InverseTransformVector(victim.transform.up));

            if (checkDir)
            {
                for (int i = 0; i < indices.Length; i += 3)
                {
                    p1 = indices[i];
                    p2 = indices[i + 1];
                    p3 = indices[i + 2];

                    if (RequiresCut(ref sides, p1, p2, p3))
                    {
                        if (p1 > maxCut)
                        {
                            left_side.AddTriangle(p1, p2, p3);
                        }
                        else if (p1 < minCut)
                        {
                            right_side.AddTriangle(p1, p2, p3);
                        }
                        else
                        {
                            Cut_this_Face(sides, p1, p2, p3);
                        }
                    }
                    else
                    {
                        if (sides[0])
                        {
                            if (p1 <= minCut)
                            {
                                right_side.AddTriangle(p1, p2, p3);
                            }
                            else
                            {
                                left_side.AddTriangle(p1, p2, p3);
                            }
                        }
                        else
                        {
                            if (p1 >= maxCut)
                            {
                                left_side.AddTriangle(p1, p2, p3);
                            }
                            else
                            {
                                right_side.AddTriangle(p1, p2, p3);
                            }
                        }
                    }
                }
            }
            else
            {
                for (int i = 0; i < indices.Length; i += 3)
                {
                    p1 = indices[i];
                    p2 = indices[i + 1];
                    p3 = indices[i + 2];

                    if (RequiresCut(ref sides, p1, p2, p3))
                    {
                        if (p1 < minCut)
                        {
                            left_side.AddTriangle(p1, p2, p3);
                        }
                        else if (p1 > maxCut)
                        {
                            right_side.AddTriangle(p1, p2, p3);
                        }
                        else
                        {
                            Cut_this_Face(sides, p1, p2, p3);
                        }
                    }
                    else
                    {
                        if (sides[0])
                        {
                            if (p1 >= maxCut)
                            {
                                right_side.AddTriangle(p1, p2, p3);
                            }
                            else
                            {
                                left_side.AddTriangle(p1, p2, p3);
                            }
                        }
                        else
                        {
                            if (p1 <= minCut)
                            {
                                left_side.AddTriangle(p1, p2, p3);
                            }
                            else
                            {
                                right_side.AddTriangle(p1, p2, p3);
                            }
                        }
                    }
                }
            }

            // cap the opennings
            Capping();

            // Left Mesh
            Mesh left_HalfMesh = new Mesh();

            left_HalfMesh.name      = "Split Mesh Left";
            left_HalfMesh.vertices  = left_side.vertices.ToArray();
            left_HalfMesh.triangles = left_side.triangles.ToArray();
            left_HalfMesh.normals   = left_side.normals.ToArray();

            left_HalfMesh.SetIndices(left_side.indices.ToArray(), MeshTopology.Triangles, 0);

            // Right Mesh
            Mesh right_HalfMesh = new Mesh();

            right_HalfMesh.name      = "Split Mesh Right";
            right_HalfMesh.vertices  = right_side.vertices.ToArray();
            right_HalfMesh.triangles = right_side.triangles.ToArray();
            right_HalfMesh.normals   = right_side.normals.ToArray();

            right_HalfMesh.SetIndices(right_side.indices.ToArray(), MeshTopology.Triangles, 0);

            return(new Mesh[] { left_HalfMesh, right_HalfMesh });
        }
Example #7
0
    /// <summary>
    /// Cut the specified victim, blade_plane and capMaterial.
    /// (指定された「victim」をカットする。ブレード(平面)とマテリアルから切断を実行する)
    /// </summary>
    /// <param name="victim">Victim.</param>
    /// <param name="blade_plane">Blade plane.</param>
    /// <param name="capMaterial">Cap material.</param>
    public static GameObject[] Cut(GameObject victim, Plane plane, Mesh mesh, Material capMaterial)
    {
        //相対的な平面をセット
        blade = plane;

        //対象のメッシュを取得
        victim_mesh = mesh;

        // reset values
        // 新しい頂点郡
        new_vertices.Clear();

        // 平面より左の頂点郡(MeshCutSide)
        left_side.ClearAll();

        //平面より右の頂点郡(MeshCutSide)
        right_side.ClearAll();

        // ここでの「3」はトライアングル?
        bool[] sides = new bool[3];
        int[]  indices;
        int    p1, p2, p3;

        // go throught the submeshes
        // サブメッシュの数だけループ
        for (int sub = 0; sub < victim_mesh.subMeshCount; sub++)
        {
            // サブメッシュのインデックス数を取得
            indices = victim_mesh.GetIndices(sub);

            // List<List<int>>型のリスト。サブメッシュ一つ分のインデックスリスト
            left_side.subIndices.Add(new List <int>());  // 左
            right_side.subIndices.Add(new List <int>()); // 右

            // サブメッシュのインデックス数分ループ
            for (int i = 0; i < indices.Length; i += 3)
            {
                // p1 - p3のインデックスを取得。つまりトライアングル
                p1 = indices[i + 0];
                p2 = indices[i + 1];
                p3 = indices[i + 2];

                // それぞれ評価中のメッシュの頂点が、冒頭で定義された平面の左右どちらにあるかを評価。
                // `GetSide` メソッドによりboolを得る。
                sides[0] = blade.GetSide(victim_mesh.vertices[p1]);
                sides[1] = blade.GetSide(victim_mesh.vertices[p2]);
                sides[2] = blade.GetSide(victim_mesh.vertices[p3]);

                // whole triangle
                // 頂点0と頂点1および頂点2がどちらも同じ側にある場合はカットしない
                if (sides[0] == sides[1] && sides[0] == sides[2])
                {
                    if (sides[0])
                    {
                        left_side.AddTriangle(p1, p2, p3, sub);
                    }
                    else
                    {
                        right_side.AddTriangle(p1, p2, p3, sub);
                    }
                }
                else
                { // cut the triangle
                  // そうではなく、どちらかの点が平面の反対側にある場合はカットを実行する
                    Cut_this_Face(sub, sides, p1, p2, p3);
                }
            }
        }

        // 設定されているマテリアル配列を取得
        Material[] mats = victim.GetComponent <MeshRenderer>().sharedMaterials;

        // 取得したマテリアル配列の最後のマテリアルが、カット面のマテリアルでない場合
        if (mats[mats.Length - 1].name != capMaterial.name)
        { // add cap indices
          // カット面用のインデックス配列を追加?
            left_side.subIndices.Add(new List <int>());
            right_side.subIndices.Add(new List <int>());

            // カット面分増やしたマテリアル配列を準備
            Material[] newMats = new Material[mats.Length + 1];

            // 既存のものを新しい配列にコピー
            mats.CopyTo(newMats, 0);

            // 新しいマテリアル配列の最後に、カット面用マテリアルを追加
            newMats[mats.Length] = capMaterial;

            // 生成したマテリアルリストを再設定
            mats = newMats;
        }

        // cap the opennings
        // カット開始
        Capping();

        Debug.Log("左メッシュ:頂点" + left_side.vertices.Count);

        // Left Mesh
        // 左側のメッシュを生成
        // MeshCutSideクラスのメンバから各値をコピー
        Mesh left_HalfMesh = new Mesh();

        left_HalfMesh.name      = "Split Mesh Left";
        left_HalfMesh.vertices  = left_side.vertices.ToArray();
        left_HalfMesh.triangles = left_side.triangles.ToArray();
        left_HalfMesh.normals   = left_side.normals.ToArray();
        left_HalfMesh.uv        = left_side.uvs.ToArray();

        left_HalfMesh.subMeshCount = left_side.subIndices.Count;
        for (int i = 0; i < left_side.subIndices.Count; i++)
        {
            left_HalfMesh.SetIndices(left_side.subIndices[i].ToArray(), MeshTopology.Triangles, i);
        }

        Debug.Log("右メッシュ:頂点" + right_side.vertices.Count);

        // Right Mesh
        // 右側のメッシュも同様に生成
        Mesh right_HalfMesh = new Mesh();

        right_HalfMesh.name      = "Split Mesh Right";
        right_HalfMesh.vertices  = right_side.vertices.ToArray();
        right_HalfMesh.triangles = right_side.triangles.ToArray();
        right_HalfMesh.normals   = right_side.normals.ToArray();
        right_HalfMesh.uv        = right_side.uvs.ToArray();

        right_HalfMesh.subMeshCount = right_side.subIndices.Count;

        for (int i = 0; i < right_side.subIndices.Count; i++)
        {
            right_HalfMesh.SetIndices(right_side.subIndices[i].ToArray(), MeshTopology.Triangles, i);
        }

        GameObject leftSideObj  = null;
        GameObject rightSideObj = null;

        if (left_HalfMesh.triangles.Length != 0 && right_HalfMesh.triangles.Length != 0)
        {
            //左側のオブジェクトを新規作成
            leftSideObj = new GameObject("left side", typeof(MeshFilter), typeof(MeshRenderer), typeof(Rigidbody), typeof(MeshCollider));
            leftSideObj.transform.position               = victim.transform.position;
            leftSideObj.transform.rotation               = victim.transform.rotation;
            leftSideObj.transform.localScale             = victim.transform.localScale;
            leftSideObj.GetComponent <MeshFilter>().mesh = left_HalfMesh;

            leftSideObj.GetComponent <Rigidbody>().useGravity = true;

            if (left_HalfMesh.triangles.Length == 0)
            {
                Debug.Log("no");
            }

            leftSideObj.GetComponent <MeshCollider>().sharedMesh = left_HalfMesh;
            leftSideObj.GetComponent <MeshCollider>().convex     = true;

            leftSideObj.AddComponent <CutControl>().Count = victim.GetComponent <CutControl>().Count;
            leftSideObj.tag = "CutObject";


            // 右側のオブジェクトは新規作成
            rightSideObj = new GameObject("right side", typeof(MeshFilter), typeof(MeshRenderer), typeof(Rigidbody), typeof(MeshCollider));
            rightSideObj.transform.position               = victim.transform.position;
            rightSideObj.transform.rotation               = victim.transform.rotation;
            rightSideObj.transform.localScale             = victim.transform.localScale;
            rightSideObj.GetComponent <MeshFilter>().mesh = right_HalfMesh;

            rightSideObj.GetComponent <Rigidbody>().useGravity = true;

            if (right_HalfMesh.triangles.Length == 0)
            {
                Debug.Log("no");
            }

            rightSideObj.GetComponent <MeshCollider>().sharedMesh = right_HalfMesh;
            rightSideObj.GetComponent <MeshCollider>().convex     = true;

            rightSideObj.AddComponent <CutControl>().Count = victim.GetComponent <CutControl>().Count;
            rightSideObj.tag = "CutObject";

            if (rightSideObj.GetComponent <CutControl>().Count == 0)
            {
                Destroy(rightSideObj);
                Destroy(leftSideObj);
            }

            // 新規生成したマテリアルリストをそれぞれのオブジェクトに適用する
            leftSideObj.GetComponent <MeshRenderer>().materials  = mats;
            rightSideObj.GetComponent <MeshRenderer>().materials = mats;

            //元のオブジェクトは削除
            Destroy(victim);
        }

        // 左右のGameObjectの配列を返す
        return(new GameObject[] { leftSideObj, rightSideObj });
    }