【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; //对应dir
public Vector3 cutVertical;//对应vertical
public 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 -> p2
if (Vector3.Dot(normal, Vector3.Cross(vp1, p1p2)) > 0)
{
tempTriangle.Add(vIndex);
tempTriangle.Add(p1Index);
tempTriangle.Add(p2Index);
}
else
{
//p2 -> p1 -> v
tempTriangle.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 tempNormal
tempVert.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->p1
tempTriangle.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->v1
Vector3 _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作为Y
if (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作为Y
uvs[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作为Y
uvs[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 -> p2
if (Vector3.Dot(normal, Vector3.Cross(vp1, p1p2)) > 0)
{
tempTriangle[tempTriangleCount++] = (vIndex);
tempTriangle[tempTriangleCount++] = (p1Index);
tempTriangle[tempTriangleCount++] = (p2Index);
}
else
{
//p2 -> p1 -> v
tempTriangle[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 tempNormal
tempVert[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->p1
tempTriangle[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->v1
Vector3 _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作为Y
if (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作为Y
uvs[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作为Y
uvs[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
}