【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优化处理切割物体
参考文章: 【Unity】切割网格 【Unity3D】ECS入门学习(一)导入及基础学习_unity ecs教程-CSDN博客 【Unity3D】ECS入门学习(十二)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风格 …...
基于文件系统分布式锁原理
分布式锁:在一个公共的存储服务上打上一个标记,如Redis的setnx命令,是先到先得方式获得锁,ZooKeeper有点像下面的demo,比较大小的方式判决谁获得锁。 package com.ldj.mybatisflex.demo;import java.util.*; import java.util.co…...
简历整理YH
一,订单中心 1,调拨单 融通(Rocketmq)-订单中心:ECC_BMS123(已出单),125(分配),127(发货),129(收货) 通过RocketMq接入多场景订单数据 2,销售单 sap(FTP)-订单中心,下发1002,1003,…...
Kotlin 协程基础三 —— 结构化并发(二)
Kotlin 协程基础系列: Kotlin 协程基础一 —— 总体知识概述 Kotlin 协程基础二 —— 结构化并发(一) Kotlin 协程基础三 —— 结构化并发(二) Kotlin 协程基础四 —— CoroutineScope 与 CoroutineContext Kotlin 协程…...
微信小程序实现长按录音,点击播放等功能,CSS实现语音录制动画效果
有一个需求需要在微信小程序上实现一个长按时进行语音录制,录制时间最大为60秒,录制完成后,可点击播放,播放时再次点击停止播放,可以反复录制,新录制的语音把之前的语音覆盖掉,也可以主动长按删…...

校园跑腿小程序---轮播图,导航栏开发
hello hello~ ,这里是 code袁~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 🦁作者简介:一名喜欢分享和记录学习的在校大学生…...

详细全面讲解C++中重载、隐藏、覆盖的区别
文章目录 总结1、重载示例代码特点1. 模板函数和非模板函数重载2. 重载示例与调用规则示例代码调用规则解释3. 特殊情况与注意事项二义性问题 函数特化与重载的交互 2. 函数隐藏(Function Hiding)概念示例代码特点 3. 函数覆盖(重写ÿ…...

一文读懂单片机的串口
目录 串口通信的基本概念 串口通信的关键参数 单片机串口的硬件连接 单片机串口的工作原理 数据发送过程 数据接收过程 单片机串口的编程实现 以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 中,rpx 和 upx 是两种不同的单位,它们的主要区别在于适用的场景和计算方式。 ### rpx(Responsive Pixel) - **适用场景**:rpx 是一种响应式单位,主要用于小程序和移动端的布局。 - **计算方式**…...

什么是卷积网络中的平移不变性?平移shft在数据增强中的意义
今天来介绍一下数据增强中的平移shft操作和卷积网络中的平移不变性。 1、什么是平移 Shift 平移是指在数据增强(data augmentation)过程中,通过对输入图像或目标进行位置偏移(平移),让目标在图像中呈现出…...
java.net.SocketException: Connection reset 异常原因分析和解决方法
导致此异常的原因,总结下来有三种情况: 一、服务器端偶尔出现了异常,导致连接关闭 解决方法: 采用出错重试机制 二、 服务器端和客户端使用的连接方式不一致 解决方法: 服务器端和客户端使用相同的连接方式ÿ…...
Maven 仓库的分类
Maven 是一个广泛使用的项目构建和依赖管理工具,在 Java 开发生态中占据重要地位。作为 Maven 的核心概念之一,仓库(Repository)扮演着至关重要的角色,用于存储项目的依赖、插件以及构建所需的各种资源。 了解 Maven 仓…...
隧道网络:为数据传输开辟安全通道
什么是隧道网络? 想象一下,你正在一个陌生的城市旅行,并且想要访问家里的电脑。但是,直接连接是不可能的,因为家庭网络通常受到防火墙或路由器的保护,不允许外部直接访问。这时候,隧道网络&…...

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设置某几个字符为别的颜色
设置输出文件的列宽,防止文件过于丑陋 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值笔记
一、背景 以雨量数据为例,当获得一个站点一年的日雨量数据后,我们需要估计该站点的雨量的概率分布情况,因此我们利用有参估计的方式如极大似然法估计得到了假定该随机变量服从某一分布的参数,从而得到该站点的概率密度函数&#x…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...

Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...

免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...

Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...