Skip to content

Instantly share code, notes, and snippets.

@FullStackForger
Forked from ditzel/MeshDestroy.cs
Created April 1, 2022 20:26
Show Gist options
  • Select an option

  • Save FullStackForger/1329fb7f862bd4d23780499af8292093 to your computer and use it in GitHub Desktop.

Select an option

Save FullStackForger/1329fb7f862bd4d23780499af8292093 to your computer and use it in GitHub Desktop.

Revisions

  1. @ditzel ditzel created this gist Aug 19, 2019.
    302 changes: 302 additions & 0 deletions MeshDestroy.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,302 @@
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class MeshDestroy : MonoBehaviour
    {
    private bool edgeSet = false;
    private Vector3 edgeVertex = Vector3.zero;
    private Vector2 edgeUV = Vector2.zero;
    private Plane edgePlane = new Plane();

    public int CutCascades = 1;
    public float ExplodeForce = 0;

    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
    if (Input.GetMouseButtonDown(0))
    {
    DestroyMesh();
    }
    }

    private void DestroyMesh()
    {
    var originalMesh = GetComponent<MeshFilter>().mesh;
    originalMesh.RecalculateBounds();
    var parts = new List<PartMesh>();
    var subParts = new List<PartMesh>();

    var mainPart = new PartMesh()
    {
    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 (var c = 0; c < CutCascades; c++)
    {
    for (var i = 0; i < parts.Count; i++)
    {
    var bounds = parts[i].Bounds;
    bounds.Expand(0.5f);

    var 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<PartMesh>(subParts);
    subParts.Clear();
    }

    for (var i = 0; i < parts.Count; i++)
    {
    parts[i].MakeGameobject(this);
    parts[i].GameObject.GetComponent<Rigidbody>().AddForceAtPosition(parts[i].Bounds.center * ExplodeForce, transform.position);
    }

    Destroy(gameObject);
    }

    private PartMesh GenerateMesh(PartMesh original, Plane plane, bool left)
    {
    var partMesh = new PartMesh() { };
    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;
    }

    //cut points
    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;

    //first vertex = ancor
    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]],
    //Vector3.Lerp(originalMesh.vertices[triangles[j + singleIndex]], originalMesh.vertices[triangles[j + ((singleIndex + 1) % 3)]], lerp1),
    //Vector3.Lerp(originalMesh.vertices[triangles[j + singleIndex]], originalMesh.vertices[triangles[j + ((singleIndex + 2) % 3)]], lerp2),
    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, PartMesh partMesh, Vector3 normal, Vector3 vertex1, Vector3 vertex2, Vector2 uv1, Vector2 uv2)
    {
    if (!edgeSet)
    {
    edgeSet = true;
    edgeVertex = vertex1;
    edgeUV = uv1;
    }
    else
    {
    edgePlane.Set3Points(edgeVertex, vertex1, vertex2);

    partMesh.AddTriangle(subMesh,
    edgeVertex,
    edgePlane.GetSide(edgeVertex + normal) ? vertex1 : vertex2,
    edgePlane.GetSide(edgeVertex + normal) ? vertex2 : vertex1,
    normal,
    normal,
    normal,
    edgeUV,
    uv1,
    uv2);
    }
    }

    public class PartMesh
    {
    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 GameObject;
    public Bounds Bounds = new Bounds();

    public PartMesh()
    {

    }

    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(MeshDestroy original)
    {
    GameObject = new GameObject(original.name);
    GameObject.transform.position = original.transform.position;
    GameObject.transform.rotation = original.transform.rotation;
    GameObject.transform.localScale = original.transform.localScale;

    var mesh = new Mesh();
    mesh.name = original.GetComponent<MeshFilter>().mesh.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 = GameObject.AddComponent<MeshRenderer>();
    renderer.materials = original.GetComponent<MeshRenderer>().materials;

    var filter = GameObject.AddComponent<MeshFilter>();
    filter.mesh = mesh;

    var collider = GameObject.AddComponent<MeshCollider>();
    collider.convex = true;

    var rigidbody = GameObject.AddComponent<Rigidbody>();
    var meshDestroy = GameObject.AddComponent<MeshDestroy>();
    meshDestroy.CutCascades = original.CutCascades;
    meshDestroy.ExplodeForce = original.ExplodeForce;

    }

    }
    }