我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Unity3D怎么实现模型随机切割

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Unity3D怎么实现模型随机切割

这篇文章主要介绍Unity3D怎么实现模型随机切割,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

模型切割的效果图如下:

Unity3D怎么实现模型随机切割

Unity3D怎么实现模型随机切割

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

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

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

Unity3D怎么实现模型随机切割

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

Unity3D怎么实现模型随机切割

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

Unity3D怎么实现模型随机切割

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

即已知平面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<MeshFilter>();  if(filter == null)  {  return null;  }   //切割面位置调整为相对于模型的本地坐标  a = a - obj.transform.position;  b = b - obj.transform.position;  c = c - obj.transform.position;    List<Vector3> vertices = new List<Vector3>(filter.mesh.vertices);  List<int> triangles = new List<int>(filter.mesh.triangles);  List<Vector2> uvs = new List<Vector2>(filter.mesh.uv);   for (int i = 0; i < filter.mesh.triangles.Length; i = i + 3)  {  //取三角形;  Vector3[] p = new Vector3[3];  for (int m = 0; m < 3; m++)  {   p[m] = filter.mesh.vertices[filter.mesh.triangles[i + m]];  }   //0 1 2   //1 2 0 ==> 切割每条边,判断是否有交点,如有交点,在交点处生成两个新的顶点:L/R  //2 0 1  //凡是顶点与平面相交的,一律以新顶点替换  //判断以交点为其中一个顶点的三角形在面的哪一面  //指定:交点到其它顶点形成的向量与平面法向量方向一致,则使用L,否则使用R  //无交点  //其中一个顶点在平面上  //其中的一条边在平面上  //整个三角形都在平面上   List<Point> cross = new List<Point>();   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<List<int>> ntriangles = new List<List<int>>();  List<List<int>> temps = new List<List<int>>();  List<List<Vector3>> nvertices = new List<List<Vector3>>();  List<List<Vector2>> nuvs = new List<List<Vector2>>();   //切割面的法向量;  Vector3 pnormal = Vector3.Cross((c - a).normalized, (b - a).normalized);  ntriangles.Add(new List<int>());  ntriangles.Add(new List<int>());  temps.Add(new List<int>());  temps.Add(new List<int>());  nuvs.Add(new List<Vector2>());  nuvs.Add(new List<Vector2>());  nvertices.Add(new List<Vector3>());  nvertices.Add(new List<Vector3>());  for (int i = 0; i < triangles.Count; i = i + 3)  {  //判断新的三角形在面的哪一侧;  float t = 0;  for(int j = 0; j < 3; j++)  {   Vector3 dir = (vertices[triangles[i + j]] - a).normalized;   float tt = Vector3.Dot(dir, pnormal);   t = Mathf.Abs(tt) > Mathf.Abs(t) ? tt : t;  }    int tidx = t >= 0 ? 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<GameObject> items = new List<GameObject>();  MeshRenderer render = obj.GetComponent<MeshRenderer>();  for (int i = 0; i < ntriangles.Count; i++)  {  GameObject tobj = new GameObject(i.ToString());  tobj.transform.position = obj.transform.position;  items.Add(tobj);  MeshFilter fi = tobj.AddComponent<MeshFilter>();  MeshRenderer mr = tobj.AddComponent<MeshRenderer>();    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();}

以上是“Unity3D怎么实现模型随机切割”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网行业资讯频道!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Unity3D怎么实现模型随机切割

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Unity3D怎么实现模型随机切割

这篇文章主要介绍Unity3D怎么实现模型随机切割,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!模型切割的效果图如下:我们都知道,模型是由一个个小三角形面组成的,因此我们不妨将问题简化,先实现个小目标,完成单个三角形
2023-06-14

C++怎么实现字符串切割

本篇内容介绍了“C++怎么实现字符串切割”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!字符串切割的两种方法字符串切割的使用频率还是挺高的,s
2023-07-02

python中怎么实现一个随机数模块

python中怎么实现一个随机数模块,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。随机整数:>>> import random >>> random.randint(0,99
2023-06-17

MATLAB全景图切割及盒图显示怎么实现

小编给大家分享一下MATLAB全景图切割及盒图显示怎么实现,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!part1 全景图切割原图:切割效果:以下是切割部分步骤:
2023-06-15

python的​PyPDF2怎么实现pdf文件切割和合并

这篇文章将为大家详细讲解有关python的PyPDF2怎么实现pdf文件切割和合并,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。在百度了一番后,发现大多都是使用 Adobe Acrobat 软件进行剪裁,
2023-06-29

Android中怎么实现一个图片切割工具类

Android中怎么实现一个图片切割工具类,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。图片切割工具类定义:public class ImageSplitter{ /**
2023-05-30

Java中怎么实现一个日志切割清理工具

本篇文章给大家分享的是有关Java中怎么实现一个日志切割清理工具,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。对于服务器的日常维护来说,日志清理是非常重要的事情,如果残留日志过
2023-06-17

怎么用vue实现滚动tab跟随切换效果

这篇文章主要介绍“怎么用vue实现滚动tab跟随切换效果”,在日常操作中,相信很多人在怎么用vue实现滚动tab跟随切换效果问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么用vue实现滚动tab跟随切换效果
2023-07-04

python怎么实现随机森林算法

要实现随机森林算法,你可以使用scikit-learn库中的RandomForestClassifier类。下面是一个示例代码:```pythonfrom sklearn.ensemble import RandomForestClassi
2023-08-15

pgsql生成随机码UUId怎么实现

在 PostgreSQL 中,可以使用 gen_random_uuid() 函数生成随机 UUID。以下是一个示例:SELECT gen_random_uuid();该函数将返回一个随机生成的 UUID。如果要将其存储在表中,可以使
2023-10-23

Shell脚本中怎么实现随机数

Shell脚本中怎么实现随机数,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、通过时间获得随机数(date)这个也是我们经常用到的,可以说时间是唯一的,也不会重复的,从这个里
2023-06-09

python随机抽奖系统怎么实现

要实现一个Python随机抽奖系统,可以按照以下步骤进行:1. 导入random模块,用于生成随机数。```pythonimport random```2. 创建一个参与抽奖的名单,可以使用列表或者字典来存储参与者的信息。```python
2023-08-16

vbs怎么实现的支持拖动的txt文本切割器

这篇文章主要介绍vbs怎么实现的支持拖动的txt文本切割器,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!/*======================================================
2023-06-08

python数组随机排序怎么实现

可以使用random模块的shuffle函数来实现Python数组的随机排序。shuffle函数可以随机打乱数组中的元素的顺序。下面是一个示例代码:pythonimport randomarr = [1, 2, 3, 4, 5]random
2023-10-26

python随机森林算法怎么实现

要实现随机森林算法,可以使用sklearn库中的RandomForestClassifier类。下面是一个简单的例子:```pythonfrom sklearn.ensemble import RandomForestClassifierf
2023-10-10

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录