/// <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 }); }
/// <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 }); }
/// <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. /// (指定された「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 }); }