using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MeshDestroyMachine : Singleton<MeshDestroyMachine>
{
private bool edgeSet = false;
private Vector3 edgeVertex = Vector3.zero;
private Vector2 edgeUV = Vector2.zero;
private Plane edgePlane = new Plane();
public List<MeshPart> DestroyMesh(MeshDestroyAble destroyAble)
{
Mesh originalMesh = destroyAble.OrigionMesh;
if (originalMesh == null) { return null; }
originalMesh.RecalculateBounds();
List<MeshPart> parts = new List<MeshPart>();
List<MeshPart> subParts = new List<MeshPart>();
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<MeshPart>(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 List<MeshPart> SliceMesh(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<MeshPart> parts = new List<MeshPart>();
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<MeshFilter>();
meshRenderer = GetComponentInChildren<MeshRenderer>();
}
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<Vector3> _Verticies = new List<Vector3>();
private List<Vector3> _Normals = new List<Vector3>();
private List<List<int>> _Triangles = new List<List<int>>();
private List<Vector2> _UVs = new List<Vector2>();
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<int>());
_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<MeshRenderer>();
renderer.materials = original.meshRenderer.materials;
var filter = go.AddComponent<MeshFilter>();
filter.mesh = mesh;
var collider = go.AddComponent<MeshCollider>();
collider.convex = true;
rb = go.AddComponent<Rigidbody>();
var meshDestroy = go.AddComponent<MeshDestroyAble>();
meshDestroy.Init(filter, renderer, original.cutCascades, original.explodeForce);
}
}
测试:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MeshDestroyTest : MonoBehaviour
{
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<MeshDestroyAble>();
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);
}
}
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()
{
}
}
|