当前位置: 首页 > news >正文

【Unity3D】利用IJob、Burst优化处理切割物体

参考文章: 

【Unity】切割网格

【Unity3D】ECS入门学习(一)导入及基础学习_unity ecs教程-CSDN博客 

【Unity3D】ECS入门学习(十二)IJob、IJobFor、IJobParallelFor_unity ijobparallelfor-CSDN博客

工程资源地址: 

BStandShaderResources/job_burst_cut_demo.unitypackage at master · AMikeW/BStandShaderResources · GitHub

优化前

使用Job、Burst会将切割数据处理放到一个非主线程处理,并行加速计算。
麻烦的地方是所有List<T>都要改成NativeArray,所有Dictionary<K,V>都要改成NativeHashMap<K,V>,以及不能传递GameObject,Transform等,也就是不能有任何的引用类型对象出现在继承了IJob接口的脚本,而且CutJob是一个struct结构体。

注意:在CutManager脚本,必须引入:using Unity.Jobs; 才能使用job.Schedule接口方法,因为这玩意并不是IJor的方法,毕竟IJor只是个接口,它是一个扩展方法。

namespace Unity.Jobs
{//// 摘要://     Extension methods for Jobs using the IJob interface.public static class IJobExtensions{public static void Run<T>(this T jobData) where T : struct, IJob;public static JobHandle Schedule<T>(this T jobData, JobHandle dependsOn = default) where T : struct, IJob;}
}

  只会切割CutGo标签的物体 

开启Job

