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