当前位置:  首页  >  PHP资讯  >  业界资讯

Unity3D实现模型随机切割

这篇文章主要为大家详细介绍了Unity3D实现模型随机切割,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了Unity3D实现模型随机切割的具体代码,供大家参考,具体内容如下

模型切割的效果图如下:

我们都知道,模型是由一个个小三角形面组成的,因此我们不妨将问题简化,先实现个小目标,完成单个三角形的切割,甚至继续细分成求一条线段与某个平面的交点。

三角形与切割平面的位置关系主要有以下三种:

1. 三角形与切割平面有两个交点,一个交点在顶点上,一个交点在边上。这时,原有的三角形将被分成两个三角形,分别为013、042。

2. 三角形与切割平面有两个交点,两个交点都在边上。这时,原有的三角形将被分成三个三角形,分别为:034、561、126。

3. 其它(无交点、三角形完全在切割平面上、一条边在切割平面上)

那么,我们如何求线段与平面的交点呢?

即已知平面ABC,线段P0P1,求交点P。

故:

N为平面ABC法向量,可得:N= AB X AC;

P在P0P1上,可得:P = P0 + t * L;   L = P1 - P0;

又因P在平面ABC上,可得: N * PA = 0;

代入得:

=> N * (A - P0 + t * L) = 0;

=> N * (A - P0)   + t * N * L = 0;

=> t =  (P0 - A) * N / (N * L);

=> t =  (P0 - A) * (AB X AC) / (N * (P1 - P0));

最终求得P坐标,因为P0P1是线段而非直线,所以我们需要再做个判断,P是否在线段P0P1中间,用向量点乘可轻易实现。