using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;/// <summary>
/// 切割平面信息
/// </summary>
public class CutInfo
{public Vector3 cutPoint;      //对应射线碰撞点public Vector3 cutHorizontal; //对应dirpublic Vector3 cutVertical;//对应verticalpublic Vector3 cutNormal;  //对应normal
}/// <summary>
/// 必须挂在摄像机上才会有GL线条
/// 功能:凸网格切割网格(不支持凹网格)
/// 使用方法:按F开启和禁用切割功能,鼠标指向物体出现辅助线条,滑轮滚动控制切割线条旋转,鼠标左击进行切割物体
/// </summary>
public class CutManager : MonoBehaviour
{private static CutManager _instance;public static CutManager Instance{get { return _instance; }}bool isOn;public bool blockCut;Transform hitTarget;Vector3 hitPos;Vector3 dir;Vector3 cutVerticalDir;Vector3 cutNormalDir;float angle;float scrollSpeed = 25.0f;bool isCutting;Mesh targetMesh;const string TagName = "CutGo";public Transform generatePoint;//使用GL画线所需材质public Material mater;private float force = 0.8f;public float destroyTime = 0.5f;public List<CutInfo> cutInfos; //记录所有正常的切割(防止出现极其相似的切割平面造成奇怪的bug)public Material dissolveMat;private GameObject lastCutObject;private Vector3 cutStartPos;private Vector3 cutEndPos;private Action<float> cutCallback;public bool isUseJob;//试图尝试使用常驻的变量,但测试发现会导致数据混乱,具体表现是切割第二次时,整个模型的顶点乱了,如果使用TempJob临时的则不会发生//NativeArray<Vector3> _tempVert1;//NativeArray<Vector3> _tempVert2;//NativeArray<Vector3> _tempNormal1;//NativeArray<Vector3> _tempNormal2;//NativeArray<int> _tempTriangles1;//NativeArray<int> _tempTriangles2;//NativeArray<Vector2> _uvs1;//NativeArray<Vector2> _uvs2;//NativeHashMap<int, int> _tempIndex1;//NativeHashMap<int, int> _tempIndex2;//NativeArray<int> _temp1CountArray;//NativeArray<int> _temp2CountArray;//NativeArray<Vector3> _localPos;//NativeArray<Vector3> _allPos;//NativeArray<Vector3> targetMeshVert;//NativeArray<Vector3> targetMeshNormal;//NativeArray<int> targetMeshTriangles;private void Awake(){_instance = this;}private void OnDestroy(){//targetMeshVert.Dispose();//targetMeshNormal.Dispose();//targetMeshTriangles.Dispose();//_tempVert1.Dispose();//_tempNormal1.Dispose();//_tempTriangles1.Dispose();//_uvs1.Dispose();//_tempVert2.Dispose();//_tempNormal2.Dispose();//_tempTriangles2.Dispose();//_uvs2.Dispose();//_temp1CountArray.Dispose();//_temp2CountArray.Dispose();//_tempIndex1.Dispose();//_tempIndex2.Dispose();//_localPos.Dispose();//_allPos.Dispose();}void Start(){isOn = false;tempVert1 = new List<Vector3>();tempNormal1 = new List<Vector3>();tempTriangles1 = new List<int>();tempIndex1 = new Dictionary<int, int>();uvs1 = new List<Vector2>();tempVert2 = new List<Vector3>();tempNormal2 = new List<Vector3>();tempTriangles2 = new List<int>();tempIndex2 = new Dictionary<int, int>();uvs2 = new List<Vector2>();localPos = new List<Vector3>();allPos = new List<Vector3>();cutInfos = new List<CutInfo>();//targetMeshVert = new Unity.Collections.NativeArray<Vector3>(5000, Unity.Collections.Allocator.Persistent);//targetMeshNormal = new Unity.Collections.NativeArray<Vector3>(2500, Unity.Collections.Allocator.Persistent);//targetMeshTriangles = new Unity.Collections.NativeArray<int>(9000, Unity.Collections.Allocator.Persistent);//_tempVert1 = new Unity.Collections.NativeArray<Vector3>(5000, Unity.Collections.Allocator.Persistent);//_tempNormal1 = new Unity.Collections.NativeArray<Vector3>(2500, Unity.Collections.Allocator.Persistent);//_tempTriangles1 = new Unity.Collections.NativeArray<int>(9000, Unity.Collections.Allocator.Persistent);//_uvs1 = new Unity.Collections.NativeArray<Vector2>(5000, Unity.Collections.Allocator.Persistent);//_tempIndex1 = new Unity.Collections.NativeHashMap<int, int>(9000, Unity.Collections.Allocator.Persistent);//_temp1CountArray = new NativeArray<int>(5, Allocator.Persistent);//_tempVert2 = new Unity.Collections.NativeArray<Vector3>(5000, Unity.Collections.Allocator.Persistent);//_tempNormal2 = new Unity.Collections.NativeArray<Vector3>(2500, Unity.Collections.Allocator.Persistent);//_tempTriangles2 = new Unity.Collections.NativeArray<int>(9000, Unity.Collections.Allocator.Persistent);//_uvs2 = new Unity.Collections.NativeArray<Vector2>(5000, Unity.Collections.Allocator.Persistent);//_tempIndex2 = new Unity.Collections.NativeHashMap<int, int>(9000, Unity.Collections.Allocator.Persistent);//_temp2CountArray = new NativeArray<int>(5, Allocator.Persistent);//_localPos = new NativeArray<Vector3>(1000, Allocator.Persistent);//_allPos = new NativeArray<Vector3>(1000, Allocator.Persistent);}void Update(){ControlIsOn();ControlCutSpace();}void OnPostRender(){if (!isOn || !isCutting)return;if (!mater){Debug.LogError("Please Assign a material on the inspector");return;}GL.PushMatrix();mater.SetPass(0);GL.Color(Color.yellow);GL.Begin(GL.LINES);GL.Vertex(hitPos + cutVerticalDir * 12f + dir * 1f);GL.Vertex(hitPos - cutVerticalDir * 12f + dir * 1f);GL.Vertex(hitPos + dir * 1f);GL.Vertex(hitPos + cutNormalDir * 0.2f + dir * 1f);GL.End();GL.PopMatrix();}void ControlIsOn(){isOn = true;}void ControlCutSpace(){//射线发射射线计算出射线交点,以射线为轴计算出另外2个轴向 (红线为射线,绿线为垂直于射线和法线的线, 黄线为法线)        Ray ray = Camera.main.ScreenPointToRay(InputController.GetPosition());Debug.DrawRay(Camera.main.transform.position, InputController.GetPosition(), Color.red);RaycastHit hit;if (Physics.Raycast(ray, out hit)){if (hit.transform.tag != TagName){TryCut();cutStartPos = Vector3.zero;cutEndPos = Vector3.zero;return;}if (cutStartPos == null || cutStartPos == Vector3.zero){cutStartPos = hit.point;}isCutting = true;hitTarget = hit.transform;hitPos = hit.point;cutEndPos = hitPos;MeshFilter meshFilter = hit.transform.GetComponent<MeshFilter>();if (meshFilter != null){targetMesh = hit.transform.GetComponent<MeshFilter>().mesh;}else{Debug.LogWarning("尝试切割没有网格的物品");cutStartPos = Vector3.zero;cutEndPos = Vector3.zero;return;}//dir = (Camera.main.transform.position - hitPos).normalized;//cutVerticalDir = (Vector3.Dot(dir, Vector3.up) * -dir + Vector3.up).normalized;//dir和cutVerticalDir保持垂直使用鼠标滚轮旋转切割平面//if (Input.GetAxis("Mouse ScrollWheel") < 0)//{//    angle += scrollSpeed * Time.deltaTime;//}//else if (Input.GetAxis("Mouse ScrollWheel") > 0)//{//    angle -= scrollSpeed * Time.deltaTime;//}//cutVerticalDir = Quaternion.AngleAxis(Mathf.Rad2Deg * angle, dir) * cutVerticalDir; //围绕dir轴旋转//cutNormalDir = Vector3.Cross(dir, cutVerticalDir).normalized; //计算出切割面的法线#if DEBUG//Debug.DrawRay(hitPos, cutVerticalDir, Color.green);//Debug.DrawRay(hitPos, dir, Color.red);//Debug.DrawRay(hitPos, cutNormalDir, Color.yellow);
#endif            }else{TryCut();cutStartPos = Vector3.zero;cutEndPos = Vector3.zero;isCutting = false;}滑动切割//Ray ray1 = Camera.main.ScreenPointToRay(InputController.GetPosition());//Physics.Raycast(ray);//if (Input.GetKeyDown(KeyCode.Mouse0))//{//    CutInfo tempCutInfo = new CutInfo();//    tempCutInfo.cutHorizontal = dir;//    tempCutInfo.cutVertical = cutVerticalDir;//    tempCutInfo.cutNormal = cutNormalDir;//    Cutting();//}}IEnumerator TryCutting1(){for (int i = 0; i < 3; i++){if ((cutEndPos != null && cutEndPos != Vector3.zero) && (cutStartPos != null && cutStartPos != Vector3.zero)){isCutting = true;var point = (cutStartPos + cutEndPos) / 2;dir = (Camera.main.transform.position - point).normalized;var tempDir = (cutEndPos - cutStartPos).normalized;cutVerticalDir = (Vector3.Dot(dir, tempDir) * -dir + tempDir).normalized;//dir和cutVerticalDir保持垂直cutNormalDir = Vector3.Cross(dir, cutVerticalDir).normalized; //计算出切割面的法线Cutting();yield return new WaitForSeconds(0.1f);}}cutEndPos = Vector3.zero;cutStartPos = Vector3.zero;}private void TryCut(){if (!blockCut && (cutEndPos != null && cutEndPos != Vector3.zero) && (cutStartPos != null && cutStartPos != Vector3.zero)){isCutting = true;var point = (cutStartPos + cutEndPos) / 2;dir = (Camera.main.transform.position - point).normalized;var tempDir = (cutEndPos - cutStartPos).normalized;cutVerticalDir = (Vector3.Dot(dir, tempDir) * -dir + tempDir).normalized;//dir和cutVerticalDir保持垂直cutNormalDir = Vector3.Cross(dir, cutVerticalDir).normalized; //计算出切割面的法线Cutting();}cutEndPos = Vector3.zero;cutStartPos = Vector3.zero;isCutting = false;}private bool IsValidCutInfo(Vector3 dir, Vector3 vertical, Vector3 normal){float limitValue = 0.15f;foreach (var v in cutInfos){if (Mathf.Abs(dir.x - v.cutHorizontal.x) < limitValue && Mathf.Abs(dir.y - v.cutHorizontal.y) < limitValue && Mathf.Abs(dir.z - v.cutHorizontal.z) < limitValue&& Mathf.Abs(vertical.x - v.cutVertical.x) < limitValue && Mathf.Abs(vertical.y - v.cutVertical.y) < limitValue && Mathf.Abs(vertical.z - v.cutVertical.z) < limitValue&& Mathf.Abs(normal.x - v.cutNormal.x) < limitValue && Mathf.Abs(normal.y - v.cutNormal.y) < limitValue && Mathf.Abs(normal.z - v.cutNormal.z) < limitValue){return false;}}return true;}List<Vector3> tempVert1;List<Vector3> tempNormal1;List<int> tempTriangles1;Dictionary<int, int> tempIndex1;List<Vector2> uvs1;List<Vector3> tempVert2;List<Vector3> tempNormal2;List<int> tempTriangles2;Dictionary<int, int> tempIndex2;List<Vector2> uvs2;int[] triangles;List<Vector3> localPos;List<Vector3> allPos;void Cutting(){if (!isCutting || !isOn || targetMesh == null || hitTarget == null)return;tempVert1.Clear();tempNormal1.Clear();tempTriangles1.Clear();tempIndex1.Clear();uvs1.Clear();tempVert2.Clear();tempNormal2.Clear();tempTriangles2.Clear();tempIndex2.Clear();uvs2.Clear();allPos.Clear();System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();if (isUseJob){CutJob job = new CutJob();var vertices = targetMesh.vertices;var normals = targetMesh.normals;var triangles = targetMesh.triangles;var _tempVert1 = new Unity.Collections.NativeArray<Vector3>(5000, Unity.Collections.Allocator.TempJob);var _tempNormal1 = new Unity.Collections.NativeArray<Vector3>(2500, Unity.Collections.Allocator.TempJob);var _tempTriangles1 = new Unity.Collections.NativeArray<int>(9000, Unity.Collections.Allocator.TempJob);var _uvs1 = new Unity.Collections.NativeArray<Vector2>(5000, Unity.Collections.Allocator.TempJob);var _tempIndex1 = new Unity.Collections.NativeHashMap<int, int>(9000, Unity.Collections.Allocator.TempJob);var _temp1CountArray = new NativeArray<int>(5, Allocator.TempJob);var _tempVert2 = new Unity.Collections.NativeArray<Vector3>(5000, Unity.Collections.Allocator.TempJob);var _tempNormal2 = new Unity.Collections.NativeArray<Vector3>(2500, Unity.Collections.Allocator.TempJob);var _tempTriangles2 = new Unity.Collections.NativeArray<int>(9000, Unity.Collections.Allocator.TempJob);var _uvs2 = new Unity.Collections.NativeArray<Vector2>(5000, Unity.Collections.Allocator.TempJob);var _tempIndex2 = new Unity.Collections.NativeHashMap<int, int>(9000, Unity.Collections.Allocator.TempJob);var _temp2CountArray = new NativeArray<int>(5, Allocator.TempJob);var _localPos = new NativeArray<Vector3>(1000, Allocator.TempJob);var _allPos = new NativeArray<Vector3>(1000, Allocator.TempJob);var targetMeshVert = new Unity.Collections.NativeArray<Vector3>(vertices.Length, Unity.Collections.Allocator.TempJob);var targetMeshNormal = new Unity.Collections.NativeArray<Vector3>(normals.Length, Unity.Collections.Allocator.TempJob);var targetMeshTriangles = new Unity.Collections.NativeArray<int>(triangles.Length, Unity.Collections.Allocator.TempJob);for (int i = 0; i < vertices.Length; i++){targetMeshVert[i] = vertices[i];}job.targetMeshVert = targetMeshVert;for (int i = 0; i < normals.Length; i++){targetMeshNormal[i] = normals[i];}job.targetMeshNormal = targetMeshNormal;for (int i = 0; i < triangles.Length; i++){targetMeshTriangles[i] = triangles[i];}job.targetMeshTriangles_Count = triangles.Length;job.targetMeshTriangles = targetMeshTriangles;//job.hitTarget = hitTarget;job.hitTarget_LocalScale = hitTarget.localScale;job.hitTarget_o2w = hitTarget.localToWorldMatrix;job.hitTarget_w2o = hitTarget.worldToLocalMatrix;job.hitPos = hitPos;job.dir = dir;job.cutVerticalDir = cutVerticalDir;job.cutNormalDir = cutNormalDir;job.tempVert1_Count = 0;job.tempVert1 = _tempVert1;job.tempNormal1_Count = 0;job.tempNormal1 = _tempNormal1;job.tempTriangles1_Count = 0;job.tempTriangles1 = _tempTriangles1;job.uvs1_Count = 0;job.uvs1 = _uvs1;job.tempIndex1 = _tempIndex1;job.temp1CountArray = _temp1CountArray;job.tempVert2_Count = 0;job.tempVert2 = _tempVert2;job.tempNormal2_Count = 0;job.tempNormal2 = _tempNormal2;job.tempTriangles2_Count = 0;job.tempTriangles2 = _tempTriangles2;job.uvs2_Count = 0;job.uvs2 = _uvs2;job.tempIndex2 = _tempIndex2;job.temp2CountArray = _temp2CountArray;job.localPos = _localPos;job.allPos = _allPos;JobHandle jobHandle = job.Schedule();jobHandle.Complete();//数据转化 切割后的2个模型数据(顶点、法线、索引、UV)int temp1_VertCount = job.temp1CountArray[0];int temp1_NormalCount = job.temp1CountArray[1];int temp1_TrianglesCount = job.temp1CountArray[2];int temp1_UvsCount = job.temp1CountArray[3];int temp2_VertCount = job.temp2CountArray[0];int temp2_NormalCount = job.temp2CountArray[1];int temp2_TrianglesCount = job.temp2CountArray[2];int temp2_UvsCount = job.temp2CountArray[3];for (int i = 0; i < temp1_VertCount; i++){tempVert1.Add(_tempVert1[i]);}for (int i = 0; i < temp2_VertCount; i++){tempVert2.Add(_tempVert2[i]);}for (int i = 0; i < temp1_NormalCount; i++){tempNormal1.Add(_tempNormal1[i]);}for (int i = 0; i < temp2_NormalCount; i++){tempNormal2.Add(_tempNormal2[i]);}for (int i = 0; i < temp1_TrianglesCount; i++){tempTriangles1.Add(_tempTriangles1[i]);}for (int i = 0; i < temp2_TrianglesCount; i++){tempTriangles2.Add(_tempTriangles2[i]);}for (int i = 0; i < temp1_UvsCount; i++){uvs1.Add(_uvs1[i]);}for (int i = 0; i < temp2_UvsCount; i++){uvs2.Add(_uvs2[i]);}//>>>>>>>>>>>>>>>>>>>>>>>>>>>>第一个切割出的物体开始构建Mesh originMesh = new Mesh(), newMesh = new Mesh();       originMesh.vertices = tempVert1.ToArray();originMesh.normals = tempNormal1.ToArray();originMesh.triangles = tempTriangles1.ToArray();originMesh.uv = uvs1.ToArray();hitTarget.GetComponent<MeshFilter>().mesh = originMesh;Collider collider = hitTarget.GetComponent<Collider>();if (collider != null){Destroy(collider);}//hitTarget.gameObject.AddComponent<BoxCollider>();MeshCollider meshCollider = hitTarget.gameObject.AddComponent<MeshCollider>();hitTarget.gameObject.tag = TagName;hitTarget.gameObject.layer = 11;hitTarget.SetParent(generatePoint);float obj1Volume = CalculateVolumeHelper.CalculateSumVolume(hitTarget.transform.lossyScale, hitTarget.GetComponent<MeshFilter>());//>>>>>>>>>>>>>>>>>>>>>>>>>>切割出的第二个物体开始构建newMesh.vertices = tempVert2.ToArray();newMesh.normals = tempNormal2.ToArray();newMesh.triangles = tempTriangles2.ToArray();newMesh.uv = uvs2.ToArray();GameObject newobj = new GameObject();newobj.transform.position = hitTarget.position;newobj.transform.rotation = hitTarget.rotation;newobj.transform.localScale = hitTarget.localScale;newobj.AddComponent<MeshFilter>().mesh = newMesh;newobj.AddComponent<MeshRenderer>();Material mat = hitTarget.GetComponent<MeshRenderer>().material;newobj.GetComponent<MeshRenderer>().material = new Material(mat);newobj.tag = TagName;newobj.layer = 11;newobj.transform.SetParent(generatePoint);//顶点少的情况可以使用它 否则会报错超出顶点限制MeshCollider meshCollider2 = newobj.AddComponent<MeshCollider>();try{meshCollider.convex = true;meshCollider2.convex = true;}catch (Exception e){Debug.LogWarning(e.Message);}float obj2Volume = CalculateVolumeHelper.CalculateSumVolume(newobj.transform.lossyScale, newobj.GetComponent<MeshFilter>());//this.cutCallback(Mathf.Min(obj1Volume, obj2Volume));//比较两者体积,较小的一个进行添加刚体 自由落体...if (obj1Volume < obj2Volume){//hitTarget物体掉落 消失Rigidbody rigidbody1 = hitTarget.gameObject.GetOrAddComponent<Rigidbody>();rigidbody1.AddForce((hitTarget.InverseTransformDirection(cutNormalDir) * force), ForceMode.Impulse); //可去掉这个力            CutObjectDestroyBySelf cutObjectDestroyBySelf = hitTarget.gameObject.GetComponent<CutObjectDestroyBySelf>();if (!cutObjectDestroyBySelf){cutObjectDestroyBySelf = hitTarget.gameObject.AddComponent<CutObjectDestroyBySelf>();cutObjectDestroyBySelf.time = destroyTime;}cutObjectDestroyBySelf.SetMat(dissolveMat);Rigidbody newobjRigidbody = newobj.GetComponent<Rigidbody>();if (newobjRigidbody){Destroy(newobjRigidbody);}lastCutObject = newobj;}else{Rigidbody rigidbody2 = newobj.GetOrAddComponent<Rigidbody>();rigidbody2.AddForce(-newobj.transform.InverseTransformDirection(cutNormalDir) * force, ForceMode.Impulse);//可去掉这个力            CutObjectDestroyBySelf cutObjectDestroyBySelf = newobj.GetComponent<CutObjectDestroyBySelf>();if (!cutObjectDestroyBySelf){cutObjectDestroyBySelf = newobj.AddComponent<CutObjectDestroyBySelf>();cutObjectDestroyBySelf.time = destroyTime;}cutObjectDestroyBySelf.SetMat(dissolveMat);Rigidbody hitTargetRigidbody = hitTarget.gameObject.GetComponent<Rigidbody>();if (hitTargetRigidbody){Destroy(hitTargetRigidbody);}lastCutObject = hitTarget.gameObject;}//Destroy(newobj, 5f);targetMeshVert.Dispose();targetMeshNormal.Dispose();targetMeshTriangles.Dispose();_tempVert1.Dispose();_tempNormal1.Dispose();_tempTriangles1.Dispose();_uvs1.Dispose();_tempVert2.Dispose();_tempNormal2.Dispose();_tempTriangles2.Dispose();_uvs2.Dispose();_temp1CountArray.Dispose();_temp2CountArray.Dispose();_tempIndex1.Dispose();_tempIndex2.Dispose();_localPos.Dispose();_allPos.Dispose();}else{triangles = targetMesh.triangles;for (int i = 0; i < triangles.Length; i += 3){int index1 = triangles[i];int index2 = triangles[i + 1];int index3 = triangles[i + 2];Vector3 vertex1 = targetMesh.vertices[index1];Vector3 vertex2 = targetMesh.vertices[index2];Vector3 vertex3 = targetMesh.vertices[index3];float vert1 = Vector3.Dot(cutNormalDir, (hitTarget.TransformPoint(vertex1) - hitPos).normalized);float vert2 = Vector3.Dot(cutNormalDir, (hitTarget.TransformPoint(vertex2) - hitPos).normalized);float vert3 = Vector3.Dot(cutNormalDir, (hitTarget.TransformPoint(vertex3) - hitPos).normalized);if (vert1 >= 0 && vert2 >= 0 && vert3 >= 0){//同面if (!tempIndex1.ContainsKey(index1)) //过滤相同顶点{tempVert1.Add(vertex1);tempNormal1.Add(targetMesh.normals[index1]);tempIndex1.Add(index1, tempVert1.Count - 1); //旧索引为key,新索引为value}if (!tempIndex1.ContainsKey(index2)) //过滤相同顶点{tempVert1.Add(vertex2);tempNormal1.Add(targetMesh.normals[index2]);tempIndex1.Add(index2, tempVert1.Count - 1); //旧索引为key,新索引为value}if (!tempIndex1.ContainsKey(index3)) //过滤相同顶点{tempVert1.Add(vertex3);tempNormal1.Add(targetMesh.normals[index3]);tempIndex1.Add(index3, tempVert1.Count - 1); //旧索引为key,新索引为value}tempTriangles1.Add(tempIndex1[index1]); //使用旧索引index1 获取对应的新索引tempTriangles1.Add(tempIndex1[index2]); //使用旧索引index2 获取对应的新索引tempTriangles1.Add(tempIndex1[index3]); //使用旧索引index3 获取对应的新索引if (tempIndex1[index1] == tempIndex1[index2] || tempIndex1[index1] == tempIndex1[index3] || tempIndex1[index2] == tempIndex1[index3]){Debug.LogError("[1]問題");}}else if (vert1 <= 0 && vert2 <= 0 && vert3 <= 0){//另一个同面                if (!tempIndex2.ContainsKey(index1)) //过滤相同顶点{tempVert2.Add(vertex1);tempNormal2.Add(targetMesh.normals[index1]);tempIndex2.Add(index1, tempVert2.Count - 1); //旧索引为key,新索引为value}if (!tempIndex2.ContainsKey(index2)) //过滤相同顶点{tempVert2.Add(vertex2);tempNormal2.Add(targetMesh.normals[index2]);tempIndex2.Add(index2, tempVert2.Count - 1); //旧索引为key,新索引为value}if (!tempIndex2.ContainsKey(index3)) //过滤相同顶点{tempVert2.Add(vertex3);tempNormal2.Add(targetMesh.normals[index3]);tempIndex2.Add(index3, tempVert2.Count - 1); //旧索引为key,新索引为value}tempTriangles2.Add(tempIndex2[index1]); //使用旧索引index1 获取对应的新索引tempTriangles2.Add(tempIndex2[index2]); //使用旧索引index2 获取对应的新索引tempTriangles2.Add(tempIndex2[index3]); //使用旧索引index3 获取对应的新索引if (tempIndex2[index1] == tempIndex2[index2] || tempIndex2[index1] == tempIndex2[index3] || tempIndex2[index2] == tempIndex2[index3]){Debug.LogError("[2]問題");}}else{//continue;localPos.Clear();//不同面情况 (PS:不存在3点不同面情况)bool isV1V2Sample = (vert1 > 0 && vert2 > 0 || vert1 < 0 && vert2 < 0);bool isV2V3Sample = (vert2 > 0 && vert3 > 0 || vert2 < 0 && vert3 < 0);bool isV3V1Sample = (vert3 > 0 && vert1 > 0 || vert3 < 0 && vert1 < 0);Vector3 normal = Vector3.Cross(vertex2 - vertex1, vertex3 - vertex2);//1. index1 和 index2 顶点不同面if (!(isV1V2Sample)){CaculateIntersectionPoint(vertex1, vertex2);}//2. index2 和 index3 顶点不同面if (!(isV2V3Sample)){CaculateIntersectionPoint(vertex2, vertex3);}//3. index3 和 index1 顶点不同面if (!(isV3V1Sample)){CaculateIntersectionPoint(vertex3, vertex1);}//此时localPos保存2个交点, allPos是保存所有交点的if (isV1V2Sample){if (vert1 > 0 && vert2 > 0){if (index1 == index2){Debug.LogError(">>>>>>>>>>>>>>>>>>>>>1 : " + index1);}ConnectPointToTriangle(index1, index2, localPos[0], localPos[1], normal, ref tempVert1, ref tempNormal1, ref tempTriangles1, ref tempIndex1, index3);ConnectPointToTriangle(index3, localPos[0], localPos[1], normal, ref tempVert2, ref tempNormal2, ref tempTriangles2, ref tempIndex2);}else{if (index1 == index2){Debug.LogError(">>>>>>>>>>>>>>>>>>>>>2 : " + index1);}ConnectPointToTriangle(index1, index2, localPos[0], localPos[1], normal, ref tempVert2, ref tempNormal2, ref tempTriangles2, ref tempIndex2, index3);ConnectPointToTriangle(index3, localPos[0], localPos[1], normal, ref tempVert1, ref tempNormal1, ref tempTriangles1, ref tempIndex1);}}if (isV2V3Sample){if (vert2 > 0 && vert3 > 0){if (index2 == index3){Debug.LogError(">>>>>>>>>>>>>>>>>>>>>3 : " + index2);}ConnectPointToTriangle(index2, index3, localPos[0], localPos[1], normal, ref tempVert1, ref tempNormal1, ref tempTriangles1, ref tempIndex1, index1);ConnectPointToTriangle(index1, localPos[0], localPos[1], normal, ref tempVert2, ref tempNormal2, ref tempTriangles2, ref tempIndex2);}else{if (index2 == index3){Debug.LogError(">>>>>>>>>>>>>>>>>>>>>4 : " + index2);}ConnectPointToTriangle(index2, index3, localPos[0], localPos[1], normal, ref tempVert2, ref tempNormal2, ref tempTriangles2, ref tempIndex2, index1);ConnectPointToTriangle(index1, localPos[0], localPos[1], normal, ref tempVert1, ref tempNormal1, ref tempTriangles1, ref tempIndex1);}}if (isV3V1Sample){if (vert3 > 0 && vert1 > 0){if (index3 == index1){Debug.LogError(">>>>>>>>>>>>>>>>>>>>>5 : " + index3);}ConnectPointToTriangle(index3, index1, localPos[0], localPos[1], normal, ref tempVert1, ref tempNormal1, ref tempTriangles1, ref tempIndex1, index2);ConnectPointToTriangle(index2, localPos[0], localPos[1], normal, ref tempVert2, ref tempNormal2, ref tempTriangles2, ref tempIndex2);}else{if (index3 == index1){Debug.LogError(">>>>>>>>>>>>>>>>>>>>>6 : " + index3);}ConnectPointToTriangle(index3, index1, localPos[0], localPos[1], normal, ref tempVert2, ref tempNormal2, ref tempTriangles2, ref tempIndex2, index2);ConnectPointToTriangle(index2, localPos[0], localPos[1], normal, ref tempVert1, ref tempNormal1, ref tempTriangles1, ref tempIndex1);}}}}//补全截面FillCutSurface();//注释下面两行代码,UV纹理全没但报错没了(目前UV组成有问题可能会导致模型某一面完全透明)//BUG已查明:上面代码生成新2个网格数据 会存在三角面的3个顶点位置数据一样,导致UV无法正常出现,因此此时简单地做个后处理 剔除这些异常三角面 ...      //bool isFilter1 = TempFuncFilterErrorTriangle(ref tempVert1, ref tempTriangles1, ref tempNormal1); //依然有问题 待修复...//bool isFilter2 = TempFuncFilterErrorTriangle(ref tempVert2, ref tempTriangles2, ref tempNormal2);CalculateUV(hitTarget.transform.localScale, tempVert1, tempTriangles1, tempNormal1, ref uvs1);CalculateUV(hitTarget.transform.localScale, tempVert2, tempTriangles2, tempNormal2, ref uvs2);//>>>>>>>>>>>>>>>>>>>>>>>>>>>>第一个切割出的物体开始构建Mesh originMesh = new Mesh(), newMesh = new Mesh();originMesh.vertices = tempVert1.ToArray();originMesh.normals = tempNormal1.ToArray();originMesh.triangles = tempTriangles1.ToArray();originMesh.uv = uvs1.ToArray();hitTarget.GetComponent<MeshFilter>().mesh = originMesh;Collider collider = hitTarget.GetComponent<Collider>();if (collider != null){Destroy(collider);}//hitTarget.gameObject.AddComponent<BoxCollider>();MeshCollider meshCollider = hitTarget.gameObject.AddComponent<MeshCollider>();hitTarget.gameObject.tag = TagName;hitTarget.gameObject.layer = 11;hitTarget.SetParent(generatePoint);float obj1Volume = CalculateVolumeHelper.CalculateSumVolume(hitTarget.transform.lossyScale, hitTarget.GetComponent<MeshFilter>());//>>>>>>>>>>>>>>>>>>>>>>>>>>切割出的第二个物体开始构建newMesh.vertices = tempVert2.ToArray();newMesh.normals = tempNormal2.ToArray();newMesh.triangles = tempTriangles2.ToArray();newMesh.uv = uvs2.ToArray();GameObject newobj = new GameObject();newobj.transform.position = hitTarget.position;newobj.transform.rotation = hitTarget.rotation;newobj.transform.localScale = hitTarget.localScale;newobj.AddComponent<MeshFilter>().mesh = newMesh;newobj.AddComponent<MeshRenderer>();Material mat = hitTarget.GetComponent<MeshRenderer>().material;newobj.GetComponent<MeshRenderer>().material = new Material(mat);newobj.tag = TagName;newobj.layer = 11;newobj.transform.SetParent(generatePoint);//顶点少的情况可以使用它 否则会报错超出顶点限制MeshCollider meshCollider2 = newobj.AddComponent<MeshCollider>();try{meshCollider.convex = true;meshCollider2.convex = true;}catch (Exception e){Debug.LogWarning(e.Message);}float obj2Volume = CalculateVolumeHelper.CalculateSumVolume(newobj.transform.lossyScale, newobj.GetComponent<MeshFilter>());//this.cutCallback(Mathf.Min(obj1Volume, obj2Volume));//比较两者体积,较小的一个进行添加刚体 自由落体...if (obj1Volume < obj2Volume){//hitTarget物体掉落 消失Rigidbody rigidbody1 = hitTarget.gameObject.GetOrAddComponent<Rigidbody>();rigidbody1.AddForce((hitTarget.InverseTransformDirection(cutNormalDir) * force), ForceMode.Impulse); //可去掉这个力            CutObjectDestroyBySelf cutObjectDestroyBySelf = hitTarget.gameObject.GetComponent<CutObjectDestroyBySelf>();if (!cutObjectDestroyBySelf){cutObjectDestroyBySelf = hitTarget.gameObject.AddComponent<CutObjectDestroyBySelf>();cutObjectDestroyBySelf.time = destroyTime;}cutObjectDestroyBySelf.SetMat(dissolveMat);Rigidbody newobjRigidbody = newobj.GetComponent<Rigidbody>();if (newobjRigidbody){Destroy(newobjRigidbody);}lastCutObject = newobj;}else{Rigidbody rigidbody2 = newobj.GetOrAddComponent<Rigidbody>();rigidbody2.AddForce(-newobj.transform.InverseTransformDirection(cutNormalDir) * force, ForceMode.Impulse);//可去掉这个力            CutObjectDestroyBySelf cutObjectDestroyBySelf = newobj.GetComponent<CutObjectDestroyBySelf>();if (!cutObjectDestroyBySelf){cutObjectDestroyBySelf = newobj.AddComponent<CutObjectDestroyBySelf>();cutObjectDestroyBySelf.time = destroyTime;}cutObjectDestroyBySelf.SetMat(dissolveMat);Rigidbody hitTargetRigidbody = hitTarget.gameObject.GetComponent<Rigidbody>();if (hitTargetRigidbody){Destroy(hitTargetRigidbody);}lastCutObject = hitTarget.gameObject;}//Destroy(newobj, 5f);}sw.Stop();Debug.Log($"代码块执行时间: {sw.ElapsedMilliseconds} 毫秒"); // 输出执行时间}bool IsEqualFloat(float a, float b){float num = a - b;if (num < 0.01f && num > -0.01f){return true;}return false;}bool IsEqualTwoPoint(Vector3 a, Vector3 b){if (IsEqualFloat(a.x, b.x) && IsEqualFloat(a.y, b.y) && IsEqualFloat(a.z, b.z)){return true;}return false;}//临时方法过滤异常三角面bool TempFuncFilterErrorTriangle(ref List<Vector3> vertices, ref List<int> triangles, ref List<Vector3> normals){bool isFilter = false;List<Vector3> newVertices = new List<Vector3>();List<int> newTriangles = new List<int>();List<Vector3> newNormals = new List<Vector3>();int index = 0;//剔除三角面的3个顶点位置数据全相同的三角面for (int i = 0; i < triangles.Count / 3; i++){int i0 = triangles[i * 3];int i1 = triangles[i * 3 + 1];int i2 = triangles[i * 3 + 2];Vector3 v0 = vertices[i0];Vector3 v1 = vertices[i1];Vector3 v2 = vertices[i2];if (IsEqualTwoPoint(v0, v1) || IsEqualTwoPoint(v1, v2) || IsEqualTwoPoint(v2, v0)){isFilter = true;//Debug.Log("有过滤!");}else{newVertices.Add(v0);newVertices.Add(v1);newVertices.Add(v2);newTriangles.Add(index++);newTriangles.Add(index++);newTriangles.Add(index++);newNormals.Add(normals[i0]);newNormals.Add(normals[i1]);newNormals.Add(normals[i2]);}}//if (isFilter)//{//    Debug.Log(vertices.Count + ", " + newVertices.Count + "," + triangles.Count + "," + normals.Count);//}vertices = newVertices;triangles = newTriangles;normals = newNormals;return isFilter;}//计算交点void CaculateIntersectionPoint(Vector3 v1, Vector3 v2){Vector3 localIntersectionPointPos = hitTarget.InverseTransformPoint(MathHelper.GetIntersectionPoint(cutNormalDir, hitPos, hitTarget.TransformPoint(v1), hitTarget.TransformPoint(v2)));localPos.Add(localIntersectionPointPos);allPos.Add(localIntersectionPointPos);}void ConnectPointToTriangle(int index, Vector3 p1, Vector3 p2, Vector3 normal, ref List<Vector3> tempVert, ref List<Vector3> tempNormal, ref List<int> tempTriangle, ref Dictionary<int, int> tempIndex){//可能还未添加if (!tempIndex.ContainsKey(index)){tempVert.Add(targetMesh.vertices[index]);tempNormal.Add(targetMesh.normals[index]);tempIndex.Add(index, tempVert.Count - 1);}Vector3 v = targetMesh.vertices[index];Vector3 vp1 = p1 - v;Vector3 p1p2 = p2 - p1;Vector3 p2v = v - p2;tempVert.Add(p1);int p1Index = tempVert.Count - 1;tempVert.Add(p2);int p2Index = tempVert.Count - 1;tempNormal.Add(targetMesh.normals[index]);tempNormal.Add(targetMesh.normals[index]);int vIndex = tempIndex[index];//v -> p1 -> p2if (Vector3.Dot(normal, Vector3.Cross(vp1, p1p2)) > 0){tempTriangle.Add(vIndex);tempTriangle.Add(p1Index);tempTriangle.Add(p2Index);}else{//p2 -> p1 -> vtempTriangle.Add(p2Index);tempTriangle.Add(p1Index);tempTriangle.Add(vIndex);}}void ConnectPointToTriangle(int index1, int index2, Vector3 p1, Vector3 p2, Vector3 normal, ref List<Vector3> tempVert, ref List<Vector3> tempNormal, ref List<int> tempTriangle, ref Dictionary<int, int> tempIndex, int index3){//可能还未添加if (!tempIndex.ContainsKey(index1)){tempVert.Add(targetMesh.vertices[index1]);tempNormal.Add(targetMesh.normals[index1]);tempIndex.Add(index1, tempVert.Count - 1);}if (!tempIndex.ContainsKey(index2)){tempVert.Add(targetMesh.vertices[index2]);tempNormal.Add(targetMesh.normals[index2]);tempIndex.Add(index2, tempVert.Count - 1);}//1.切割点放入tempVert tempNormaltempVert.Add(p1);int p1Index = tempVert.Count - 1;tempVert.Add(p2);int p2Index = tempVert.Count - 1;tempNormal.Add(targetMesh.normals[index1]);tempNormal.Add(targetMesh.normals[index2]);Vector3 v1 = targetMesh.vertices[index1];Vector3 v2 = targetMesh.vertices[index2];//试错方式进行连接Vector3 v1v2 = v2 - v1;Vector3 v2p1 = p1 - v2;Vector3 p1v1 = v1 - p1;//说明是正确的顺时针if (Vector3.Dot(normal, Vector3.Cross(v1v2, v2p1)) > 0){//获取到真正的索引int v1Index = tempIndex[index1];int v2Index = tempIndex[index2];//v1->v2->p1tempTriangle.Add(v1Index);tempTriangle.Add(v2Index);tempTriangle.Add(p1Index);if (v1Index == v2Index || v1Index == p1Index || v2Index == p1Index){Debug.LogError("if(v1Index == v2Index || v1Index == p1Index || v2Index == p1Index) 222");}//Vector3 //1. v2 -> p2, p2->p1 , p1 -> v2  //证明不与另一个三角面相交if (!MathHelper.IsIntectsect(v2, p2, v1, v2) && !MathHelper.IsIntectsect(p2, p1, v1, v2) && !MathHelper.IsIntectsect(p1, v2, v1, v2)&& !MathHelper.IsIntectsect(v2, p2, v2, p1) && !MathHelper.IsIntectsect(p2, p1, v2, p1) && !MathHelper.IsIntectsect(p1, v2, v2, p1)&& !MathHelper.IsIntectsect(v2, p2, p1, v1) && !MathHelper.IsIntectsect(p2, p1, p1, v1) && !MathHelper.IsIntectsect(p1, v2, p1, v1)){Vector3 _v2p2 = p2 - v2;Vector3 _p2p1 = p1 - p2;Vector3 _p1v2 = v2 - p1;//(v2 -> p2 -> p1)if (Vector3.Dot(normal, Vector3.Cross(_v2p2, _p2p1)) > 0){tempTriangle.Add(v2Index);tempTriangle.Add(p2Index);tempTriangle.Add(p1Index);if (v2Index == p2Index || p2Index == p1Index || p1Index == v2Index){Debug.LogError("if (v2Index == p2Index || p2Index == p1Index || p1Index == v2Index) 1111");}}else{//p1 -> p2 -> v2 (反转)tempTriangle.Add(p1Index);tempTriangle.Add(p2Index);tempTriangle.Add(v2Index);if (p1Index == p2Index || p2Index == v2Index || v2Index == p1Index){Debug.LogError(" if (p1Index == p2Index || p2Index == v2Index || v2Index == p1Index) 8888");}}}else if (!MathHelper.IsIntectsect(v1, p2, v1, v2) && !MathHelper.IsIntectsect(p2, p1, v1, v2) && !MathHelper.IsIntectsect(p1, v1, v1, v2)&& !MathHelper.IsIntectsect(v1, p2, v2, p1) && !MathHelper.IsIntectsect(p2, p1, v2, p1) && !MathHelper.IsIntectsect(p1, v1, v2, p1)&& !MathHelper.IsIntectsect(v1, p2, p1, v1) && !MathHelper.IsIntectsect(p2, p1, p1, v1) && !MathHelper.IsIntectsect(p1, v1, p1, v1)){//2. v1->p2, p2->p1, p1->v1Vector3 _v1p2 = p2 - v1;Vector3 _p2p1 = p1 - p2;Vector3 _p1v1 = v1 - p1;//(v1 -> p2 -> p1)if (Vector3.Dot(normal, Vector3.Cross(_v1p2, _p2p1)) > 0){tempTriangle.Add(v1Index);tempTriangle.Add(p2Index);tempTriangle.Add(p1Index);if (v1Index == p2Index || p2Index == p1Index || p1Index == v1Index){Debug.LogError(" if (p1Index == p2Index || p2Index == v2Index || v2Index == p1Index) 8888");}}else{//p1 -> p2 -> v1 (反转)tempTriangle.Add(p1Index);tempTriangle.Add(p2Index);tempTriangle.Add(v1Index);if (p1Index == p2Index || p2Index == v1Index || v1Index == p1Index){Debug.LogError("if (p1Index == p2Index || p2Index == v1Index || v1Index == p1Index) 66666");}}}else{//发现是p1,p2是相同的...v1,v2非常相近的情况 没有很大影响 暂时忽略Debug.Log(v1);Debug.Log(v2);Debug.Log(p1 + "\n");Debug.Log(v2);Debug.Log(p2);Debug.Log(p1 + "\n");Debug.Log(v1);Debug.Log(p2);Debug.Log(p1 + "\n");Debug.LogWarning("绝对不会出现的....但是出现过,具体原因未知"); //?? 一般切割2D的平面会出现这种情况,但实际每有很大影响 }}else{//Debug.DrawLine(v1, v2, Color.blue);//Debug.DrawLine(p1, p1, Color.green);//Debug.DrawLine(v2, p1, Color.red);//出现了v1和v2相同情况,p1和p2也相同..然后就这样了//确实是会存在顶点相同的情况这种情况无法构成面应该忽略!if (v1 == p1 || v2 == p1 || v1 == v2){//正常现象 或者你可以控制。。交点确实是有可能存在和v1,v2相同的情况...//Debug.LogError(">>>>111//正常现象 或者你可以控制。。交点确实是有可能存在和v1,v2相同的情况...");}else{//当点之间非常相近时会出现这种情况,暂时忽略。。 或者是API的问题//Debug.Log(index1);//Debug.Log(index2);//Debug.Log(index3);//Debug.Log("v1:" + v1 + "," + (v1 == p1));//Debug.Log("v2:" + v2 + "," + (v2 == p1));//Debug.Log("v3:" + targetMesh.vertices[index3]);//Debug.Log("p1:" + p1);//Debug.Log("p2:" + p2);//Debug.Log("Cross:" + Vector3.Dot(normal, Vector3.Cross(v1v2, v2p1)));p1 -> v2 -> v1 相反//Debug.LogWarning("从逻辑上看,不可能进入! 但是进去了 不知道为什么...");  //????}}}void FillCutSurface(){//Debug.Log("allPos.Count = " + allPos.Count);if (allPos.Count <= 0){//Debug.LogError("切割面的顶点全都没有..."); //?????? 算正常吧???....return;}Vector3 center = (allPos[0] + allPos[allPos.Count / 2]) * 0.5f;Vector3 normal = hitTarget.InverseTransformDirection(cutNormalDir);tempVert1.Add(center);int center1Index = tempVert1.Count - 1;tempNormal1.Add(-normal);tempVert2.Add(center);int center2Index = tempVert2.Count - 1;tempNormal2.Add(normal);for (int i = 0; i < allPos.Count; i += 2){//排除相同顶点的情况,只要有三角面2点位置相同,那就无法构成三角面 忽略...(不然会出问题)if (allPos[i] == allPos[i + 1] || allPos[i] == center || center == allPos[i + 1]){continue;}tempVert1.Add(allPos[i]);int tempVert1AllPos1Index = tempVert1.Count - 1;tempVert1.Add(allPos[i + 1]);int tempVert1AllPos2Index = tempVert1.Count - 1;tempNormal1.Add(-normal);tempNormal1.Add(-normal);Vector3 a1 = allPos[i] - center;//Vector3 a2 = allPos[i + 1] - allPos[i];Vector3 a2 = allPos[i + 1] - center;Vector3 crossA1A2 = Vector3.Cross(a1, a2);if (Vector3.Dot(-normal, crossA1A2) >= 0){tempTriangles1.Add(center1Index);tempTriangles1.Add(tempVert1AllPos1Index);tempTriangles1.Add(tempVert1AllPos2Index);if (center1Index == tempVert1AllPos1Index || center1Index == tempVert1AllPos2Index || tempVert1AllPos1Index == tempVert1AllPos2Index){Debug.Log(center + "," + allPos[i] + "," + allPos[i + 1]+ "\n " + tempVert1.LastIndexOf(center) + "," + tempVert1AllPos1Index + "," + tempVert1AllPos2Index + "," + allPos.Count);Debug.LogError("tempVert1.LastIndexOf(center) == tempVert1AllPos1Index || tempVert1.LastIndexOf(center) == tempVert1AllPos2Index || tempVert1AllPos1Index == tempVert1AllPos2Index 9999999999");}}else{tempTriangles1.Add(tempVert1AllPos2Index);tempTriangles1.Add(tempVert1AllPos1Index);tempTriangles1.Add(center1Index);if (center1Index == tempVert1AllPos1Index || center1Index == tempVert1AllPos2Index || tempVert1AllPos1Index == tempVert1AllPos2Index){Debug.Log(center + "," + allPos[i] + "," + allPos[i + 1] + "\n" +tempVert1.LastIndexOf(center) + "," + tempVert1AllPos1Index + "," + tempVert1AllPos2Index + "," + allPos.Count);Debug.LogError("if (tempVert1.LastIndexOf(center) == tempVert1AllPos1Index || tempVert1.LastIndexOf(center) == tempVert1AllPos2Index || tempVert1AllPos1Index == tempVert1AllPos2Index) -----------");}}tempVert2.Add(allPos[i]);int tempV1Index = tempVert2.Count - 1;tempVert2.Add(allPos[i + 1]);int tempV2Index = tempVert2.Count - 1;tempNormal2.Add(normal);tempNormal2.Add(normal);if (Vector3.Dot(normal, crossA1A2) >= 0){tempTriangles2.Add(center2Index);tempTriangles2.Add(tempV1Index);tempTriangles2.Add(tempV2Index);if (center2Index == tempV1Index || center2Index == tempV2Index || tempV1Index == tempV2Index){Debug.Log(center + "," + allPos[i] + "," + allPos[i + 1] + "\n" +tempVert2.LastIndexOf(center) + "," + tempV1Index + "," + tempV2Index + "," + allPos.Count);Debug.LogError("tempVert2.LastIndexOf(center) == tempV1Index || tempVert2.LastIndexOf(center) == tempV2Index || tempV1Index == tempV2Index /");}}else{tempTriangles2.Add(tempV2Index);tempTriangles2.Add(tempV1Index);tempTriangles2.Add(center2Index);if (center2Index == tempV1Index || center2Index == tempV2Index || tempV1Index == tempV2Index){Debug.Log(center + "," + allPos[i] + "," + allPos[i + 1] + "\n" +tempVert2.LastIndexOf(center) + "," + tempV1Index + "," + tempV2Index + "," + allPos.Count);Debug.LogError("tempVert2.LastIndexOf(center) == tempV1Index || tempVert2.LastIndexOf(center) == tempV2Index || tempV1Index == tempV2Index qqqqqqq");}}}}/// <summary>/// 计算Box的UV方法 /// </summary>void CalculateUV(Vector3 size, List<Vector3> vertices, List<int> triangles, List<Vector3> normals, ref List<Vector2> uvs){uvs = new List<Vector2>();for (int i = 0; i < vertices.Count; i++){uvs.Add(new Vector2(0, 0));}for (int i = 0; i < triangles.Count / 3; i++){int i0 = triangles[i * 3];int i1 = triangles[i * 3 + 1];int i2 = triangles[i * 3 + 2];//Vector3 v0 = vertices[i0] - center + size / 2f;//Vector3 v1 = vertices[i1] - center + size / 2f;//Vector3 v2 = vertices[i2] - center + size / 2f;Vector3 v0 = vertices[i0];Vector3 v1 = vertices[i1];Vector3 v2 = vertices[i2];string str = string.Format("原始数据:({0},{1},{2}) index:({3},{4},{5})", v0.ToString(), v1.ToString(), v2.ToString(), i0, i1, i2);// 除以size.x,y,z是为了缩小范围到[0,1] UV的范围v0 = new Vector3(v0.x / size.x, v0.y / size.y, v0.z / size.z);v1 = new Vector3(v1.x / size.x, v1.y / size.y, v1.z / size.z);v2 = new Vector3(v2.x / size.x, v2.y / size.y, v2.z / size.z);//Vector3 a = v0 - v1;//Vector3 b = v2 - v1; Vector3 a = v1 - v0;Vector3 b = v2 - v1;//我老感觉这法线计算错了...v0->v1-v2             Vector3 dir = normals[i0]; //Vector3.Cross(a, b);  //改用顶点法线作为法线float x = Mathf.Abs(Vector3.Dot(dir, Vector3.right));float y = Mathf.Abs(Vector3.Dot(dir, Vector3.up));float z = Mathf.Abs(Vector3.Dot(dir, Vector3.forward));//法线倾向于X轴,用Z作为X,Y作为Yif (x > y && x > z){uvs[i0] = new Vector2(v0.z, v0.y);uvs[i1] = new Vector2(v1.z, v1.y);uvs[i2] = new Vector2(v2.z, v2.y);}else if (y > z && y > x){//法线倾向于Y轴,用X作为X,Z作为Yuvs[i0] = new Vector2(v0.x, v0.z);uvs[i1] = new Vector2(v1.x, v1.z);uvs[i2] = new Vector2(v2.x, v2.z);}else if (z > x && z > y){//法线倾向于Z轴,用X作为X,Y作为Yuvs[i0] = new Vector2(v0.x, v0.y);uvs[i1] = new Vector2(v1.x, v1.y);uvs[i2] = new Vector2(v2.x, v2.y);}else{//防止出现UV不正常情况uvs[i0] = new Vector2(0, 0);uvs[i1] = new Vector2(1, 1);uvs[i2] = new Vector2(0, 0);//Debug.LogWarning("UV出问题啦..." + x + ", " + y + "," + z + "\n"//    + v0 + ", " + v1 + "," + v2 + " \n"//    + a + ", " + b + "\n"//    + dir + "\n"//    + str);//虽然已经处理了异常三角面,但仍然会出现(x,y,z)全为0的情况...先放任不管看看效果...}}}public void ClearCutInfos(){cutInfos?.Clear();}public void DestroyLastCutObject(){if (lastCutObject != null){Destroy(lastCutObject);}}public void SetLastCutObject(GameObject obj){lastCutObject = obj;}public void AddCutCallback(Action<float> action){cutCallback = action;}
}
using System.Collections;
using System.Collections.Generic;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;[BurstCompile]
public struct CutJob : IJob
{public int targetMeshTriangles_Count;public NativeArray<Vector3> targetMeshVert;public NativeArray<Vector3> targetMeshNormal;public NativeArray<int> targetMeshTriangles;public Matrix4x4 hitTarget_o2w;public Matrix4x4 hitTarget_w2o;public Vector3 hitTarget_LocalScale;int localPos_Count;int allPos_Count;public NativeArray<Vector3> localPos;public NativeArray<Vector3> allPos;public int tempVert1_Count;public int tempNormal1_Count;public int tempTriangles1_Count;public int uvs1_Count;public NativeArray<Vector3> tempVert1;public NativeArray<Vector3> tempNormal1;public NativeArray<int> tempTriangles1;public NativeHashMap<int, int> tempIndex1;public NativeArray<Vector2> uvs1;public NativeArray<int> temp1CountArray;public int tempVert2_Count;public int tempNormal2_Count;public int tempTriangles2_Count;public int uvs2_Count;public NativeArray<Vector3> tempVert2;public NativeArray<Vector3> tempNormal2;public NativeArray<int> tempTriangles2;public NativeHashMap<int, int> tempIndex2;public NativeArray<Vector2> uvs2;public NativeArray<int> temp2CountArray;public Vector3 hitPos;public Vector3 dir;public Vector3 cutVerticalDir;public Vector3 cutNormalDir;public void Execute(){Cutting();}#region 切割void Cutting(){//tempVert1.Clear();//tempNormal1.Clear();//tempTriangles1.Clear();//tempIndex1.Clear();//uvs1.Clear();//tempVert2.Clear();//tempNormal2.Clear();//tempTriangles2.Clear();//tempIndex2.Clear();//uvs2.Clear();//allPos.Clear();for (int i = 0; i < targetMeshTriangles.Length; i += 3){int index1 = targetMeshTriangles[i];int index2 = targetMeshTriangles[i + 1];int index3 = targetMeshTriangles[i + 2];Vector3 vertex1 = targetMeshVert[index1];Vector3 vertex2 = targetMeshVert[index2];Vector3 vertex3 = targetMeshVert[index3];float vert1 = Vector3.Dot(cutNormalDir, (hitTarget_o2w.MultiplyPoint(vertex1) - hitPos).normalized);float vert2 = Vector3.Dot(cutNormalDir, (hitTarget_o2w.MultiplyPoint(vertex2) - hitPos).normalized);float vert3 = Vector3.Dot(cutNormalDir, (hitTarget_o2w.MultiplyPoint(vertex3) - hitPos).normalized);if (vert1 >= 0 && vert2 >= 0 && vert3 >= 0){//同面if (!tempIndex1.ContainsKey(index1)) //过滤相同顶点{tempVert1[tempVert1_Count++] = vertex1;tempNormal1[tempNormal1_Count++] = targetMeshNormal[index1];tempIndex1.Add(index1, tempVert1_Count - 1); //旧索引为key,新索引为value}if (!tempIndex1.ContainsKey(index2)) //过滤相同顶点{tempVert1[tempVert1_Count++] = vertex2;tempNormal1[tempNormal1_Count++] = targetMeshNormal[index2];tempIndex1.Add(index2, tempVert1_Count - 1); //旧索引为key,新索引为value}if (!tempIndex1.ContainsKey(index3)) //过滤相同顶点{tempVert1[tempVert1_Count++] = vertex3;tempNormal1[tempNormal1_Count++] = targetMeshNormal[index3];tempIndex1.Add(index3, tempVert1_Count - 1); //旧索引为key,新索引为value}tempTriangles1[tempTriangles1_Count++] = tempIndex1[index1]; //使用旧索引index1 获取对应的新索引tempTriangles1[tempTriangles1_Count++] = tempIndex1[index2]; //使用旧索引index2 获取对应的新索引tempTriangles1[tempTriangles1_Count++] = tempIndex1[index3]; //使用旧索引index3 获取对应的新索引if (tempIndex1[index1] == tempIndex1[index2] || tempIndex1[index1] == tempIndex1[index3] || tempIndex1[index2] == tempIndex1[index3]){//Debug.LogError("[1]問題");}}else if (vert1 <= 0 && vert2 <= 0 && vert3 <= 0){//另一个同面                if (!tempIndex2.ContainsKey(index1)) //过滤相同顶点{tempVert2[tempVert2_Count++] = (vertex1);tempNormal2[tempNormal2_Count++] = (targetMeshNormal[index1]);tempIndex2.Add(index1, tempVert2_Count - 1); //旧索引为key,新索引为value}if (!tempIndex2.ContainsKey(index2)) //过滤相同顶点{tempVert2[tempVert2_Count++] = (vertex2);tempNormal2[tempNormal2_Count++] = (targetMeshNormal[index2]);tempIndex2.Add(index2, tempVert2_Count - 1); //旧索引为key,新索引为value}if (!tempIndex2.ContainsKey(index3)) //过滤相同顶点{tempVert2[tempVert2_Count++] = (vertex3);tempNormal2[tempNormal2_Count++] = (targetMeshNormal[index3]);tempIndex2.Add(index3, tempVert2_Count - 1); //旧索引为key,新索引为value}tempTriangles2[tempTriangles2_Count++] = (tempIndex2[index1]); //使用旧索引index1 获取对应的新索引tempTriangles2[tempTriangles2_Count++] = (tempIndex2[index2]); //使用旧索引index2 获取对应的新索引tempTriangles2[tempTriangles2_Count++] = (tempIndex2[index3]); //使用旧索引index3 获取对应的新索引if (tempIndex2[index1] == tempIndex2[index2] || tempIndex2[index1] == tempIndex2[index3] || tempIndex2[index2] == tempIndex2[index3]){//Debug.LogError("[2]問題");}}else{//continue;localPos_Count = 0;//不同面情况 (PS:不存在3点不同面情况)bool isV1V2Sample = (vert1 > 0 && vert2 > 0 || vert1 < 0 && vert2 < 0);bool isV2V3Sample = (vert2 > 0 && vert3 > 0 || vert2 < 0 && vert3 < 0);bool isV3V1Sample = (vert3 > 0 && vert1 > 0 || vert3 < 0 && vert1 < 0);Vector3 normal = Vector3.Cross(vertex2 - vertex1, vertex3 - vertex2);//1. index1 和 index2 顶点不同面if (!(isV1V2Sample)){CaculateIntersectionPoint(vertex1, vertex2);}//2. index2 和 index3 顶点不同面if (!(isV2V3Sample)){CaculateIntersectionPoint(vertex2, vertex3);}//3. index3 和 index1 顶点不同面if (!(isV3V1Sample)){CaculateIntersectionPoint(vertex3, vertex1);}//此时localPos保存2个交点, allPos是保存所有交点的if (isV1V2Sample){if (vert1 > 0 && vert2 > 0){if (index1 == index2){//Debug.LogError(">>>>>>>>>>>>>>>>>>>>>1 : " + index1);}ConnectPointToTriangle(index1, index2, localPos[0], localPos[1], normal, ref tempVert1, ref tempNormal1, ref tempTriangles1, ref tempIndex1, index3, ref tempVert1_Count, ref tempNormal1_Count, ref tempTriangles1_Count);ConnectPointToTriangle(index3, localPos[0], localPos[1], normal, ref tempVert2, ref tempNormal2, ref tempTriangles2, ref tempIndex2, ref tempVert2_Count, ref tempNormal2_Count, ref tempTriangles2_Count);}else{if (index1 == index2){//Debug.LogError(">>>>>>>>>>>>>>>>>>>>>2 : " + index1);}ConnectPointToTriangle(index1, index2, localPos[0], localPos[1], normal, ref tempVert2, ref tempNormal2, ref tempTriangles2, ref tempIndex2, index3, ref tempVert2_Count, ref tempNormal2_Count, ref tempTriangles2_Count);ConnectPointToTriangle(index3, localPos[0], localPos[1], normal, ref tempVert1, ref tempNormal1, ref tempTriangles1, ref tempIndex1, ref tempVert1_Count, ref tempNormal1_Count, ref tempTriangles1_Count);}}if (isV2V3Sample){if (vert2 > 0 && vert3 > 0){if (index2 == index3){//Debug.LogError(">>>>>>>>>>>>>>>>>>>>>3 : " + index2);}ConnectPointToTriangle(index2, index3, localPos[0], localPos[1], normal, ref tempVert1, ref tempNormal1, ref tempTriangles1, ref tempIndex1, index1, ref tempVert1_Count, ref tempNormal1_Count, ref tempTriangles1_Count);ConnectPointToTriangle(index1, localPos[0], localPos[1], normal, ref tempVert2, ref tempNormal2, ref tempTriangles2, ref tempIndex2, ref tempVert2_Count, ref tempNormal2_Count, ref tempTriangles2_Count);}else{if (index2 == index3){//Debug.LogError(">>>>>>>>>>>>>>>>>>>>>4 : " + index2);}ConnectPointToTriangle(index2, index3, localPos[0], localPos[1], normal, ref tempVert2, ref tempNormal2, ref tempTriangles2, ref tempIndex2, index1, ref tempVert2_Count, ref tempNormal2_Count, ref tempTriangles2_Count);ConnectPointToTriangle(index1, localPos[0], localPos[1], normal, ref tempVert1, ref tempNormal1, ref tempTriangles1, ref tempIndex1, ref tempVert1_Count, ref tempNormal1_Count, ref tempTriangles1_Count);}}if (isV3V1Sample){if (vert3 > 0 && vert1 > 0){if (index3 == index1){//Debug.LogError(">>>>>>>>>>>>>>>>>>>>>5 : " + index3);}ConnectPointToTriangle(index3, index1, localPos[0], localPos[1], normal, ref tempVert1, ref tempNormal1, ref tempTriangles1, ref tempIndex1, index2, ref tempVert1_Count, ref tempNormal1_Count, ref tempTriangles1_Count);ConnectPointToTriangle(index2, localPos[0], localPos[1], normal, ref tempVert2, ref tempNormal2, ref tempTriangles2, ref tempIndex2, ref tempVert2_Count, ref tempNormal2_Count, ref tempTriangles2_Count);}else{if (index3 == index1){//Debug.LogError(">>>>>>>>>>>>>>>>>>>>>6 : " + index3);}ConnectPointToTriangle(index3, index1, localPos[0], localPos[1], normal, ref tempVert2, ref tempNormal2, ref tempTriangles2, ref tempIndex2, index2, ref tempVert2_Count, ref tempNormal2_Count, ref tempTriangles2_Count);ConnectPointToTriangle(index2, localPos[0], localPos[1], normal, ref tempVert1, ref tempNormal1, ref tempTriangles1, ref tempIndex1, ref tempVert1_Count, ref tempNormal1_Count, ref tempTriangles1_Count);}}}}//补全截面FillCutSurface();//注释下面两行代码,UV纹理全没但报错没了(目前UV组成有问题可能会导致模型某一面完全透明)//BUG已查明:上面代码生成新2个网格数据 会存在三角面的3个顶点位置数据一样,导致UV无法正常出现,因此此时简单地做个后处理 剔除这些异常三角面 ...      //bool isFilter1 = TempFuncFilterErrorTriangle(ref tempVert1, ref tempTriangles1, ref tempNormal1); //依然有问题 待修复...//bool isFilter2 = TempFuncFilterErrorTriangle(ref tempVert2, ref tempTriangles2, ref tempNormal2);CalculateUV(hitTarget_LocalScale, ref tempVert1, ref tempTriangles1, ref tempNormal1, ref uvs1, ref tempVert1_Count, ref tempTriangles1_Count, ref tempNormal1_Count, ref uvs1_Count);CalculateUV(hitTarget_LocalScale, ref tempVert2, ref tempTriangles2, ref tempNormal2, ref uvs2, ref tempVert2_Count, ref tempTriangles2_Count, ref tempNormal2_Count, ref uvs2_Count);temp1CountArray[0] = tempVert1_Count;temp1CountArray[1] = tempNormal1_Count;temp1CountArray[2] = tempTriangles1_Count;temp1CountArray[3] = uvs1_Count;temp2CountArray[0] = tempVert2_Count;temp2CountArray[1] = tempNormal2_Count;temp2CountArray[2] = tempTriangles2_Count;temp2CountArray[3] = uvs2_Count;}bool IsEqualFloat(float a, float b){float num = a - b;if (num < 0.01f && num > -0.01f){return true;}return false;}//计算交点void CaculateIntersectionPoint(Vector3 v1, Vector3 v2){Vector3 localIntersectionPointPos = hitTarget_w2o.MultiplyPoint(MathHelper.GetIntersectionPoint(cutNormalDir, hitPos, hitTarget_o2w.MultiplyPoint(v1), hitTarget_o2w.MultiplyPoint(v2)));localPos[localPos_Count++] = (localIntersectionPointPos);allPos[allPos_Count++] = (localIntersectionPointPos);}void ConnectPointToTriangle(int index, Vector3 p1, Vector3 p2, Vector3 normal, ref NativeArray<Vector3> tempVert, ref NativeArray<Vector3> tempNormal, ref NativeArray<int> tempTriangle, ref NativeHashMap<int, int> tempIndex, ref int tempVertCount, ref int tempNormalCount, ref int tempTriangleCount){//可能还未添加if (!tempIndex.ContainsKey(index)){tempVert[tempVertCount++] = (targetMeshVert[index]);tempNormal[tempNormalCount++] = (targetMeshNormal[index]);tempIndex.Add(index, tempVertCount - 1);}Vector3 v = targetMeshVert[index];Vector3 vp1 = p1 - v;Vector3 p1p2 = p2 - p1;Vector3 p2v = v - p2;tempVert[tempVertCount++] = (p1);int p1Index = tempVertCount - 1;tempVert[tempVertCount++] = (p2);int p2Index = tempVertCount - 1;tempNormal[tempNormalCount++] = (targetMeshNormal[index]);tempNormal[tempNormalCount++] = (targetMeshNormal[index]);int vIndex = tempIndex[index];//v -> p1 -> p2if (Vector3.Dot(normal, Vector3.Cross(vp1, p1p2)) > 0){tempTriangle[tempTriangleCount++] = (vIndex);tempTriangle[tempTriangleCount++] = (p1Index);tempTriangle[tempTriangleCount++] = (p2Index);}else{//p2 -> p1 -> vtempTriangle[tempTriangleCount++] = (p2Index);tempTriangle[tempTriangleCount++] = (p1Index);tempTriangle[tempTriangleCount++] = (vIndex);}}void ConnectPointToTriangle(int index1, int index2, Vector3 p1, Vector3 p2, Vector3 normal, ref NativeArray<Vector3> tempVert, ref NativeArray<Vector3> tempNormal, ref NativeArray<int> tempTriangle, ref NativeHashMap<int, int> tempIndex, int index3, ref int tempVertCount, ref int tempNormalCount, ref int tempTriangleCount){//可能还未添加if (!tempIndex.ContainsKey(index1)){tempVert[tempVertCount++] = (targetMeshVert[index1]);tempNormal[tempNormalCount++] = (targetMeshNormal[index1]);tempIndex.Add(index1, tempVertCount - 1);}if (!tempIndex.ContainsKey(index2)){tempVert[tempVertCount++] = (targetMeshVert[index2]);tempNormal[tempNormalCount++] = (targetMeshNormal[index2]);tempIndex.Add(index2, tempVertCount - 1);}//1.切割点放入tempVert tempNormaltempVert[tempVertCount++] = (p1);int p1Index = tempVertCount - 1;tempVert[tempVertCount++] = (p2);int p2Index = tempVertCount - 1;tempNormal[tempNormalCount++] = (targetMeshNormal[index1]);tempNormal[tempNormalCount++] = (targetMeshNormal[index2]);Vector3 v1 = targetMeshVert[index1];Vector3 v2 = targetMeshVert[index2];//试错方式进行连接Vector3 v1v2 = v2 - v1;Vector3 v2p1 = p1 - v2;Vector3 p1v1 = v1 - p1;//说明是正确的顺时针if (Vector3.Dot(normal, Vector3.Cross(v1v2, v2p1)) > 0){//获取到真正的索引int v1Index = tempIndex[index1];int v2Index = tempIndex[index2];//v1->v2->p1tempTriangle[tempTriangleCount++] = (v1Index);tempTriangle[tempTriangleCount++] = (v2Index);tempTriangle[tempTriangleCount++] = (p1Index);if (v1Index == v2Index || v1Index == p1Index || v2Index == p1Index){//Debug.LogError("if(v1Index == v2Index || v1Index == p1Index || v2Index == p1Index) 222");}//Vector3 //1. v2 -> p2, p2->p1 , p1 -> v2  //证明不与另一个三角面相交if (!MathHelper.IsIntectsect(v2, p2, v1, v2) && !MathHelper.IsIntectsect(p2, p1, v1, v2) && !MathHelper.IsIntectsect(p1, v2, v1, v2)&& !MathHelper.IsIntectsect(v2, p2, v2, p1) && !MathHelper.IsIntectsect(p2, p1, v2, p1) && !MathHelper.IsIntectsect(p1, v2, v2, p1)&& !MathHelper.IsIntectsect(v2, p2, p1, v1) && !MathHelper.IsIntectsect(p2, p1, p1, v1) && !MathHelper.IsIntectsect(p1, v2, p1, v1)){Vector3 _v2p2 = p2 - v2;Vector3 _p2p1 = p1 - p2;Vector3 _p1v2 = v2 - p1;//(v2 -> p2 -> p1)if (Vector3.Dot(normal, Vector3.Cross(_v2p2, _p2p1)) > 0){tempTriangle[tempTriangleCount++] = (v2Index);tempTriangle[tempTriangleCount++] = (p2Index);tempTriangle[tempTriangleCount++] = (p1Index);if (v2Index == p2Index || p2Index == p1Index || p1Index == v2Index){//Debug.LogError("if (v2Index == p2Index || p2Index == p1Index || p1Index == v2Index) 1111");}}else{//p1 -> p2 -> v2 (反转)tempTriangle[tempTriangleCount++] = (p1Index);tempTriangle[tempTriangleCount++] = (p2Index);tempTriangle[tempTriangleCount++] = (v2Index);if (p1Index == p2Index || p2Index == v2Index || v2Index == p1Index){//Debug.LogError(" if (p1Index == p2Index || p2Index == v2Index || v2Index == p1Index) 8888");}}}else if (!MathHelper.IsIntectsect(v1, p2, v1, v2) && !MathHelper.IsIntectsect(p2, p1, v1, v2) && !MathHelper.IsIntectsect(p1, v1, v1, v2)&& !MathHelper.IsIntectsect(v1, p2, v2, p1) && !MathHelper.IsIntectsect(p2, p1, v2, p1) && !MathHelper.IsIntectsect(p1, v1, v2, p1)&& !MathHelper.IsIntectsect(v1, p2, p1, v1) && !MathHelper.IsIntectsect(p2, p1, p1, v1) && !MathHelper.IsIntectsect(p1, v1, p1, v1)){//2. v1->p2, p2->p1, p1->v1Vector3 _v1p2 = p2 - v1;Vector3 _p2p1 = p1 - p2;Vector3 _p1v1 = v1 - p1;//(v1 -> p2 -> p1)if (Vector3.Dot(normal, Vector3.Cross(_v1p2, _p2p1)) > 0){tempTriangle[tempTriangleCount++] = (v1Index);tempTriangle[tempTriangleCount++] = (p2Index);tempTriangle[tempTriangleCount++] = (p1Index);if (v1Index == p2Index || p2Index == p1Index || p1Index == v1Index){//Debug.LogError(" if (p1Index == p2Index || p2Index == v2Index || v2Index == p1Index) 8888");}}else{//p1 -> p2 -> v1 (反转)tempTriangle[tempTriangleCount++] = (p1Index);tempTriangle[tempTriangleCount++] = (p2Index);tempTriangle[tempTriangleCount++] = (v1Index);if (p1Index == p2Index || p2Index == v1Index || v1Index == p1Index){//Debug.LogError("if (p1Index == p2Index || p2Index == v1Index || v1Index == p1Index) 66666");}}}else{//发现是p1,p2是相同的...v1,v2非常相近的情况 没有很大影响 暂时忽略//Debug.Log(v1);//Debug.Log(v2);//Debug.Log(p1 + "\n");//Debug.Log(v2);//Debug.Log(p2);//Debug.Log(p1 + "\n");//Debug.Log(v1);//Debug.Log(p2);//Debug.Log(p1 + "\n");//Debug.LogWarning("绝对不会出现的....但是出现过,具体原因未知"); //?? 一般切割2D的平面会出现这种情况,但实际每有很大影响 }}else{//Debug.DrawLine(v1, v2, Color.blue);//Debug.DrawLine(p1, p1, Color.green);//Debug.DrawLine(v2, p1, Color.red);//出现了v1和v2相同情况,p1和p2也相同..然后就这样了//确实是会存在顶点相同的情况这种情况无法构成面应该忽略!if (v1 == p1 || v2 == p1 || v1 == v2){//正常现象 或者你可以控制。。交点确实是有可能存在和v1,v2相同的情况...//Debug.LogError(">>>>111//正常现象 或者你可以控制。。交点确实是有可能存在和v1,v2相同的情况...");}else{//当点之间非常相近时会出现这种情况,暂时忽略。。 或者是API的问题//Debug.Log(index1);//Debug.Log(index2);//Debug.Log(index3);//Debug.Log("v1:" + v1 + "," + (v1 == p1));//Debug.Log("v2:" + v2 + "," + (v2 == p1));//Debug.Log("v3:" + targetMeshVert[index3]);//Debug.Log("p1:" + p1);//Debug.Log("p2:" + p2);//Debug.Log("Cross:" + Vector3.Dot(normal, Vector3.Cross(v1v2, v2p1)));p1 -> v2 -> v1 相反//Debug.LogWarning("从逻辑上看,不可能进入! 但是进去了 不知道为什么...");  //????}}}void FillCutSurface(){//Debug.Log("allPos_Count = " + allPos_Count);if (allPos_Count <= 0){//Debug.LogError("切割面的顶点全都没有..."); //?????? 算正常吧???....return;}Vector3 center = (allPos[0] + allPos[allPos_Count / 2]) * 0.5f;Vector3 normal = hitTarget_w2o.MultiplyVector(cutNormalDir); // hitTarget.InverseTransformDirection(cutNormalDir);tempVert1[tempVert1_Count++] = (center);int center1Index = tempVert1_Count - 1;tempNormal1[tempNormal1_Count++] = (-normal);tempVert2[tempVert2_Count++] = (center);int center2Index = tempVert2_Count - 1;tempNormal2[tempNormal2_Count++] = (normal);for (int i = 0; i < allPos_Count; i += 2){//排除相同顶点的情况,只要有三角面2点位置相同,那就无法构成三角面 忽略...(不然会出问题)if (allPos[i] == allPos[i + 1] || allPos[i] == center || center == allPos[i + 1]){continue;}tempVert1[tempVert1_Count++] = (allPos[i]);int tempVert1AllPos1Index = tempVert1_Count - 1;tempVert1[tempVert1_Count++] = (allPos[i + 1]);int tempVert1AllPos2Index = tempVert1_Count - 1;tempNormal1[tempNormal1_Count++] = (-normal);tempNormal1[tempNormal1_Count++] = (-normal);Vector3 a1 = allPos[i] - center;//Vector3 a2 = allPos[i + 1] - allPos[i];Vector3 a2 = allPos[i + 1] - center;Vector3 crossA1A2 = Vector3.Cross(a1, a2);if (Vector3.Dot(-normal, crossA1A2) >= 0){tempTriangles1[tempTriangles1_Count++] = (center1Index);tempTriangles1[tempTriangles1_Count++] = (tempVert1AllPos1Index);tempTriangles1[tempTriangles1_Count++] = (tempVert1AllPos2Index);if (center1Index == tempVert1AllPos1Index || center1Index == tempVert1AllPos2Index || tempVert1AllPos1Index == tempVert1AllPos2Index){//Debug.Log(//     center + "," + allPos[i] + "," + allPos[i + 1]//     + "\n " + tempVert1.IndexOf(center) + "," + tempVert1AllPos1Index + "," + tempVert1AllPos2Index + "," + allPos_Count);//Debug.LogError("tempVert1.LastIndexOf(center) == tempVert1AllPos1Index || tempVert1.LastIndexOf(center) == tempVert1AllPos2Index || tempVert1AllPos1Index == tempVert1AllPos2Index 9999999999");}}else{tempTriangles1[tempTriangles1_Count++] = (tempVert1AllPos2Index);tempTriangles1[tempTriangles1_Count++] = (tempVert1AllPos1Index);tempTriangles1[tempTriangles1_Count++] = (center1Index);if (center1Index == tempVert1AllPos1Index || center1Index == tempVert1AllPos2Index || tempVert1AllPos1Index == tempVert1AllPos2Index){//Debug.Log(//    center + "," + allPos[i] + "," + allPos[i + 1] + "\n" +//    tempVert1.IndexOf(center) + "," + tempVert1AllPos1Index + "," + tempVert1AllPos2Index + "," + allPos_Count);//Debug.LogError("if (tempVert1.LastIndexOf(center) == tempVert1AllPos1Index || tempVert1.LastIndexOf(center) == tempVert1AllPos2Index || tempVert1AllPos1Index == tempVert1AllPos2Index) -----------");}}tempVert2[tempVert2_Count++] = (allPos[i]);int tempV1Index = tempVert2_Count - 1;tempVert2[tempVert2_Count++] = (allPos[i + 1]);int tempV2Index = tempVert2_Count - 1;tempNormal2[tempNormal2_Count++] = (normal);tempNormal2[tempNormal2_Count++] = (normal);if (Vector3.Dot(normal, crossA1A2) >= 0){tempTriangles2[tempTriangles2_Count++] = (center2Index);tempTriangles2[tempTriangles2_Count++] = (tempV1Index);tempTriangles2[tempTriangles2_Count++] = (tempV2Index);if (center2Index == tempV1Index || center2Index == tempV2Index || tempV1Index == tempV2Index){//Debug.Log(//    center + "," + allPos[i] + "," + allPos[i + 1] + "\n" +//    tempVert2.IndexOf(center) + "," + tempV1Index + "," + tempV2Index + "," + allPos_Count);//Debug.LogError("tempVert2.LastIndexOf(center) == tempV1Index || tempVert2.LastIndexOf(center) == tempV2Index || tempV1Index == tempV2Index /");}}else{tempTriangles2[tempTriangles2_Count++] = (tempV2Index);tempTriangles2[tempTriangles2_Count++] = (tempV1Index);tempTriangles2[tempTriangles2_Count++] = (center2Index);if (center2Index == tempV1Index || center2Index == tempV2Index || tempV1Index == tempV2Index){//Debug.Log(//    center + "," + allPos[i] + "," + allPos[i + 1] + "\n" +//    tempVert2.IndexOf(center) + "," + tempV1Index + "," + tempV2Index + "," + allPos_Count);//Debug.LogError("tempVert2.LastIndexOf(center) == tempV1Index || tempVert2.LastIndexOf(center) == tempV2Index || tempV1Index == tempV2Index qqqqqqq");}}}}/// <summary>/// 计算Box的UV方法 /// </summary>void CalculateUV(Vector3 size, ref NativeArray<Vector3> vertices, ref NativeArray<int> triangles, ref NativeArray<Vector3> normals, ref NativeArray<Vector2> uvs, ref int verticesCount, ref int trianglesCount, ref int normalsCount, ref int uvsCount){for (int i = 0; i < verticesCount; i++){uvs[uvsCount++] = (new Vector2(0, 0));}for (int i = 0; i < trianglesCount / 3; i++){int i0 = triangles[i * 3];int i1 = triangles[i * 3 + 1];int i2 = triangles[i * 3 + 2];//Vector3 v0 = vertices[i0] - center + size / 2f;//Vector3 v1 = vertices[i1] - center + size / 2f;//Vector3 v2 = vertices[i2] - center + size / 2f;Vector3 v0 = vertices[i0];Vector3 v1 = vertices[i1];Vector3 v2 = vertices[i2];//string str = string.Format("原始数据:({0},{1},{2}) index:({3},{4},{5})", v0.ToString(), v1.ToString(), v2.ToString(), i0, i1, i2);// 除以size.x,y,z是为了缩小范围到[0,1] UV的范围v0 = new Vector3(v0.x / size.x, v0.y / size.y, v0.z / size.z);v1 = new Vector3(v1.x / size.x, v1.y / size.y, v1.z / size.z);v2 = new Vector3(v2.x / size.x, v2.y / size.y, v2.z / size.z);//Vector3 a = v0 - v1;//Vector3 b = v2 - v1; Vector3 a = v1 - v0;Vector3 b = v2 - v1;//我老感觉这法线计算错了...v0->v1-v2             Vector3 dir = normals[i0]; //Vector3.Cross(a, b);  //改用顶点法线作为法线float x = Mathf.Abs(Vector3.Dot(dir, Vector3.right));float y = Mathf.Abs(Vector3.Dot(dir, Vector3.up));float z = Mathf.Abs(Vector3.Dot(dir, Vector3.forward));//法线倾向于X轴,用Z作为X,Y作为Yif (x > y && x > z){uvs[i0] = new Vector2(v0.z, v0.y);uvs[i1] = new Vector2(v1.z, v1.y);uvs[i2] = new Vector2(v2.z, v2.y);}else if (y > z && y > x){//法线倾向于Y轴,用X作为X,Z作为Yuvs[i0] = new Vector2(v0.x, v0.z);uvs[i1] = new Vector2(v1.x, v1.z);uvs[i2] = new Vector2(v2.x, v2.z);}else if (z > x && z > y){//法线倾向于Z轴,用X作为X,Y作为Yuvs[i0] = new Vector2(v0.x, v0.y);uvs[i1] = new Vector2(v1.x, v1.y);uvs[i2] = new Vector2(v2.x, v2.y);}else{//防止出现UV不正常情况uvs[i0] = new Vector2(0, 0);uvs[i1] = new Vector2(1, 1);uvs[i2] = new Vector2(0, 0);//Debug.LogWarning("UV出问题啦..." + x + ", " + y + "," + z + "\n"//    + v0 + ", " + v1 + "," + v2 + " \n"//    + a + ", " + b + "\n"//    + dir + "\n"//    + str);//虽然已经处理了异常三角面,但仍然会出现(x,y,z)全为0的情况...先放任不管看看效果...}}}#endregion
}

