// 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; }