具体代码如下,其中abc为切割平面上的三个顶点(确保必定构成一个平面):

 public static GameObject[] Split(GameObject obj, Vector3 a, Vector3 b, Vector3 c) { if(obj == null) { return null; } MeshFilter filter = obj.GetComponent(); if(filter == null) { return null; } //切割面位置调整为相对于模型的本地坐标 a = a - obj.transform.position; b = b - obj.transform.position; c = c - obj.transform.position; List vertices = new List(filter.mesh.vertices); List triangles = new List(filter.mesh.triangles); List uvs = new List(filter.mesh.uv); for (int i = 0; i  切割每条边,判断是否有交点,如有交点,在交点处生成两个新的顶点:L/R //2 0 1 //凡是顶点与平面相交的,一律以新顶点替换 //判断以交点为其中一个顶点的三角形在面的哪一面 //指定:交点到其它顶点形成的向量与平面法向量方向一致,则使用L,否则使用R //无交点 //其中一个顶点在平面上 //其中的一条边在平面上 //整个三角形都在平面上 List cross = new List(); for (int m = 0; m <3; m++) { //求线段与面的交点-无交点返回null Point tpoint = MathfUtils.LineCrossPlane(p[m], p[(m + 1) % 3], a, b, c); //排除线段两个端点与平面相交的情况; if (MathfUtils.PointAtPlane(p[m], a, b, c) || MathfUtils.PointAtPlane(p[(m + 1) % 3], a, b, c)) { cross.Add(null); continue; } cross.Add(tpoint); } int tcount = cross.FindAll(t => t != null).Count; if (tcount == 0) { //完全没交点; continue; } if(tcount == 1) { //只与一条边有交点; //012 tidx = 0 交点x在 0-1上,则有三角形 02x 12x //012 tidx = 1 交点x在 1-2上,则有三角形 01x 02x //012 tidx = 2 交点x在 2-3上,则有三角形 01x 12x int tidx = cross.FindIndex(t => t != null); if(tidx <0) { continue; } vertices.Add(cross[tidx].GetVector3()); vertices.Add(cross[tidx].GetVector3()); Vector2 tuv = (uvs[triangles[i + tidx]] + uvs[triangles[i + (tidx + 1) % 3]]) * 0.5f; uvs.Add(tuv); uvs.Add(tuv); //计算法线,保证新三角形与原来的三角形法线保持一致; Vector3 nor0 = Vector3.Cross((p[1] - p[0]).normalized, (p[2] - p[0]).normalized); //改一个 triangles[i + 0] = filter.mesh.triangles[i + tidx]; triangles[i + 1] = filter.mesh.triangles[i + (tidx + 2) % 3]; triangles[i + 2] = vertices.Count - 2; Vector3 nor1 = Vector3.Cross((vertices[triangles[i + 1]] - vertices[triangles[i + 0]]).normalized, (vertices[triangles[i + 2]] - vertices[triangles[i + 0]]).normalized); if(Vector3.Dot(nor0, nor1) <0) { //使用法线方向判断三角形顶点顺序是否与原来一致 int tpidx = triangles[i + 1]; triangles[i + 1] = triangles[i + 2]; triangles[i + 2] = tpidx; } //新增一个 triangles.Add(filter.mesh.triangles[i + (tidx + 1) % 3]); triangles.Add(filter.mesh.triangles[i + (tidx + 2) % 3]); triangles.Add(vertices.Count - 1); Vector3 nor2 = Vector3.Cross((vertices[triangles[triangles.Count - 2]] - vertices[triangles[triangles.Count - 3]]).normalized, (vertices[triangles[triangles.Count - 1]] - vertices[triangles[triangles.Count - 3]]).normalized); if (Vector3.Dot(nor0, nor2) <0) { int tpidx = triangles[triangles.Count - 1]; triangles[triangles.Count - 1] = triangles[triangles.Count - 2]; triangles[triangles.Count - 2] = tpidx; } } if(tcount == 2) { //与两条边有交点; //012 tidx = 0 交点xy不在 0-1上,则有三角形 xy2 xy1 01y //012 tidx = 1 交点xy不在 1-2上,则有三角形 xy0 xy2 12y //012 tidx = 2 交点xy不在 2-3上,则有三角形 xy1 xy0 01y // x-y-tidx+2 是独立三角形,使用一组顶点 int tidx = cross.FindIndex(t => t == null); if (tidx <0) { continue; } //计算法线,保证新三角形与原来的三角形法线保持一致; Vector3 nor0 = Vector3.Cross((p[1] - p[0]).normalized, (p[2] - p[0]).normalized); //x vertices.Add(cross[(tidx + 1) % 3].GetVector3()); vertices.Add(cross[(tidx + 1) % 3].GetVector3()); Vector2 tuvx = (uvs[triangles[i + (tidx + 1) % 3]] + uvs[triangles[i + (tidx + 2) % 3]]) * 0.5f; uvs.Add(tuvx); uvs.Add(tuvx); //y vertices.Add(cross[(tidx + 2) % 3].GetVector3()); vertices.Add(cross[(tidx + 2) % 3].GetVector3()); Vector2 tuvy = (uvs[triangles[i + tidx]] + uvs[triangles[i + (tidx + 2) % 3]]) * 0.5f; uvs.Add(tuvy); uvs.Add(tuvy); //改一个 triangles[i + 0] = filter.mesh.triangles[i + (tidx + 2) % 3]; triangles[i + 1] = vertices.Count - 4; triangles[i + 2] = vertices.Count - 2; Vector3 nor1 = Vector3.Cross((vertices[triangles[i + 1]] - vertices[triangles[i + 0]]).normalized, (vertices[triangles[i + 2]] - vertices[triangles[i + 0]]).normalized); if (Vector3.Dot(nor0, nor1) <0) { int tpidx = triangles[i + 1]; triangles[i + 1] = triangles[i + 2]; triangles[i + 2] = tpidx; } //新增一个 triangles.Add(filter.mesh.triangles[i + (tidx + 1) % 3]); triangles.Add(vertices.Count - 3); triangles.Add(vertices.Count - 1); Vector3 nor2 = Vector3.Cross((vertices[triangles[triangles.Count - 2]] - vertices[triangles[triangles.Count - 3]]).normalized, (vertices[triangles[triangles.Count - 1]] - vertices[triangles[triangles.Count - 3]]).normalized); if (Vector3.Dot(nor0, nor2) <0) { int tpidx = triangles[triangles.Count - 1]; triangles[triangles.Count - 1] = triangles[triangles.Count - 2]; triangles[triangles.Count - 2] = tpidx; } //新增一个 triangles.Add(filter.mesh.triangles[i + tidx % 3]); triangles.Add(filter.mesh.triangles[i + (tidx + 1) % 3]); triangles.Add(vertices.Count - 1); Vector3 nor3 = Vector3.Cross((vertices[triangles[triangles.Count - 2]] - vertices[triangles[triangles.Count - 3]]).normalized, (vertices[triangles[triangles.Count - 1]] - vertices[triangles[triangles.Count - 3]]).normalized); if (Vector3.Dot(nor0, nor3) <0) { int tpidx = triangles[triangles.Count - 1]; triangles[triangles.Count - 1] = triangles[triangles.Count - 2]; triangles[triangles.Count - 2] = tpidx; } } } //根据顶点索引数组确定mesh被分成了几份 //经实验:不可行;因为同一个位置的点在不同的面中是不同的点,无法判断这两个三角形是否是连接起来的 //故只能按方向将模型分成两个 List> ntriangles = new List>(); List> temps = new List>(); List> nvertices = new List>(); List> nuvs = new List>(); //切割面的法向量; Vector3 pnormal = Vector3.Cross((c - a).normalized, (b - a).normalized); ntriangles.Add(new List()); ntriangles.Add(new List()); temps.Add(new List()); temps.Add(new List()); nuvs.Add(new List()); nuvs.Add(new List()); nvertices.Add(new List()); nvertices.Add(new List()); for (int i = 0; i  Mathf.Abs(t) &#63; tt : t; } int tidx = t >= 0 &#63; 0 : 1; for (int j = 0; j <3; j++) { int idx = temps[tidx].IndexOf(triangles[i + j]); if (idx <0) { ntriangles[tidx].Add(nvertices[tidx].Count); nvertices[tidx].Add(vertices[triangles[i + j]]); temps[tidx].Add(triangles[i + j]); nuvs[tidx].Add(uvs[triangles[i + j]]); continue; } ntriangles[tidx].Add(idx); } } if(nvertices[0].Count == 0 || nvertices[1].Count == 0) { //没有切割到物体 return null; } //生成新的模型; List items = new List(); MeshRenderer render = obj.GetComponent(); for (int i = 0; i (); MeshRenderer mr = tobj.AddComponent(); if(render != null) { mr.material = render.material; } Mesh mesh = new Mesh(); mesh.vertices = nvertices[i].ToArray(); mesh.triangles = ntriangles[i].ToArray(); mesh.uv = nuvs[i].ToArray(); mesh.RecalculateNormals(); mesh.RecalculateTangents(); mesh.RecalculateBounds(); fi.mesh = mesh; } return items.ToArray(); } 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

内容推荐:免费高清PNG素材下载
吐了个 "CAO" !
扫码关注 PHP1 官方微信号
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved PHP1.CN 第一PHP社区 版权所有 京ICP备19059560号-4