예제 #1
0
    // target = 切りたいオブジェクト
    // anchorPoint = 剣の座標
    // normalDirection = 剣の右方向ベクトル
    // capMaterial = 切った断面に被せるマテリアル
    // leftSideObject = 切った左半分のオブジェクト
    // rightSideObject = 切った右半分のオブジェクト
    public static void Cut(GameObject target, Vector3 anchorPoint, Vector3 normalDirection, Material capMaterial, out GameObject leftSideObjct, out GameObject rightSideObjct)
    {
        // 不正な呼び出しを防ぐ
        if (target == null)
        {
            leftSideObjct  = null;
            rightSideObjct = null;
            return;
        }

        // 切るプレートの定義(ブレードの左方向ベクトル,ブレードの座標)
        // 絶対座標・ベクトルから相対座標・ベクトルへと変換して引数を渡している
        blade = new Plane(target.transform.InverseTransformDirection(-normalDirection), target.transform.InverseTransformPoint(anchorPoint));

        // 切りたいオブジェクトのメッシュを取得
        targetMesh = target.GetComponent <MeshFilter>().mesh;

        //新しい2つのオブジェクト分のメッシュメーカーを初期化
        leftMeshMaker.Clear();
        rightMeshMaker.Clear();
        newVertices.Clear();

        int index_1, index_2, index_3;

        //Meshの頂点座標配列verticesを取得
        Vector3[] meshVertices = targetMesh.vertices;
        //Meshの法線ベクトル配列を取得
        Vector3[] meshNormals = targetMesh.normals;
        //MeshのUV(テクスチャを正方形に見たときの左端を0,0とみた座標)配列を取得
        Vector2[] meshUvs = targetMesh.uv;
        //tangents←接線ベクトルVector4
        Vector4[] meshTangents = targetMesh.tangents;

        //接線配列が存在するけどサイズが0のとき、接線配列を初期化
        if (meshTangents != null && meshTangents.Length == 0)
        {
            meshTangents = null;
        }

        // サブメッシュの数まで使う
        for (int c = 0; c < targetMesh.subMeshCount; c++)
        {
            // targetのメッシュのインデックスをindex配列に代入
            int[] index = targetMesh.GetTriangles(c);

            // インデックスを個々で見ていく
            for (int i = 0; i < index.Length; i += 3)
            {
                // ポリゴンの3頂点のインデックス
                index_1 = index[i];     //左下
                index_2 = index[i + 1]; //真ん中
                index_3 = index[i + 2]; //右上

                // メッシュのポリゴン一つ一つの情報を仮の三角形に
                // 3頂点の絶対座標
                tmpTriangle.vertices[0] = meshVertices[index_1];
                tmpTriangle.vertices[1] = meshVertices[index_2];
                tmpTriangle.vertices[2] = meshVertices[index_3];

                // 3頂点の法線ベクトル
                tmpTriangle.normals[0] = meshNormals[index_1];
                tmpTriangle.normals[1] = meshNormals[index_2];
                tmpTriangle.normals[2] = meshNormals[index_3];

                // 3頂点のUV
                tmpTriangle.uvs[0] = meshUvs[index_1];
                tmpTriangle.uvs[1] = meshUvs[index_2];
                tmpTriangle.uvs[2] = meshUvs[index_3];

                // tangentsは接線ベクトル
                if (meshTangents != null)
                {
                    // 接線ベクトルが存在する場合
                    tmpTriangle.tangents[0] = meshTangents[index_1];
                    tmpTriangle.tangents[1] = meshTangents[index_2];
                    tmpTriangle.tangents[2] = meshTangents[index_3];
                }
                else
                {
                    // もし接線ベクトルが存在しなければ、zeroベクトルを設定
                    tmpTriangle.tangents[0] = Vector4.zero;
                    tmpTriangle.tangents[1] = Vector4.zero;
                    tmpTriangle.tangents[2] = Vector4.zero;
                }

                /* ポリゴンの頂点たちについて
                 * ポリゴンの頂点には4状態ある。
                 * ①全ての頂点がブレードの左(ブレードの表)側
                 * ②全ての頂点がブレードの左側
                 * ③3つの頂点のうち、1つの頂点が右側
                 * ④3つの頂点のうち、2つの頂点が右側
                 */

                // メッシュの頂点が、ブレードのおもて(法線ベクトル側)にあるかチェック
                // 法線ベクトル側(左側)にあればtrue,出なければfalse
                isLeftSides[0] = blade.GetSide(meshVertices[index_1]);
                isLeftSides[1] = blade.GetSide(meshVertices[index_2]);
                isLeftSides[2] = blade.GetSide(meshVertices[index_3]);

                // ①・② 全ての頂点がどちらか片方に偏っている=状態が同じ
                if (isLeftSides[0] == isLeftSides[1] && isLeftSides[0] == isLeftSides[2])
                {
                    // ①の状態の時、左側のリストに追加する
                    if (isLeftSides[0]) // left side
                    // 左側三角形(ポリゴン)リストに今対象のポリゴンを追加
                    {
                        leftMeshMaker.AddTriangle(tmpTriangle, c);
                    }
                    else // ②の状態の時、
                         // 右側三角形(ポリゴン)リストに今対象のポリゴンを追加
                    {
                        rightMeshMaker.AddTriangle(tmpTriangle, c);
                    }
                }
                else // どれか一つが反対側にある場合
                {
                    // 三角形(ポリゴン)を切るスプリクトを実行
                    Cut_this_Face(ref tmpTriangle, c);
                }
            }
        }

        // 断面に被せるメッシュの準備
        // mats = ターゲットのマテリアル
        Material[] mats = target.GetComponent <MeshRenderer>().sharedMaterials;
        // メッシュのマテリアルが被せるマテリアルと同じならパス
        // 違うならマテリアルを追加
        if (mats[mats.Length - 1].name != capMaterial.name)
        {
            // matsより1つ大きな配列newMatsを作成
            Material[] newMats = new Material[mats.Length + 1];
            // matsの中身をnewMatsにコピー
            mats.CopyTo(newMats, 0);
            // newMatsの最後[mats.length]には断面のマテリアルを追加
            newMats[mats.Length] = capMaterial;
            // matsに新しく追加したnewMatsを代入する
            mats = newMats;
        }

        // 被せるマテリアルの添え字を取得
        capMatSub = mats.Length - 1;

        // 切断処理
        Cap_the_Cut();

        // leftSideに入っているポリゴン達をメッシュにまとめる
        Mesh leftSideMesh = leftMeshMaker.GetMesh();

        leftSideMesh.name = "Split Mesh Left";

        // 同様に右側のポリゴン達もメッシュにまとめる
        Mesh rightSideMesh = rightMeshMaker.GetMesh();

        rightSideMesh.name = "Split Mesh Right";

        //準備ができたので、実際に2つのオブジェクトを作成していく

        // 左側のオブジェクトを作成
        leftSideObjct = new GameObject("LeftSide", typeof(MeshFilter), typeof(MeshRenderer), typeof(Rigidbody));
        leftSideObjct.transform.position = target.transform.position;
        leftSideObjct.transform.rotation = target.transform.rotation;
        leftSideObjct.GetComponent <MeshFilter>().mesh = leftSideMesh;

        // 右側のオブジェクトを作成
        rightSideObjct = new GameObject("RightSide", typeof(MeshFilter), typeof(MeshRenderer), typeof(Rigidbody));
        rightSideObjct.transform.position = target.transform.position;
        rightSideObjct.transform.rotation = target.transform.rotation;
        rightSideObjct.GetComponent <MeshFilter>().mesh = rightSideMesh;

        // 切ったブジェクトにRigidbodyを付加する
        //if (!rightSideObj.GetComponent<Rigidbody>()) rightSideObj.AddComponent<Rigidbody>();
        if (!leftSideObjct.GetComponent <Rigidbody>())
        {
            leftSideObjct.AddComponent <Rigidbody>();
        }

        // 切ったオブジェクトを分けるために切れた方向に少しずらす
        //rightSideObjct.transform.position += -_blade.normal * 0.01f;
        //leftSideObjct.transform.position += _blade.normal * 0.01f;
        rightSideObjct.GetComponent <Rigidbody>().AddForce(-blade.normal * 50f);
        leftSideObjct.GetComponent <Rigidbody>().AddForce(blade.normal * 50f);


        // もしターゲットのオブジェクトに親がいれば、入れ子に
        if (target.transform.parent != null)
        {
            leftSideObjct.transform.parent  = target.transform.parent;
            rightSideObjct.transform.parent = target.transform.parent;
        }
        // スケールをコピー
        leftSideObjct.transform.localScale  = target.transform.localScale;
        rightSideObjct.transform.localScale = target.transform.localScale;

        // どちらとものマテリアルをmatsに
        leftSideObjct.GetComponent <MeshRenderer>().materials  = mats;
        rightSideObjct.GetComponent <MeshRenderer>().materials = mats;
    }