相关文章:

【Unity3D】利用IJob、Burst优化处理切割物体

参考文章&#xff1a; 【Unity】切割网格 【Unity3D】ECS入门学习&#xff08;一&#xff09;导入及基础学习_unity ecs教程-CSDN博客 【Unity3D】ECS入门学习&#xff08;十二&#xff09;IJob、IJobFor、IJobParallelFor_unity ijobparallelfor-CSDN博客 工程资源地址&…...

【大前端】Vue3 工程化项目使用详解

目录 一、前言 二、前置准备 2.1 环境准备 2.1.1 create-vue功能 2.1.2 nodejs环境 2.1.3 配置nodejs的环境变量 2.1.4 更换安装包的源 三、工程化项目创建与启动过程 3.1 创建工程化项目 3.2 项目初始化 3.3 项目启动 3.4 核心文件说明 四、VUE两种不同的API风格 …...

基于文件系统分布式锁原理

分布式锁&#xff1a;在一个公共的存储服务上打上一个标记&#xff0c;如Redis的setnx命令&#xff0c;是先到先得方式获得锁&#xff0c;ZooKeeper有点像下面的demo,比较大小的方式判决谁获得锁。 package com.ldj.mybatisflex.demo;import java.util.*; import java.util.co…...

简历整理YH

