IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Unity 程序破坏网格 -> 正文阅读

[游戏开发]Unity 程序破坏网格

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();

    /// <summary>
    /// 爆炸的切割
    /// </summary>
    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;
    }

    /// <summary>
    /// 刀剑的切割
    /// </summary>
    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;
    }

    /// <summary>
    /// 用平面切网格
    /// </summary>
    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;
    }

    /// <summary>
    /// 添加边
    /// </summary>
    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
{
    // 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<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);
            //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() 
    {
        
    }
}

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-05-08 08:26:50  更:2022-05-08 08:27:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 11:47:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码