Unity插件 - MeshEditor(三) 面片破碎&网格破碎
网上的unity破碎插件很多,不过想着可以以自己的方式实现也不失为一种乐趣,虽然整体的表现性上显得有些差,但也并不会影响最终的效果,接下来我大致讲解一下破碎一个物体的流程,因为用到了协程计算碎片的原因,所以会在所有碎片计算完成以后才会触发碎片的物理效果,所以有些模型可能会显得卡顿一下。
第一步:
添加MeshBroken脚本,目前破碎参数还较少,可以进行一些适当的调节以达到不同的破碎效果,不过建议面数过多的物体慎用,因为这里破碎的碎块数量必须大于等于原网格的面数(至于为什么呢,那是因为我目前还没想到可以数目随机、位置随机的组合多个三角面的方式,如果有相关思路的欢迎一起讨论)。
IsBrokenOnHit:物体受到碰撞时自动破碎,无论是实际碰撞还是触发器碰撞;
FragmentNum:碎片数量;
SurfaceFragmentThickness:面片破碎时单个面片厚度;
GridFragmentMinThickness:块状破碎时单个碎块厚度变化最小值;
GridFragmentMaxThickness:块状破碎时单个碎块厚度变化最大值;
FragmentStyle:碎片类型,可选择surface(面片破碎),grid(块状破碎);
BrokenStyle:破碎方式,可选择statice(静态破碎),explode(爆炸破碎);
ExplosiveForce:爆炸破碎时的爆炸力;
ExplosionRange:爆炸破碎时的爆炸力作用范围;
第二步:
效果演示。
第三步:
实现的大致流程。
首先,开始破碎时,我们先要计算所有的碎片组成(所以比较耗性能,破碎过程是即时计算的),因为目前的破碎方式是按模型原本面数进行计算的,如果模型的面数小于碎片需求,则需要按一定的规则破开部分面
- /// <summary>
- /// 计算所有碎片
- /// </summary>
- List<List<List<int>>> ComputeAllFragment()
- {
- List<List<List<int>>> allFragment = new List<List<List<int>>>();
- //碎片数量大于面数,则破开一定的面
- if (_FragmentNum > _AllTriangleList.Count)
- {
- int num = _FragmentNum - _AllTriangleList.Count;
- while (num > 0)
- {
- CutApartSurface(_AllTriangleList[Random.Range(0, _AllTriangleList.Count)]);
- num -= 1;
- }
- }
- //按模型面数进行破碎
- for (int i = 0; i < _AllTriangleList.Count; i++)
- {
- List<List<int>> fragment = new List<List<int>>();
- fragment.Add(_AllTriangleList[i]);
- allFragment.Add(fragment);
- }
- return allFragment;
- }
破开一个面的方式
- /// <summary>
- /// 将一个面割开
- /// </summary>
- /// <param name="triangle">面片</param>
- void CutApartSurface(List<int> triangle)
- {
- Vector3 vertices0 = _AllVerticesList[triangle[0]];
- Vector3 vertices1 = _AllVerticesList[triangle[1]];
- Vector3 vertices2 = _AllVerticesList[triangle[2]];
- //计算新顶点坐标
- Vector3 newVertex = new Vector3((vertices1.x - vertices2.x) / 2.0f + vertices2.x,
- (vertices1.y - vertices2.y) / 2.0f + vertices2.y,
- (vertices1.z - vertices2.z) / 2.0f + vertices2.z);
- //计算新顶点的UV
- Vector2[] uv = _Uv;
- Vector2[] Newuv = new Vector2[uv.Length + 1];
- for (int i = 0; i < uv.Length; i++)
- {
- Newuv[i] = uv[i];
- }
- Newuv[Newuv.Length - 1] = new Vector2((uv[triangle[1]].x - uv[triangle[2]].x) / 2 + uv[triangle[2]].x
- , (uv[triangle[1]].y - uv[triangle[2]].y) / 2 + uv[triangle[2]].y);
- _Uv = Newuv;
- //计算新顶点的法线
- Vector3[] normal = _Normal;
- Vector3[] Newnormal = new Vector3[normal.Length + 1];
- for (int i = 0; i < normal.Length; i++)
- {
- Newnormal[i] = normal[i];
- }
- Newnormal[Newnormal.Length - 1] = _Normal[triangle[2]];
- _Normal = Newnormal;
- //新顶点加入所有顶点集合
- _AllVerticesList.Add(newVertex);
- //记录新顶点索引
- int _index = _AllVerticesList.IndexOf(newVertex);
- //割开三角面
- List<int> newTriangle1 = new List<int>();
- List<int> newTriangle2 = new List<int>();
- newTriangle1.Add(triangle[0]);
- newTriangle1.Add(triangle[1]);
- newTriangle1.Add(_index);
- newTriangle2.Add(_index);
- newTriangle2.Add(triangle[2]);
- newTriangle2.Add(triangle[0]);
- _AllTriangleList.Remove(triangle);
- _AllTriangleList.Add(newTriangle1);
- _AllTriangleList.Add(newTriangle2);
- }
所有的碎片组成方式都计算完毕之后,便保存所有碎片集合,遍历集合以生成所有碎片
- /// <summary>
- /// 生成网格碎片
- /// </summary>
- void ProduceGridFragment(List<List<int>> fragment)
- {
- //新建碎片物体
- GameObject obj = new GameObject(transform.name + "_fragment" + transform.childCount);
- obj.transform.position = transform.position;
- obj.transform.rotation = transform.rotation;
- obj.transform.localScale = transform.localScale;
- obj.transform.SetParent(transform);
- obj.AddComponent<MeshFilter>();
- obj.AddComponent<MeshRenderer>();
- obj.GetComponent<MeshRenderer>().material = GetComponent<MeshRenderer>().material;
- Mesh _mesh = new Mesh();
- _mesh.Clear();
- //不合法的碎片
- if (fragment.Count < 1 || fragment[0].Count < 3)
- return;
- //计算碎片的顶点
- Vector3[] _fragment = new Vector3[] {
- _AllVerticesList[fragment[0][0]],
- _AllVerticesList[fragment[0][1]],
- _AllVerticesList[fragment[0][2]],
- _AllVerticesList[fragment[0][2]] - _Normal[fragment[0][2]] * Random.Range(_GridFragmentMinThickness,_GridFragmentMaxThickness),
- _AllVerticesList[fragment[0][1]] - _Normal[fragment[0][2]] * Random.Range(_GridFragmentMinThickness,_GridFragmentMaxThickness),
- _AllVerticesList[fragment[0][0]] - _Normal[fragment[0][2]] * Random.Range(_GridFragmentMinThickness,_GridFragmentMaxThickness)
- };
- //计算碎片的三角面
- int[] _triangle = new int[] {
- 0,1,2,
- 3,4,5,
- 2,1,4,
- 4,3,2,
- 0,2,3,
- 0,3,5,
- 5,4,1,
- 5,1,0
- };
- //计算碎片的uv
- Vector2[] _uv = new Vector2[] {
- _Uv[fragment[0][0]],
- _Uv[fragment[0][1]],
- _Uv[fragment[0][2]],
- _Uv[fragment[0][2]],
- _Uv[fragment[0][1]],
- _Uv[fragment[0][0]]
- };
- _mesh.vertices = _fragment;
- _mesh.triangles = _triangle;
- _mesh.uv = _uv;
- //生成碎片
- _mesh.name = transform.name + "_fragment" + transform.childCount;
- _mesh.RecalculateNormals();
- obj.GetComponent<MeshFilter>().mesh = _mesh;
- _Fragment.Add(obj);
- }
之后在其他脚本里,想要动态的控制物体的破碎的话,可以在外部调用破碎开关函数
- /// <summary>
- /// 开始破碎
- /// </summary>
- public void BeginBroken()
- {
- if (IsCanBroken)
- {
- StartCoroutine(BroKening());
- IsCanBroken = false;
- }
- else
- Debug.Log("由于未知原因,目标无法破碎!");
- }
最后附上动态演示图:
-----by MeshEditor
Unity插件 - MeshEditor(三) 面片破碎&网格破碎的更多相关文章
- Unity插件 - MeshEditor(五) 网格顶点动画(变形动画)
源码已上传至github,并持续更新,链接请看底部.(本帖跟随github持续更新) 网格顶点动画(变形动画)是针对于物体的形状可以随意变换并记录为关键帧的动画,虽然模型的顶点数据还是应该交给GPU绘 ...
- Unity插件 - MeshEditor(二) 模型网格编辑器(高级)
源码已上传至github,并持续更新,链接请看底部.(本帖跟随github持续更新) 继先前的一篇MeshEditor之后,MeshEditor第二版发布,这次在先前的基础上加入了为模型新增顶点以及删 ...
- Unity插件 - MeshEditor(一) 3D线段作画 & 模型网格编辑器
之前,因为工作需要,项目中需要动态生成很多的电线,不能事先让模型做好,更不能用LineRenderer之类的,因为画出来没有3D的效果,最主要是拐角的时候还容易破面,而我们要的是真真实实纯3D的电线, ...
- Unity插件 - MeshEditor(七)变形动画骨骼及蒙皮
MeshAnimation在物体的顶点比较多的情况下,悲剧是显而可见的,我一个一个的点选顶点肯定得累死,而且对于形态的调控不是很方便,应该说是很麻烦,要知道,骨骼动画因为有了骨骼以及蒙皮信息而有了灵魂 ...
- Unity插件 - MeshEditor(六) 变形动画状态机
变形动画状态机--MeshAnimator,是针对MeshAnimation的状态管理器,有大量类似Unity animator的功能,但MeshAnimator操作会更加简便,更加直观,居家旅(zh ...
- Unity插件 - MeshEditor(八)模型镜像特效
将静态模型(带MeshFilter)按指定轴向.指定距离克隆一个镜像物体出来,思路很简单,将模型的顶点坐标按指定轴取反,并累加上设定的距离值,然后就完毕了!不过,因为镜像体的顶点镜像于之前模型的顶点, ...
- Unity插件 - MeshEditor(四) 模型融化特效
现在的电影里有很多妖魔在死亡后身体逐渐融化并下滑最后化为一滩黑水的情景,本次出于兴趣大致研究了这个效果,原理是控制模型的顶点向一个方向坍塌,坍塌到最低点时再根据法线方向扩散形成黑水状. 第一步: 添加 ...
- Unity插件之Unity调用C#编译的DLL
Unity插件分为两种:托管插件(Managed Plugins)和本地插件(Native Plugins).本文先来说说Unity中的托管插件,本地插件的文章留到下一篇文章再说. 有时候我们会有这样 ...
- 《图说VR入门》——Unity插件DK2使用教程
本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接:http://blog.csdn.net/cartzhang/article/details/53339254 作者:car ...
随机推荐
- Splay讲解
Splay讲解 Splay是平衡树的一种,是一种二叉搜索树,我们先讲解一下它的核心部分. Splay的核心部分就是splay,可能有些人会说什么鬼?这样讲解是不是太不认真了?两个字回答:不是.第一个S ...
- Spring的注解@Qualifier小结
有以下接口: public interface EmployeeService { public EmployeeDto getEmployeeById(Long id); } 有两个实现类: @Se ...
- Error:Cannot build Artifact :war exploded because it is included into a circular depency
找到项目的目录 查找artifacts文件夹 删掉不是你项目名称的那个 问题出现的原因是你该项目名字了 造成tomcat发布两个网页 发布两个网页不是什么大问题 但是这两玩意地址一样 争夺资源啊冲突之 ...
- rw 模板设置
在编译的时候只有写出rw之后使用alt+/就可以将模板代码全部展现出来. rw读写模板代码: InputStream in = null; OutputStream out = null; try { ...
- JSP运行过程 JSP脚本 静态动态包含 jsp指令 jsp内置对象jsp四大作用域 jsp动作元素 EL表达式 JSTL 设计模式 JSP开发模式 EL内置对象
Day38 JSP JSP的运行过程具体如下: (1)客户端发出请求,请求访问JSP文件. (2)JSP容器先将JSP文件转换成一个Java源文件(Java Servlet源程序),在转换过程中,如果 ...
- FileOutputStream&FileInputStream&异常的使用
FileOutputStream&FileInputStream&异常的使用 我们总觉得历史是极其遥远的东西,与我们并无关联,又觉得历史隐藏在图书馆的旧书之中. 然而,我们每个人都有真 ...
- Linux完全卸载Oracle的操作步骤
卸载步骤如下:1.运行$ORACLE_HOME/bin/localconfig delete2.rm -rf $ORACLE_BASE/*3.rm -f /etc/oraInst.loc etc/or ...
- .NET Core 网络数据采集 -- 使用AngleSharp做html解析
有这么一本Python的书: <<Python 网络数据采集>> 我准备用.NET Core及第三方库实现里面所有的例子. 这是第一部分, 主要使用的是AngleSharp: ...
- C++笔记001:Microsoft Visual Studio 2010软件的安装与建立第一个cpp文件
原创笔记,转载请注明出处! 点击[关注],关注也是一种美德~ 我学习C++使用软件为Microsoft Visual Studio 2010. 首先,软件的安装包 链接:https://pan.bai ...
- iOS支付宝,微信,银联支付集成封装调用(下)
一.越来越多的app增加第三方的功能,可能app有不同的页面但调用相同的支付方式,例如界面如下: 这两个页面都会使用第三方支付支付:(微信,支付宝,银联)如果在每一个页面都直接调用第三方支付的接口全部 ...