一&#xff0c;订单中心 1&#xff0c;调拨单 融通(Rocketmq)-订单中心&#xff1a;ECC_BMS123(已出单)&#xff0c;125(分配),127(发货),129(收货) 通过RocketMq接入多场景订单数据 2&#xff0c;销售单 sap&#xff08;FTP&#xff09;-订单中心&#xff0c;下发1002,1003,…...

Kotlin 协程基础三 —— 结构化并发(二)

Kotlin 协程基础系列&#xff1a; Kotlin 协程基础一 —— 总体知识概述 Kotlin 协程基础二 —— 结构化并发&#xff08;一&#xff09; Kotlin 协程基础三 —— 结构化并发&#xff08;二&#xff09; Kotlin 协程基础四 —— CoroutineScope 与 CoroutineContext Kotlin 协程…...

微信小程序实现长按录音,点击播放等功能,CSS实现语音录制动画效果

有一个需求需要在微信小程序上实现一个长按时进行语音录制&#xff0c;录制时间最大为60秒&#xff0c;录制完成后&#xff0c;可点击播放&#xff0c;播放时再次点击停止播放&#xff0c;可以反复录制&#xff0c;新录制的语音把之前的语音覆盖掉&#xff0c;也可以主动长按删…...

校园跑腿小程序---轮播图,导航栏开发

