using System.Collections; using System.Collections.Generic; using UnityEngine; public class MeshDestroyMachine : Singleton{ private bool edgeSet = false; private Vector3 edgeVertex = Vector3.zero; private Vector2 edgeUV = Vector2.zero; private Plane edgePlane = new Plane(); /// /// 爆炸的切割 /// public ListDestroyMesh(MeshDestroyAble destroyAble) { Mesh originalMesh = destroyAble.OrigionMesh; if (originalMesh == null) { return null; } originalMesh.RecalculateBounds(); List parts = new List (); List subParts = new List (); var mainPart = new MeshPart() { UV = originalMesh.uv, Vertices = originalMesh.vertices, Normals = originalMesh.normals, Triangles = new int[originalMesh.subMeshCount][], Bounds = originalMesh.bounds }; for (int i = 0; i < originalMesh.subMeshCount; i++) mainPart.Triangles[i] = originalMesh.GetTriangles(i); parts.Add(mainPart); for (int c = 0; c < destroyAble.cutCascades; c++) { for (int i = 0; i < parts.Count; i++) { Bounds bounds = parts[i].Bounds; bounds.Expand(0.5f); Plane plane = new Plane(UnityEngine.Random.onUnitSphere, new Vector3(UnityEngine.Random.Range(bounds.min.x, bounds.max.x), UnityEngine.Random.Range(bounds.min.y, bounds.max.y), UnityEngine.Random.Range(bounds.min.z, bounds.max.z))); subParts.Add(GenerateMesh(parts[i], plane, true)); subParts.Add(GenerateMesh(parts[i], plane, false)); } parts = new List (subParts); subParts.Clear(); } for (var i = 0; i < parts.Count; i++) { parts[i].MakeGameobject(destroyAble); parts[i].rb.AddForceAtPosition(parts[i].Bounds.center * destroyAble.explodeForce, transform.position); } Destroy(destroyAble.gameObject); return parts; } /// /// 刀剑的切割 /// public ListSliceMesh(Plane plane, MeshDestroyAble destroyAble) { Mesh originalMesh = destroyAble.OrigionMesh; if (originalMesh == null) { return null; } originalMesh.RecalculateBounds(); var mainPart = new MeshPart() { UV = originalMesh.uv, Vertices = originalMesh.vertices, Normals = originalMesh.normals, Triangles = new int[originalMesh.subMeshCount][], Bounds = originalMesh.bounds }; for (int i = 0; i < originalMesh.subMeshCount; i++) mainPart.Triangles[i] = originalMesh.GetTriangles(i); List parts = new List (); parts.Add(GenerateMesh(mainPart, plane, true)); parts.Add(GenerateMesh(mainPart, plane, false)); for (var i = 0; i < parts.Count; i++) { parts[i].MakeGameobject(destroyAble); } Destroy(destroyAble.gameObject); return parts; } /// /// 用平面切网格 /// private MeshPart GenerateMesh(MeshPart original, Plane plane, bool left) { var partMesh = new MeshPart() { }; var ray1 = new Ray(); var ray2 = new Ray(); for (var i = 0; i < original.Triangles.Length; i++) { var triangles = original.Triangles[i]; edgeSet = false; for (var j = 0; j < triangles.Length; j = j + 3) { //判断是否被切割 var sideA = plane.GetSide(original.Vertices[triangles[j]]) == left; var sideB = plane.GetSide(original.Vertices[triangles[j + 1]]) == left; var sideC = plane.GetSide(original.Vertices[triangles[j + 2]]) == left; var sideCount = (sideA ? 1 : 0) + (sideB ? 1 : 0) + (sideC ? 1 : 0); if (sideCount == 0) { continue; } if (sideCount == 3) { partMesh.AddTriangle(i, original.Vertices[triangles[j]], original.Vertices[triangles[j + 1]], original.Vertices[triangles[j + 2]], original.Normals[triangles[j]], original.Normals[triangles[j + 1]], original.Normals[triangles[j + 2]], original.UV[triangles[j]], original.UV[triangles[j + 1]], original.UV[triangles[j + 2]]); continue; } //对于剖面 //判断三角形中单独的点的是哪一个 var singleIndex = sideB == sideC ? 0 : sideA == sideC ? 1 : 2; //求切割点的位置 ray1.origin = original.Vertices[triangles[j + singleIndex]]; var dir1 = original.Vertices[triangles[j + ((singleIndex + 1) % 3)]] - original.Vertices[triangles[j + singleIndex]]; ray1.direction = dir1; plane.Raycast(ray1, out var enter1); var lerp1 = enter1 / dir1.magnitude; //求切割点的位置 ray2.origin = original.Vertices[triangles[j + singleIndex]]; var dir2 = original.Vertices[triangles[j + ((singleIndex + 2) % 3)]] - original.Vertices[triangles[j + singleIndex]]; ray2.direction = dir2; plane.Raycast(ray2, out var enter2); var lerp2 = enter2 / dir2.magnitude; //将两个切割点加入子网格 AddEdge(i, partMesh, left ? plane.normal * -1f : plane.normal, ray1.origin + ray1.direction.normalized * enter1, ray2.origin + ray2.direction.normalized * enter2, Vector2.Lerp(original.UV[triangles[j + singleIndex]], original.UV[triangles[j + ((singleIndex + 1) % 3)]], lerp1), Vector2.Lerp(original.UV[triangles[j + singleIndex]], original.UV[triangles[j + ((singleIndex + 2) % 3)]], lerp2)); //对于切割边缘 if (sideCount == 1) { partMesh.AddTriangle(i, original.Vertices[triangles[j + singleIndex]], ray1.origin + ray1.direction.normalized * enter1, ray2.origin + ray2.direction.normalized * enter2, original.Normals[triangles[j + singleIndex]], Vector3.Lerp(original.Normals[triangles[j + singleIndex]], original.Normals[triangles[j + ((singleIndex + 1) % 3)]], lerp1), Vector3.Lerp(original.Normals[triangles[j + singleIndex]], original.Normals[triangles[j + ((singleIndex + 2) % 3)]], lerp2), original.UV[triangles[j + singleIndex]], Vector2.Lerp(original.UV[triangles[j + singleIndex]], original.UV[triangles[j + ((singleIndex + 1) % 3)]], lerp1), Vector2.Lerp(original.UV[triangles[j + singleIndex]], original.UV[triangles[j + ((singleIndex + 2) % 3)]], lerp2)); continue; } if (sideCount == 2) { partMesh.AddTriangle(i, ray1.origin + ray1.direction.normalized * enter1, original.Vertices[triangles[j + ((singleIndex + 1) % 3)]], original.Vertices[triangles[j + ((singleIndex + 2) % 3)]], Vector3.Lerp(original.Normals[triangles[j + singleIndex]], original.Normals[triangles[j + ((singleIndex + 1) % 3)]], lerp1), original.Normals[triangles[j + ((singleIndex + 1) % 3)]], original.Normals[triangles[j + ((singleIndex + 2) % 3)]], Vector2.Lerp(original.UV[triangles[j + singleIndex]], original.UV[triangles[j + ((singleIndex + 1) % 3)]], lerp1), original.UV[triangles[j + ((singleIndex + 1) % 3)]], original.UV[triangles[j + ((singleIndex + 2) % 3)]]); partMesh.AddTriangle(i, ray1.origin + ray1.direction.normalized * enter1, original.Vertices[triangles[j + ((singleIndex + 2) % 3)]], ray2.origin + ray2.direction.normalized * enter2, Vector3.Lerp(original.Normals[triangles[j + singleIndex]], original.Normals[triangles[j + ((singleIndex + 1) % 3)]], lerp1), original.Normals[triangles[j + ((singleIndex + 2) % 3)]], Vector3.Lerp(original.Normals[triangles[j + singleIndex]], original.Normals[triangles[j + ((singleIndex + 2) % 3)]], lerp2), Vector2.Lerp(original.UV[triangles[j + singleIndex]], original.UV[triangles[j + ((singleIndex + 1) % 3)]], lerp1), original.UV[triangles[j + ((singleIndex + 2) % 3)]], Vector2.Lerp(original.UV[triangles[j + singleIndex]], original.UV[triangles[j + ((singleIndex + 2) % 3)]], lerp2)); continue; } } } partMesh.FillArrays(); return partMesh; } ////// 添加边 /// private void AddEdge(int subMesh, MeshPart meshPart, Vector3 normal, Vector3 vertex1, Vector3 vertex2, Vector2 uv1, Vector2 uv2) { if (!edgeSet) { edgeSet = true; edgeVertex = vertex1; edgeUV = uv1; } else { edgePlane.Set3Points(edgeVertex, vertex1, vertex2); meshPart.AddTriangle(subMesh, edgeVertex, edgePlane.GetSide(edgeVertex + normal) ? vertex1 : vertex2, edgePlane.GetSide(edgeVertex + normal) ? vertex2 : vertex1, normal, normal, normal, edgeUV, uv1, uv2); } } }
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MeshDestroyAble : MonoBehaviour
{
[Header("Render")]
public MeshFilter meshFilter;
public MeshRenderer meshRenderer;
[Header("Destroy Settings")]
public int cutCascades = 1;
public float explodeForce = 0;
public Mesh OrigionMesh
{
get
{
if (meshFilter == null)
{
meshFilter = GetComponentInChildren();
meshRenderer = GetComponentInChildren();
}
return meshFilter.mesh;
}
}
public void Init(MeshFilter meshFilter, MeshRenderer meshRenderer, int cutCascades, float explodeForce)
{
this.meshFilter = meshFilter;
this.meshRenderer = meshRenderer;
this.cutCascades = cutCascades;
this.explodeForce = explodeForce;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MeshPart
{
private List _Verticies = new List();
private List _Normals = new List();
private List> _Triangles = new List>();
private List _UVs = new List();
public Vector3[] Vertices;
public Vector3[] Normals;
public int[][] Triangles;
public Vector2[] UV;
public GameObject go;
public Rigidbody rb;
public Bounds Bounds = new Bounds();
public MeshPart()
{
}
public void AddTriangle(int submesh,
Vector3 vert1, Vector3 vert2, Vector3 vert3,
Vector3 normal1, Vector3 normal2, Vector3 normal3,
Vector2 uv1, Vector2 uv2, Vector2 uv3)
{
if (_Triangles.Count - 1 < submesh)
_Triangles.Add(new List());
_Triangles[submesh].Add(_Verticies.Count);
_Verticies.Add(vert1);
_Triangles[submesh].Add(_Verticies.Count);
_Verticies.Add(vert2);
_Triangles[submesh].Add(_Verticies.Count);
_Verticies.Add(vert3);
_Normals.Add(normal1);
_Normals.Add(normal2);
_Normals.Add(normal3);
_UVs.Add(uv1);
_UVs.Add(uv2);
_UVs.Add(uv3);
Bounds.min = Vector3.Min(Bounds.min, vert1);
Bounds.min = Vector3.Min(Bounds.min, vert2);
Bounds.min = Vector3.Min(Bounds.min, vert3);
Bounds.max = Vector3.Min(Bounds.max, vert1);
Bounds.max = Vector3.Min(Bounds.max, vert2);
Bounds.max = Vector3.Min(Bounds.max, vert3);
}
public void FillArrays()
{
Vertices = _Verticies.ToArray();
Normals = _Normals.ToArray();
UV = _UVs.ToArray();
Triangles = new int[_Triangles.Count][];
for (var i = 0; i < _Triangles.Count; i++)
Triangles[i] = _Triangles[i].ToArray();
}
public void MakeGameobject(MeshDestroyAble original)
{
go = new GameObject(original.name);
go.transform.position = original.transform.position;
go.transform.rotation = original.transform.rotation;
go.transform.localScale = original.transform.localScale;
var mesh = new Mesh();
mesh.name = original.OrigionMesh.name;
mesh.vertices = Vertices;
mesh.normals = Normals;
mesh.uv = UV;
for (var i = 0; i < Triangles.Length; i++)
mesh.SetTriangles(Triangles[i], i, true);
Bounds = mesh.bounds;
var renderer = go.AddComponent();
renderer.materials = original.meshRenderer.materials;
var filter = go.AddComponent();
filter.mesh = mesh;
var collider = go.AddComponent();
collider.convex = true;
rb = go.AddComponent();
var meshDestroy = go.AddComponent();
meshDestroy.Init(filter, renderer, original.cutCascades, original.explodeForce);
}
}
测试:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MeshDestroyTest : MonoBehaviour
{
// Update is called once per frame
void Update()
{
Destroy();
Slice();
}
private void Destroy()
{
//鼠标左键点击摧毁
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
MeshDestroyAble destroyAble = hit.collider.GetComponent();
if (destroyAble != null)
{
MeshDestroyMachine.Instance.DestroyMesh(destroyAble);
}
}
}
}
private Vector3 startPos;
private Vector3 endPos;
private void Slice()
{
//鼠标右键拖拽切割
if (Input.GetMouseButtonDown(1))
{
startPos = MouseWorldPos();
}
if (Input.GetMouseButton(1))
{
endPos = MouseWorldPos();
DrawLine();
}
if (Input.GetMouseButtonUp(1))
{
endPos = MouseWorldPos();
Plane plane = new Plane(GetNormal(), (startPos + endPos) * 2);
//GameObject.CreatePrimitive(PrimitiveType.Plane).transform.up = plane.normal; //Test for plane
//判断平面是否切到物体的方法:startPos和endPos构成的线是否和模型屏幕空间包围盒相交
//判断刀是否切到物体:基于刀的法线和位置构建平面,然后切
}
}
private Vector3 MouseWorldPos()
{
return Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 1));
}
private Vector3 GetNormal()
{
return Vector3.Cross(startPos - endPos, Camera.main.transform.forward);
}
private void DrawLine()
{
}
}



