3d模型任意切割的思路(续)
来源:互联网 发布:全球贸易预警数据库 编辑:程序博客网 时间:2024/05/19 10:10
上一篇讲到3d模型切割我遇到的问题(切面的纹理会混乱),经过这段时间的琢磨,有了解决方案,当然我这里只给出我的解决思路,投入到实际项目中还需要做许多工作,比如我在上一篇中切割模型固定写死了切平面方程是y=0.1。实际项目中,我们应该是根据手指滑动来得出空间平面方程式。纹理之所以会混乱,根本上的原因是因为我们切割模型后生成出来的新的顶点是混乱无序的,所以我在这片文章里做的,就是把新生成的纹理重新排序,事实上,模型切割的关键点就只有上一篇讲的生成横切面的新顶点以及本篇解决的切口纹理,理论上解决了这两点,就近乎可以做到以假乱真的程度了。这里只是提供了思路,因为解决了纹理混乱的问题。如需下载完整插件,请到http://www.demodashi.com/demo/11343.html
//重新排序新生成的顶点,按照角度 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 ++; }
以上为重新排序了顶点的代码。说一下是怎么排序的吧。
首先,切出来的模型新生成的顶点是无序的,但是我们可以连接任意两个无序顶点定为参考向量,然后其他任意顶点与参考向量中的起点连接形成新的向量,求得这两个向量之间的夹角,利用这个夹角大小来排序,如图所示:
以下是完整代码
/* * @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 < 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 - 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)); } //法向量 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 + 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) < 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 = 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 ++; } mf.mesh.vertices = verticeList.ToArray(); mf.mesh.triangles = triangles1.ToArray(); if (uvList.Count > 0) { mf.mesh.uv = uvList.ToArray(); } mf.mesh.normals = normalList.ToArray(); //分割模型 GameObject newModel = new GameObject("New Model"); MeshFilter meshFilter = newModel.AddComponent<MeshFilter>(); meshFilter.mesh.vertices = mf.mesh.vertices; meshFilter.mesh.triangles = triangles2.ToArray(); meshFilter.mesh.uv = mf.mesh.uv; meshFilter.mesh.normals = mf.mesh.normals; Renderer newRenderer = newModel.AddComponent<MeshRenderer>(); newRenderer.material = this.gameObject.GetComponent<MeshRenderer>().material; }}
/* * @authors: liangjian * @desc:*/using UnityEngine;using System.Collections;using System;public class SortAngle : IComparable<SortAngle> { public int Index; public float Angle; public int CompareTo(SortAngle item) { return item.Angle.CompareTo(Angle); }}
阅读全文
3 1
- 3d模型任意切割的思路(续)
- 关于3d模型任意切割的思路
- unity模型任意无限切割插件
- 3d切割轮播图
- Android OpenGL显示任意3D模型文件
- Android OpenGL显示任意3D模型文件
- Android OpenGL显示任意3D模型文件
- 基于VTK的任意平面切割
- 基于VTK的任意平面切割
- 基于3D表面网格的切割算法
- 3D数学--学习笔记(三):3D中绕任意轴的旋转
- 3D数学--学习笔记(三):3D中绕任意轴的旋转
- Bitmap 任意切割算法
- 3D模型(.x)
- 任意多边形裁剪圆的实现思路
- VML之带背景的3D图形任意旋转
- 文章预告-3D中绕任意轴的旋转
- 3D中绕任意轴旋转的推断问题
- 如何给easyUi的input框赋值
- Freetype library not found问题解决
- linux常用命令
- 欢迎使用CSDN-markdown编辑器
- laravel5.4 使用多字段查询分组报错
- 3d模型任意切割的思路(续)
- 使 Oracle 索引失效的七大限制条件
- 3.4—字符串—Add Binary
- js知识总结思维导图
- 浅谈工程师的调试法宝(二)---半主机的巧妙应用
- 编码
- kotlin Android中 findViewById()不能推导类型的错误
- Intellij IDEA的常用设置
- Android Coding 利器 之 掌握小技巧