上一篇讲到3d模型切割我遇到的问题(切面的纹理会混乱),经过这段时间的琢磨,有了解决方案,当然我这里只给出我的解决思路,投入到实际项目中还需要做许多工作,比如我在上一篇中切割模型固定写死了切平面方程是y=0.1。实际项目中,我们应该是根据手指滑动来得出空间平面方程式。纹理之所以会混乱,根本上的原因是因为我们切割模型后生成出来的新的顶点是混乱无序的,所以我在这片文章里做的,就是把新生成的纹理重新排序,事实上,模型切割的关键点就只有上一篇讲的生成横切面的新顶点以及本篇解决的切口纹理,理论上解决了这两点,就近乎可以做到以假乱真的程度了。这里只是提供了思路,因为解决了纹理混乱的问题。
[csharp] view plain copy
//重新排序新生成的顶点,按照角度
List<SortAngle> SortAngleList = new List<SortAngle>();
for (int verticeIndex = verticeCount + 1; verticeIndex < verticeList.Count; verticeIndex++)
{
//计算角度,以0-1为参照
Vector3 vec1to0 = verticeList[verticeCount + 1] - verticeList[verticeCount];
Vector3 indexTo0 = verticeList[verticeIndex] - verticeList[verticeCount];
float angle = Vector3.Angle(indexTo0.normalized, vec1to0.normalized);
bool isExis = false;
for (int i = 0; i < SortAngleList.Count; ++i)
{
//同样角度,距离近的被剔除
if (SortAngleList[i].Angle == angle)
{
float dis1 = Vector3.Distance(verticeList[SortAngleList[i].Index], verticeList[verticeCount]);
float dis2 = Vector3.Distance(verticeList[verticeIndex], verticeList[verticeCount]);
if (dis2 > dis1)
{
SortAngleList[i].Index = verticeIndex;
}
isExis = true;
break;
}
}
if (!isExis)
{
Debug.Log(angle);
SortAngle sortAngle = new SortAngle();
sortAngle.Index = verticeIndex;
sortAngle.Angle = angle;
SortAngleList.Add(sortAngle);
}
}
SortAngleList.Sort();
//缝合切口
for (int verticeIndex = 0; verticeIndex < SortAngleList.Count - 1;)
{
triangles1.Add(verticeCount);
triangles1.Add(SortAngleList[verticeIndex].Index);
triangles1.Add(SortAngleList[verticeIndex + 1].Index);
triangles2.Add(verticeCount);
triangles2.Add(SortAngleList[verticeIndex].Index);
triangles2.Add(SortAngleList[verticeIndex + 1].Index);
verticeIndex ++;
}
以上为重新排序了顶点的代码。说一下是怎么排序的吧。
首先,切出来的模型新生成的顶点是无序的,但是我们可以连接任意两个无序顶点定为参考向量,然后其他任意顶点与参考向量中的起点连接形成新的向量,求得这两个向量之间的夹角,利用这个夹角大小来排序,如图所示:
以下是完整代码
[csharp] view plain copy
/*
* @authors: liangjian
* @desc:
*/
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class ClipMesh : MonoBehaviour {
float ClipPlaneY = 0.01f;
void Start () {
MeshFilter mf = this.gameObject.GetComponent<MeshFilter>();
//顶点数组转顶点容器
List<Vector3> verticeList = new List<Vector3>();
int verticeCount = mf.mesh.vertices.Length;
for (int verticeIndex = 0; verticeIndex < verticeCount; ++verticeIndex)
{
verticeList.Add(mf.mesh.vertices[verticeIndex]);
}
//三角形数组转三角形容器
List<int> triangleList = new List<int>();
int triangleCount = mf.mesh.triangles.Length;
for (int triangleIndex = 0; triangleIndex < triangleCount; ++triangleIndex)
{
triangleList.Add(mf.mesh.triangles[triangleIndex]);
}
//uv坐标数组转uv坐标容器
List<Vector2> uvList = new List<Vector2>();
int uvCount = mf.mesh.uv.Length;
for (int uvIndex = 0; uvIndex < uvCount; ++uvIndex)
{
uvList.Add(mf.mesh.uv[uvIndex]);
}
//顶点颜色数组转顶点颜色容器
List<Vector3> normalList = new List<Vector3>();
int normalCount = mf.mesh.normals.Length;
for (int normalIndex = 0; normalIndex <www.xucaizxyl.com/ normalCount; ++normalIndex)
{
normalList.Add(mf.mesh.normals[normalIndex]);
}
//检查每个三角面,是否存在两个顶点连接正好在直线上
for (int triangleIndex = 0; triangleIndex < triangleList.Count;)
{
int trianglePoint0 = triangleList[triangleIndex];
int trianglePoint1 = triangleList[triangleIndex + 1];
int trianglePoint2 = triangleList[triangleIndex + 2];
Vector3 point0 = verticeList[trianglePoint0];
Vector3 point1 = verticeList[trianglePoint1];
Vector3 point2 = verticeList[trianglePoint2];
float planeY = ClipPlaneY;
//0-1,1-2相连线段被切割
if ((point0.y - planeY)* (point1.y - planeY) < 0 && (point1.y - planeY) * (point2.y - planeY) < 0)
{
//截断0-1之间的顶点
float k01 = (point1.y - point0.y) / (planeY - point0.y);
float newPointX01 = (point1.x - point0.x) / k01 + point0.x;
float newPointZ01 = (point1.z - point0.z) / k01 + point0.z;
Vector3 newPoint0_1 = new Vector3(newPointX01, planeY, newPointZ01);
verticeList.Add(newPoint0_1);
//uv
if(uvList.Count > 0)
{
Vector2 uv0 = uvList[trianglePoint0];
Vector2 uv1 = uvList[trianglePoint1];
float newUV_x = (uv1.x - uv0.x) / k01 + uv0.x;
float newUV_y = (uv1.y - uv0.y) / k01 + uv0.y;
uvList.Add(new Vector2(newUV_x, newUV_y));
}
//法向量
Vector3 normalX0 = normalList[trianglePoint0];
Vector3 normalX1 = normalList[trianglePoint1];
Vector3 normalX2 = normalList[trianglePoint2];
float newNoramlX01 = (normalX1.x - normalX0.x) / k01 + normalX0.x;
float newNoramlY01 = (normalX1.y - normalX0.y) / k01 + normalX0.y;
float newNoramlZ01 = (normalX1.z - normalX0.z) / k01 + normalX0.z;
normalList.Add(new Vector3(newNoramlX01, newNoramlY01, newNoramlZ01));
//截断1-2之间的顶点
float k12 = (point2.y - point1.y) / (planeY - point1.y);
float newPointX12 = (point2.x - www.yongshiyule.cn point1.x) / k12 + point1.x;
float newPointZ12 = (point2.z - www.wmyl15.com point1.z) / k12 + point1.z;
Vector3 newPoint1_2 = new Vector3( www.tips139.com/ newPointX12, planeY, newPointZ12);
verticeList.Add(newPoint1_2);
if (uvList.Count > 0)
{
Vector2 uv1 = uvList[trianglePoint1];
Vector2 uv2 = uvList[trianglePoint2];
float newUV_x = (uv2.x - uv1.x) www.lieqibiji.com/ / k12 + uv1.x;
float newUV_y = (uv2.y - uv1.y) / k12 + uv1.y;
uvList.Add(new Vector2(newUV_x, newUV_y));
}
//法向量
float newNoramlX12 = (normalX2.x - normalX1.x) / k12 + normalX1.x;
float newNoramlY12 = (normalX2.y - normalX1.y) / k12 + normalX1.y;
float newNoramlZ12 = (normalX2.z - normalX1.z) / k12 + normalX1.z;
normalList.Add(new Vector3(newNoramlX12, newNoramlY12, newNoramlZ12));
int newVerticeCount = verticeList.Count;
//插入顶点索引,以此构建新三角形
triangleList.Insert(triangleIndex + 1, newVerticeCount - 2);
triangleList.Insert(triangleIndex + 2, newVerticeCount - 1);
triangleList.Insert(triangleIndex + 3, newVerticeCount - 1);
triangleList.Insert(triangleIndex + 4, newVerticeCount - 2);
triangleList.Insert(triangleIndex + 6, trianglePoint0);
triangleList.Insert(triangleIndex + 7, newVerticeCount - 1);
}
//1-2,2-0相连线段被切割
else if ((point1.y - planeY) * (point2.y - planeY) < 0 && (point2.y - planeY) * (point0.y - planeY) < 0)
{
//截断1-2之间的顶点
float k12 = (point2.y - point1.y) / (planeY - point1.y);
float newPointX12 = (point2.x - point1.x) / k12 + point1.x;
float newPointZ12 = (point2.z - point1.z) / k12 + point1.z;
Vector3 newPoint1_2 = new Vector3(newPointX12, planeY, newPointZ12);
verticeList.Add(newPoint1_2);
if (uvList.Count > 0)
{
Vector2 uv1 = uvList[trianglePoint1];
Vector2 uv2 = uvList[trianglePoint2];
float newUV_x = (uv2.x - uv1.x) / k12 + uv1.x;
float newUV_y = (uv2.y - uv1.y) / k12 + uv1.y;
uvList.Add(new Vector2(newUV_x, newUV_y));
}
//法向量
Vector3 normalX0 = normalList[trianglePoint0];
Vector3 normalX1 = normalList[trianglePoint1];
Vector3 normalX2 = normalList[trianglePoint2];
float newNoramlX12 = (normalX2.x - normalX1.x) / k12 + normalX1.x;
float newNoramlY12 = (normalX2.y - normalX1.y) / k12 + normalX1.y;
float newNoramlZ12 = (normalX2.z - normalX1.z) / k12 + normalX1.z;
normalList.Add(new Vector3(newNoramlX12, newNoramlY12, newNoramlZ12));
//截断0-2之间的顶点
float k02 = (point2.y - point0.y) / (planeY - point0.y);
float newPointX02 = (point2.x - point0.x) / k02 + point0.x;
float newPointZ02 = (point2.z - point0.z) / k02 + point0.z;
Vector3 newPoint0_2 = new Vector3(newPointX02, planeY, newPointZ02);
verticeList.Add(newPoint0_2);
//uv
if (uvList.Count > 0)
{
Vector2 uv0 = uvList[trianglePoint0];
Vector2 uv2 = uvList[trianglePoint2];
float newUV_x = (uv2.x - uv0.x) / k02 + uv0.x;
float newUV_y = (uv2.y - uv0.y) / k02 + uv0.y;
uvList.Add(new Vector2(newUV_x, newUV_y));
}
//法向量
float newNoramlX02 = (normalX1.x - normalX0.x) / k02 + normalX0.x;
float newNoramlY02 = (normalX1.y - normalX0.y) / k02 + normalX0.y;
float newNoramlZ02 = (normalX1.z - normalX0.z) / k02 + normalX0.z;
normalList.Add(new Vector3(newNoramlX02, newNoramlY02, newNoramlZ02));
int newVerticeCount = verticeList.Count;
//插入顶点索引,以此构建新三角形
//{0}
//{1}
triangleList.Insert(triangleIndex + 2, newVerticeCount - 2);
triangleList.Insert(triangleIndex + 3, newVerticeCount - 1);
triangleList.Insert(triangleIndex + 4, newVerticeCount - 2);
//{2}
triangleList.Insert(triangleIndex www.120xh.cn + 6, newVerticeCount - 1);
triangleList.Insert(triangleIndex + 7, trianglePoint0);
triangleList.Insert(triangleIndex + 8, newVerticeCount - 2);
}
//0-1,2-0相连线段被切割
else if((point0.y - planeY) * (point1.y - planeY) <www.wmyl11.com 0 && (point2.y - planeY) * (point0.y - planeY) < 0)
{
//截断0-1之间的顶点
float k01 = (point1.y - point0.y) / (planeY - point0.y);
float newPointX01 = (point1.x - point0.x) / k01 + point0.x;
float newPointZ01 = (point1.z - point0.z) / k01 + point0.z;
Vector3 newPoint0_1 = new Vector3(newPointX01, planeY, newPointZ01);
verticeList.Add(newPoint0_1);
//uv
if (uvList.Count > 0)
{
Vector2 uv0 = uvList[trianglePoint0];
Vector2 uv1 = uvList[trianglePoint1];
float newUV_x = (uv1.x - uv0.x) / k01 + uv0.x;
float newUV_y = (uv1.y - uv0.y) / k01 + uv0.y;
uvList.Add(new Vector2(newUV_x, newUV_y));
}
//法向量
Vector3 normalX0 = normalList[trianglePoint0];
Vector3 normalX1 = normalList[trianglePoint1];
Vector3 normalX2 = normalList[trianglePoint2];
float newNoramlX01 = (normalX1.x - normalX0.x) / k01 + normalX0.x;
float newNoramlY01 = (normalX1.y - normalX0.y) / k01 + normalX0.y;
float newNoramlZ01 = (normalX1.z - normalX0.z) / k01 + normalX0.z;
normalList.Add(new Vector3(newNoramlX01, newNoramlY01, newNoramlZ01));
//截断0-2之间的顶点
float k02 = (point2.y - point0.y) / (planeY - point0.y);
float newPointX02 = (point2.x - point0.x) / k02 + point0.x;
float newPointZ02 = (point2.z - point0.z) / k02 + point0.z;
Vector3 newPoint0_2 = new Vector3(newPointX02, planeY, newPointZ02);
verticeList.Add(newPoint0_2);
//uv
if (uvList.Count > 0)
{
Vector2 uv0 = uvList[trianglePoint0];
Vector2 uv2 = uvList[trianglePoint2];
float newUV_x = (uv2.x - uv0.x) / k02 + uv0.x;
float newUV_y = (uv2.y - uv0.y) / k02 + uv0.y;
uvList.Add(new Vector2(newUV_x, newUV_y));
}
//法向量
float newNoramlX02 = (normalX1.x - normalX0.x) / k02 + normalX0.x;
float newNoramlY02 = (normalX1.y - normalX0.y) / k02 + normalX0.y;
float newNoramlZ02 = (normalX1.z - normalX0.z) / k02 + normalX0.z;
normalList.Add(new Vector3(newNoramlX02, newNoramlY02, newNoramlZ02));
int newVerticeCount = verticeList.Count;
//插入顶点索引,以此构建新三角形
//{0}
triangleList.Insert(triangleIndex + 1, newVerticeCount - 2);
triangleList.Insert(triangleIndex + 2, newVerticeCount - 1);
triangleList.Insert(triangleIndex + 3, newVerticeCount - 2);
//{1}
//{2}
triangleList.Insert(triangleIndex + 6, trianglePoint2);
triangleList.Insert(triangleIndex + 7, newVerticeCount - 1);
triangleList.Insert(triangleIndex + 8, newVerticeCount - 2);
}
//只有0-1被切
else if((point0.y - planeY) * (point1.y - planeY) < 0)
{
Debug.Log("只有01被切");
}
//只有1-2被切
else if ((point1.y - planeY) * (point2.y - planeY) < 0)
{
Debug.Log("只有12被切");
}
//只有2-0被切
else if ((point2.y - planeY) * (point0.y - planeY) < 0)
{
Debug.Log("只有02被切");
}
triangleIndex += 3;
}
//筛选出切割面两侧的顶点索引
List<int> triangles1 = new List<int>();
List<int> triangles2 = new List<int>();
for (int triangleIndex = 0; triangleIndex < triangleList.Count; triangleIndex += 3)
{
int trianglePoint0 = triangleList[triangleIndex];
int trianglePoint1 = triangleList[triangleIndex + 1];
int trianglePoint2 = triangleList[triangleIndex + 2];
Vector3 point0 = verticeList[trianglePoint0];
Vector3 point1 = verticeList[trianglePoint1];
Vector3 point2 = verticeList[trianglePoint2];
//切割面
float planeY = ClipPlaneY;
if(point0.y > planeY || point1.y > planeY || point2.y > planeY)
{
triangles1.Add(trianglePoint0);
triangles1.Add(trianglePoint1);
triangles1.Add(trianglePoint2);
}
else
{
triangles2.Add(trianglePoint0);
triangles2.Add(trianglePoint1);
triangles2.Add(trianglePoint2);
}
}
//重新排序新生成的顶点,按照角度
List<SortAngle> SortAngleList = new List<SortAngle>();
for (int verticeIndex = verticeCount + 1; verticeIndex < verticeList.Count; verticeIndex++)
{
//计算角度,以0-1为参照
Vector3 vec1to0 = verticeList[verticeCount + 1] - verticeList[verticeCount];
Vector3 indexTo0 = verticeList[verticeIndex] - verticeList[verticeCount];
<span style="white-space:pre"> float moIndexto0 = indexTo0.magnitude;
float mo1to0 = vec1to0.magnitude;
float dotRes = Vector3.Dot(indexTo0, vec1to0);</span>
float angle = Mathf.Acos(dotRes/(mo1to0* moIndexto0));
bool isExis = false;
for (int i = 0; i < SortAngleList.Count; ++i)
{
//同样角度,距离近的被剔除
if (SortAngleList[i].Angle == angle)
{
float dis1 = Vector3.Distance(verticeList[SortAngleList[i].Index], verticeList[verticeCount]);
float dis2 = Vector3.Distance(verticeList[verticeIndex], verticeList[verticeCount]);
if (dis2 > dis1)
{
SortAngleList[i].Index = verticeIndex;
}
isExis = true;
break;
}
}
if (!isExis)
{
Debug.Log(angle);
SortAngle sortAngle = new SortAngle();
sortAngle.Index = vertic