hello hello~ &#xff0c;这里是 code袁~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f981;作者简介&#xff1a;一名喜欢分享和记录学习的在校大学生…...

详细全面讲解C++中重载、隐藏、覆盖的区别

文章目录 总结1、重载示例代码特点1. 模板函数和非模板函数重载2. 重载示例与调用规则示例代码调用规则解释3. 特殊情况与注意事项二义性问题 函数特化与重载的交互 2. 函数隐藏&#xff08;Function Hiding&#xff09;概念示例代码特点 3. 函数覆盖&#xff08;重写&#xff…...

一文读懂单片机的串口

目录 串口通信的基本概念 串口通信的关键参数 单片机串口的硬件连接 单片机串口的工作原理 数据发送过程 数据接收过程 单片机串口的编程实现 以51单片机为例 硬件连接 初始化串口 发送数据 接收数据 串口中断服务函数 代码示例 单片机串口的应用实例 单片机与…...

HTML5 网站模板

HTML5 网站模板 参考 HTML5 Website Templates...

mybatis分页插件:PageHelper、mybatis-plus-jsqlparser(解决SQL_SERVER2005连接分页查询OFFSET问题)

文章目录 引言I PageHelper坐标II mybatis-plus-jsqlparser坐标Spring Boot 添加分页插件自定义 Mapper 方法中使用分页注意事项解决SQL_SERVER2005连接分页查询OFFSET问题知识扩展MyBatis-Plus 框架结构mybatis-plus-jsqlparser的 Page 类引言 PageHelper import com.github.p…...

