【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…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...

linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...

ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)
前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 编辑 前言: 类加载器 1. …...

给网站添加live2d看板娘
给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...