uniapp中rpx和upx的区别

在 UniApp 中&#xff0c;rpx 和 upx 是两种不同的单位&#xff0c;它们的主要区别在于适用的场景和计算方式。 ### rpx&#xff08;Responsive Pixel&#xff09; - **适用场景**&#xff1a;rpx 是一种响应式单位&#xff0c;主要用于小程序和移动端的布局。 - **计算方式**…...

什么是卷积网络中的平移不变性?平移shft在数据增强中的意义

今天来介绍一下数据增强中的平移shft操作和卷积网络中的平移不变性。 1、什么是平移 Shift 平移是指在数据增强&#xff08;data augmentation&#xff09;过程中&#xff0c;通过对输入图像或目标进行位置偏移&#xff08;平移&#xff09;&#xff0c;让目标在图像中呈现出…...

java.net.SocketException: Connection reset 异常原因分析和解决方法

导致此异常的原因&#xff0c;总结下来有三种情况&#xff1a; 一、服务器端偶尔出现了异常&#xff0c;导致连接关闭 解决方法&#xff1a; 采用出错重试机制 二、 服务器端和客户端使用的连接方式不一致 解决方法&#xff1a; 服务器端和客户端使用相同的连接方式&#xff…...

Maven 仓库的分类

Maven 是一个广泛使用的项目构建和依赖管理工具&#xff0c;在 Java 开发生态中占据重要地位。作为 Maven 的核心概念之一&#xff0c;仓库&#xff08;Repository&#xff09;扮演着至关重要的角色&#xff0c;用于存储项目的依赖、插件以及构建所需的各种资源。 了解 Maven 仓…...

隧道网络:为数据传输开辟安全通道

什么是隧道网络&#xff1f; 想象一下&#xff0c;你正在一个陌生的城市旅行&#xff0c;并且想要访问家里的电脑。但是&#xff0c;直接连接是不可能的&#xff0c;因为家庭网络通常受到防火墙或路由器的保护&#xff0c;不允许外部直接访问。这时候&#xff0c;隧道网络&…...

CentOS 7 下 Nginx 的详细安装与配置

1、安装方式 1.1、通过编译方式安装 下载Nginx1.16.1的安装包 https://nginx.org/download/nginx-1.16.1.tar.gz 下载后上传至/home目录下。 1.2、通过yum方式安装 这种方式安装更简单。 2、通过编译源码包安装Nginx 2.1、安装必要依赖 sudo yum -y install gcc gcc-c sudo…...

JAVA 使用apache poi实现EXCEL文件的输出;apache poi实现标题行的第一个字符为红色;EXCEL设置某几个字符为别的颜色

设置输出文件的列宽&#xff0c;防止文件过于丑陋 Sheet sheet workbook.createSheet(FileConstants.ERROR_FILE_SHEET_NAME); sheet.setColumnWidth(0, 40 * 256); sheet.setColumnWidth(1, 20 * 256); sheet.setColumnWidth(2, 20 * 256); sheet.setColumnWidth(3, 20 * 25…...

通过vba实现在PPT中添加计时器功能

目录 一、前言 二、具体实现步骤 1、准备 2、开启宏、打开开发工具 3、添加计时器显示控件 3.1、开启母版 3.2、插入计时器控件 4、vba代码实现 4.1、添加模块 4.2、添加代码 4.3、保存为pptm 5、效果展示 一、前言 要求/目标:在PPT中每一页上面增加一个计时器功能…...

检验统计量与p值笔记

一、背景 以雨量数据为例&#xff0c;当获得一个站点一年的日雨量数据后&#xff0c;我们需要估计该站点的雨量的概率分布情况&#xff0c;因此我们利用有参估计的方式如极大似然法估计得到了假定该随机变量服从某一分布的参数&#xff0c;从而得到该站点的概率密度函数&#x…...

【集成学习】Bagging、Boosting、Stacking算法详解

文章目录 1. 相关算法详解&#xff1a;2. 算法详细解释&#xff1a;2.1 Bagging&#xff1a;2.2 Boosting&#xff1a;2.3 Stacking&#xff1a;2.4 K-fold Multi-level Stacking&#xff1a; 集成学习&#xff08;Ensemble Learning&#xff09;是一种通过结合多个模型的预测结…...

Rabbit Rocket kafka 怎么实现消息有序消费和延迟消费的

在消息队列系统中&#xff0c;像 RabbitMQ、RocketMQ 和 Kafka 这样的系统&#xff0c;都支持不同的方式来实现消息的有序消费和延迟消费。下面我们分别探讨这些系统中如何实现这两种需求&#xff1a; 1. RabbitMQ&#xff1a;实现消息有序消费和延迟消费 有序消费&#xff1…...

【Ubuntu与Linux操作系统:五、文件与目录管理】

第5章 磁盘存储管理 5.1 Linux磁盘存储概述 磁盘存储是Linux系统存储数据的重要组件&#xff0c;它通过分区和文件系统组织和管理数据。Linux支持多种文件系统&#xff0c;如ext4、xfs和btrfs&#xff0c;并以块的形式管理存储设备。 1. 分区与文件系统&#xff1a; 分区&am…...

32_Redis分片集群原理

1.Redis集群分片 1.1 Redis集群分片介绍 Redis集群没有使用一致性hash,而是引入了哈希槽的概念。Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽。 用于将密钥映射到散列插槽的基本算法如下: HASH_SLOT = CRC16(key) mod 16384 集群的每…...

微信小程序mp3音频播放组件,仅需传入url即可

// index.js // packageChat/components/audio-player/index.js Component({/*** 组件的属性列表*/properties: {/*** MP3 文件的 URL*/src: {type: String,value: ,observer(newVal, oldVal) {if (newVal ! oldVal && newVal) {// 如果 InnerAudioContext 已存在&…...

Sql 创建用户

Sql server 创建用户 Sql server 创建用户SQL MI 创建用户修改其他用户密码 Sql server 创建用户 在对应的数据库执行&#xff0c;该用户得到该库的所有权限 test.database.chinacloudapi.cn DB–01 DB–02 创建服务器登录用户 CREATE LOGIN test WITH PASSWORD zDgXI7rsafkak…...

数据结构:LinkedList与链表—面试题(三)

目录 1、移除链表元素 2、反转链表 3、链表的中间结点 4、返回倒数第k个结点 5、合并两个有序链表 1、移除链表元素 习题链接https://leetcode.cn/problems/remove-linked-list-elements/description/ 描述&#xff1a;给你一个链表的头节点 head 和一个整数 val &#xff…...

【开发日记】Docker修改国内镜像源

1、问题&#xff1a; docker pull镜像时提示以下内容&#xff1a; Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)2、解决 ①…...

Elasticsarch:使用全文搜索在 ES|QL 中进行过滤 - 8.17

8.17 在 ES|QL 中引入了 match 和 qstr 函数&#xff0c;可用于执行全文过滤。本文介绍了它们的作用、使用方法、与现有文本过滤方法的区别、当前的限制以及未来的改进。 ES|QL 现在包含全文函数&#xff0c;可用于使用文本查询过滤数据。我们将回顾可用的文本过滤方法&#xf…...

第432场周赛:跳过交替单元格的之字形遍历、机器人可以获得的最大金币数、图的最大边权的最小值、统计 K 次操作以内得到非递减子数组的数目

Q1、跳过交替单元格的之字形遍历 1、题目描述 给你一个 m x n 的二维数组 grid&#xff0c;数组由 正整数 组成。 你的任务是以 之字形 遍历 grid&#xff0c;同时跳过每个 交替 的单元格。 之字形遍历的定义如下&#xff1a; 从左上角的单元格 (0, 0) 开始。在当前行中向…...

宝鸡响应式网站开发/宁波关键词优化平台

我是表哥Harker,表妹我来咯~ 今天详细的介绍下 全局配置文件 全局配置文件 app.json 小程序根目录下的 app.json 文件用来对微信小程序进行全局配置,它决定了页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等1、在app.json配置文件中,最主要的配置节点是: pa…...

广州企业网站建设靠谱/腾讯朋友圈广告怎么投放

Windows图形基础 Windows系统的两大部分&#xff1a; User32&#xff1a;提供windows应用程序的组成元素&#xff0c;比如窗口&#xff0c;文本框&#xff0c;按钮等。GDI/GDI&#xff1a;提供绘图API&#xff0c;比如绘制图形、文本与图像等。WCF不再基于User32和GDI/GDI,而是…...

免费外贸网站模板下载/正规网站优化推广

linux内核是一个整体是结构。因此向内核添加任何东西。或者删除某些功能 ,都十分困难。为了解决这个问题。引入了内核机制。从而可以动态的想内核中添加或者删除模块。模块不被编译在内核中,因而控制了内核的大小。然而模块一旦被插入内核,他就和内核其他部分一样。这样一来 就…...

网站建设规划书企业网站/付费推广有几种方式

原计划今天返回公司&#xff0c;因功能调整、数据补录问题延迟一天&#xff0c;改到明天。 今天上午跟客户领导做了一个简单汇报&#xff0c;把从开会以来做的工作内容做简单介绍&#xff0c;领导对于当前的进度不太满意&#xff0c;项目整体进度有些滞后。强调需要将工作做的…...

2017我们一起做网站/引擎网站推广法

1.帮助命令&#xff1a; docker version docker info docker --help2.镜像命令&#xff1a; 列出&#xff1a; docker images 列出本地镜像 docker images -a 列出本地所有镜像 包含中间层 docker images -q 只列出Id docker images --digests 显示镜像摘要信息 docker ima…...

5173网站源码/指数基金怎么买才赚钱

Python大本营每日一课大家好&#xff0c;我是营长&#xff0c;上期营长分享了数据科学”的知识点&#xff1a;&#xff0c;不清楚的小伙伴可戳这????每日一课 | 详解抽象之函数本期营长将为大家分享如何快速入门Python开发。这期分享营长邀请的是应书澜&#xff08;深耕 Ja…...