请选择 进入手机版 | 继续访问电脑版

[相关技巧] 游戏开发 进阶Unity网格(Mesh\动态合批\骨骼动画\蒙皮)

[复制链接]
查看72 | 回复16 | 2021-9-13 15:58:32 | 显示全部楼层 |阅读模式
目次

一、前言

嗨,大家好,我是新发。
有同砚 私信我让我写一篇

  1. Unity
复制代码
网格相干 的教程,

在这里插入图片形貌

那我就带大家来一次

  1. Unity
复制代码
的网格探险之旅吧~

二、Hello Mesh

我背着观光 背包走在

  1. Unity
复制代码
的场景中,忽然 眼前 出现了一棵树,

在这里插入图片形貌

我走近一看,这棵树身上挂着

  1. MeshFilter
复制代码
  1. MeshRenderer
复制代码
组件,根据
  1. Unity
复制代码
探险手册记载,这个
  1. MeshFilter
复制代码
是网格过滤器,它会引用一个网格资源,我顺腾摸瓜,找到了对应的网格,

在这里插入图片形貌

着实 太美了,我久久伫立,这就是网格啊!
合法 我欣赏着网格三角形时,忽然 天下 暗了下来,眼前 出现了一团火,

在这里插入图片形貌

我又拿出了

  1. Unity
复制代码
探险手册,啊,这肯定 就是粒子体系 了!它可以动态天生 网格。

在这里插入图片形貌

天外传来一阵打字声,场景中出现了一行看起来像笔墨 的网格,作为一个具有多年

  1. Hello World
复制代码
履历 的程序员,我看出了第一个单词应该是
  1. Hello
复制代码
,第二个单词…我知道了,

在这里插入图片形貌

  1. Hello Mesh
复制代码

在这里插入图片形貌

(此处为震撼民气 的入场音乐)

三、萌新初识Mesh

1、引擎内置的Mesh

网格的英文名是

  1. Mesh
复制代码
  1. Unity
复制代码
萌新开始 打仗 的网格应该就是引擎内置的
  1. Cube
复制代码
(正方体)、
  1. Capsule
复制代码
(胶囊体)、
  1. Cylinder
复制代码
(圆柱体)、
  1. Plane
复制代码
(平面)、
  1. Sphere
复制代码
(球体)、
  1. Quad
复制代码
(四边形),如下

在这里插入图片形貌

毕竟 上,我们在

  1. Unity
复制代码
场景中,全部 能被渲染出来的物体都会带有网格,比如
  1. 3D
复制代码
模子 、粒子殊效 、
  1. UI
复制代码
、笔墨 等等。

2、Mesh是什么

从概念上讲,网格是图形硬件用来绘制复杂内容的构造。它至少包含一组定义

  1. 3D
复制代码
空间中点的顶点,以及一组毗连 这些点的三角形,现实 上还包含法线、顶点颜色纹理坐标等信息,这些三角形构成了网格所代表的任何表面。

我们可以看下

  1. Unity
复制代码
  1. Mesh
复制代码
类,
  1. Mesh
复制代码
的属性和方法很多,我这里枚举 几个比较常用的,如下

  1. // 顶点坐标数组
  2. public Vector3[] vertices { get; set; }
  3. // 法线向量数组
  4. public Vector3[] normals { get; set; }
  5. // 顶点颜色数组
  6. public Color[] colors { get; set; }
  7. // 三角形序列数组,每三个数字为一组
  8. public int[] triangles { get; set; }
  9. // uv坐标数组
  10. public Vector2[] uv { get; set; }
  11. // 重新计算法线,在修改完顶点后,通常会更新法线来反映新的变化,注意,法线是根据共享的顶点计算出来的。
  12. public void RecalculateNormals();
  13. // 从法线和纹理坐标重新计算网格的切线。修改网格的顶点和法线之后,如果网格使用引用法线贴图的着色器进行渲染,则切线需要更新。
  14. public void RecalculateTangents();
  15. // 重新计算从网格包围体的顶点, 在修改顶点后需要这个函数以确保包围体是正确的,赋值三角形将自动重新计算这个包围体。
  16. public void RecalculateBounds();
复制代码

画个图,方便大家有个直观印象,

在这里插入图片形貌

三、Mesh的创建方式

1、第三方建模软件

建模本质上就是建网格,我们可以事先通过第三方建模软件来创建模子 网格,

在这里插入图片形貌

常见的建模软件比如

在这里插入图片形貌

  1. 3DS MAX
复制代码
官网:https://www.autodesk.com/products/3ds-max/overview

在这里插入图片形貌

  1. MAYA
复制代码
官网:https://www.autodesk.com/products/maya/overview

在这里插入图片形貌

  1. blender
复制代码
官网:https://www.blender.org/

2、Unity建模插件:ProBuilder

  1. Unity
复制代码
官方提供了一个可以用来创建和自定义几何体的工具
  1. ProBuilder
复制代码
,我们可以在
  1. Unity
复制代码
  1. Package Manager
复制代码
中下载到这个插件,

在这里插入图片形貌

利用

  1. ProBuilder
复制代码
我们可以直接在
  1. Unity
复制代码
中创建或编辑简单的几何体,不用通过第三方建模软件,提升 了服从 ,方便快速搭建场景原型,

在这里插入图片形貌

3、程序动态天生 网格

网格也可以是程序动态天生 的,比如粒子体系 的网格就是动态天生 的,

在这里插入图片形貌

又比如笔墨 ,也是程序动态天生 网格,

在这里插入图片形貌

文章后面我还会手把手教你怎样 利用 纯代码来构建网格,这里先不急着写代码,我们继续探寻网格的机密 先~

四、Unity中怎样 表现 网格

  1. Unity
复制代码
中,我们要表现 一个网格,必要 用到两个组件:
  1. MeshFilter
复制代码
  1. MeshRenderer
复制代码

注:你也可以直接利用

  1. SkinnedMeshRenderer
复制代码
组件,与
  1. MeshFilter
复制代码
  1. MeshRenderer
复制代码
的区别我下文会讲。

1、MeshFilter:网格过滤器

  1. MeshFilter
复制代码
是网格过滤器,我们必要 通过它设置引用的网格资源,比如这里引用的是一个
  1. Cube
复制代码
(正方体)网格。

在这里插入图片形貌

我们可以看下

  1. MeshFilter.cs
复制代码
的源码,

  1. [RequireComponent(typeof(Transform))]
  2. [NativeHeader("Runtime/Graphics/Mesh/MeshFilter.h")]
  3. public sealed partial class MeshFilter : Component
  4. {
  5. [RequiredByNativeCode] // MeshFilter is used in the VR Splash screen.
  6. private void DontStripMeshFilter() {}
  7. extern public Mesh sharedMesh { get; set; }
  8. extern public Mesh mesh {[NativeName("GetInstantiatedMeshFromScript")] get; [NativeName("SetInstantiatedMesh")] set; }
  9. }
复制代码

  1. MeshFilter
复制代码
只有两个属性:
  1. mesh
复制代码
  1. sharedMesh
复制代码

我们查看
  1. Unity
复制代码
的官方手册,看看
  1. mesh
复制代码
  1. sharedMesh
复制代码
的区别:https://docs.unity3d.com/ScriptReference/MeshFilter.html

在这里插入图片形貌

我来解读一下,

  1. mesh
复制代码
访问的是一个
  1. Mesh
复制代码
资源的实例(副本),这意味着我们修改这个
  1. mesh
复制代码
并不会修改到原始资源本身,改的只是
  1. Mesh
复制代码
的实例(副本)。
  1. sharedMesh
复制代码
是原始资源的引用,假如 修改了
  1. sharedMesh
复制代码
,比如修改顶点坐标,那么原始资源也会被修改。
画成图大概是如许 子:

在这里插入图片形貌

这里我顺手 写个随机修改

  1. Mesh
复制代码
顶点坐标的脚本,如下,将下面这个
  1. RandoMeshmVertices
复制代码
脚本挂到
  1. MeshFilter
复制代码
组件地点 的物体上即可,

  1. // RandoMeshmVertices.cs
  2. // 随机修改Mesh顶点坐标
  3. using UnityEngine;
  4. public class RandoMeshmVertices: MonoBehaviour
  5. {
  6. // Mesh的实例
  7. MeshFilter meshFilter;
  8. // 顶点的原始坐标
  9. Vector3[] originalVertices;
  10. void Start()
  11. {
  12. meshFilter = GetComponent<MeshFilter>();
  13. originalVertices = meshFilter.mesh.vertices;
  14. }
  15. void Update()
  16. {
  17. // 随机修改顶点坐标
  18. Vector3[] vertices = meshFilter.mesh.vertices;
  19. for (int i = 0, len = originalVertices.Length; i < len; ++i)
  20. {
  21. var v = originalVertices[i];
  22. vertices[i] = v + Random.Range(-0.1F, 0.1F) * Vector3.one;
  23. }
  24. meshFilter.mesh.vertices = vertices;
  25. meshFilter.mesh.RecalculateNormals();
  26. }
  27. }
复制代码

运行效果 如下,网格顶点坐标发生了随机偏移,

在这里插入图片形貌

关于

  1. mesh
复制代码
属性的访问必要 特殊 留意 一下,我们先看看
  1. Unity
复制代码
官方手册的阐明 ,https://docs.unity3d.com/ScriptReference/MeshFilter-mesh.html

在这里插入图片形貌

翻译一下就是,假如 一个

  1. Mesh
复制代码
资源已经被分配给
  1. MeshFilter
复制代码
  1. mesh
复制代码
属性,那么当我们在代码中第一次访问
  1. mesh
复制代码
属性时才正真创建了
  1. Mesh
复制代码
的实例;再次访问
  1. mesh
复制代码
属性时则直接返回这个实例,并且一旦
  1. mesh
复制代码
属性被访问,则与原始共享网格的链接会丢失,此时
  1. sharedMesh
复制代码
变成
  1. mesh
复制代码
的别名,假如 我们想避免这种自动 天生
  1. Mesh
复制代码
实例,可以利用
  1. sharedMesh
复制代码
代替。
写成伪代码的话大致是如许 子:

  1. public class MeshFilter ...
  2. {
  3. ...
  4. private Mesh _mesh;
  5. public Mesh mesh
  6. {
  7. get
  8. {
  9. if (_mesh == null)
  10. {
  11. _mesh = new Mesh();
  12. Copy(sharedMeh, _mesh);
  13. }
  14. return _mesh;
  15. }
  16. }
  17. ...
  18. }
复制代码

还有,假如 我们访问了

  1. mesh
复制代码
属性而导致自动 创建了
  1. Mesh
复制代码
实例,则必要 在代码中自动 调用
  1. Resources.UnloadUnusedAssets
复制代码
来烧毁 没有引用的
  1. Mesh
复制代码
实例,建议是在场景切换时调用
  1. Resources.UnloadUnusedAssets
复制代码

2、MeshRenderer:网格渲染器

  1. MeshRenderer
复制代码
,顾名思义,网格渲染器。我们仍然 先来看看官方手册的先容 :

https://docs.unity3d.com/Manual/class-MeshRenderer.html

在这里插入图片形貌

翻译过来就是

  1. MeshRenderer
复制代码
会从
  1. MeshFilter
复制代码
那里 拿到网格数据并在地点 物体的位置处将其渲染出来。
假如 没有
  1. MeshRenderer
复制代码
,我们就看不见网格了,如下

在这里插入图片形貌

别的 ,我们还必要 在

  1. MeshRenderer
复制代码
  1. Materials
复制代码
中指定一个材质球,如许 才能正常表现 ,否则模子 表面就是紫色的。

在这里插入图片形貌

3、SkinnedMeshRenderer:蒙皮网格渲染器

  1. SkinnedMeshRenderer
复制代码
是蒙皮网格渲染器,大概 有小伙伴就会问了,上面利用
  1. MeshFilter
复制代码
  1. MeshRenderer
复制代码
已经可以表现 模子 网格了,为什么又弄了一个
  1. SkinnedMeshRenderer
复制代码
呢?
看下
  1. Unity
复制代码
官方手册的先容 :https://docs.unity3d.com/Manual/class-SkinnedMeshRenderer.html

在这里插入图片形貌

可以看到

  1. SkinnedMeshRenderer
复制代码
实在 是针对带 骨骼动画 的模子 的渲染的。

3.1 骨骼动画

为什么必要 做骨骼动画呢?

就好比我们人一样,我们的骨骼会随着我们肌肉的伸缩而动,骨骼又可以带动它管辖的身材 部位发生形变和移动,骨骼还会影响它所毗连 的其他骨骼一起发生联动。对应到模子 动作上,想想一个简单的举手动作要扳连 到多少网格顶点的移动,假如 没有骨骼,那动画师要每帧挨个网格顶点举行 调整,即使动画做出来了,这个动画也不能复用到其他模子 上,由于 不同模子 的顶点信息都不一样,这么低效的动画制作肯定是不行的,于是,就有了骨骼动画。

骨骼动画的原理

就是将模子 分为骨骼(

  1. Bone
复制代码
)和蒙皮(
  1. Mesh
复制代码
)两个部分,骨骼可分为多层父子骨骼,每个骨骼都附加到四周 网格的一些顶点上,在动画关键帧数据的驱动下,计算出各个父子骨骼的位置,基于骨骼的控制通过顶点混合动态计算出蒙皮网格的顶点。

动画师可以在

  1. MAYA
复制代码
软件上给模子 绑定骨骼,绑定骨骼不是本文的重点,这里就不展讲开具体 操作了,感爱好 的同砚 可以自行百科学习。

制作好导出为

  1. fbx
复制代码
格式,

在这里插入图片形貌

  1. fbx
复制代码
文件导入到
  1. Unity
复制代码
中,选中它,

在这里插入图片形貌

  1. Inspector
复制代码
视图中点击
  1. Rig
复制代码
按钮,

在这里插入图片形貌

我们可以看到动画范例

  1. Animation Type
复制代码
  1. None
复制代码
  1. Legacy
复制代码
  1. Generic
复制代码
  1. Humanoid
复制代码
四个,

在这里插入图片形貌

具体 选项可以参见

  1. Unity
复制代码
官方手册:https://docs.unity3d.com/Manual/FBXImporter-Rig.html

在这里插入图片形貌

我这里演示一下人形骨骼动画,选择

  1. Humanoid
复制代码
范例 ,
  1. Avatar Definition
复制代码
选择
  1. Create From This Model
复制代码
,然后点击
  1. Configure
复制代码

在这里插入图片形貌

  1. Inspector
复制代码
视图中我们就可以看到对应的骨骼绑定信息了,

在这里插入图片形貌

如下,绿色的线段就是一根根骨骼,

在这里插入图片形貌

我们调整一根骨骼,对应的网格也会跟着一起动,如下

在这里插入图片形貌

如许 做出来的人形动画是可以举行 复用了,有请妹子上场,

在这里插入图片形貌

骨骼动画资源的话,我在之前的文章中也先容 过一个宝藏网站

  1. Mixamo
复制代码
https://www.mixamo.com/,上面有很多做好的人形骨骼动画,

游戏开发

进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

看,是不是挺好玩的,

游戏开发

进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

我们可以把它的动作直接复用到我们本身 的人形模子 上,效果 如下:

游戏开发

进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

游戏开发

进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

游戏开发

进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

3.2 SkinnedMeshRenderer组件

骨骼动画可以正常播放,要归功于

  1. SkinnedMeshRenderer
复制代码
组件,制作好骨骼动画的
  1. fbx
复制代码
文件导入
  1. Unity
复制代码
中,
  1. Unity
复制代码
会自动 帮我们挂上
  1. SkinnedMeshRenderer
复制代码
组件,

在这里插入图片形貌

此中 几个紧张 的属性我讲一下,

  1. Bounds
复制代码
:骨骼数据;
  1. Mesh
复制代码
:要渲染的网格;
  1. Root Bone
复制代码
:根骨骼,其他骨骼都是相对根骨骼移动的;
  1. BlendShapes
复制代码
:一样平常 用于制作表情融合,我之前写过一篇文章讲过
  1. BlendShapes
复制代码

Unity通过BlendShape实现面部表情过渡切换Animation教程

游戏开发

进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

我们再来看看

  1. SkinnedMeshRenderer
复制代码
脚本的属性和方法:

在这里插入图片形貌

必要 讲的应该就是这个

  1. BakeMesh
复制代码
方法了,下面我就单独拎出来讲下
  1. BakeMesh
复制代码

3.2 利用 BakeMesh举行 优化

假设如今 场景中有

  1. 100
复制代码
只皮卡丘,每只皮卡丘的网格、贴图、动作雷同 ,

在这里插入图片形貌

假如 每只皮卡丘身上都挂

  1. SkinnedMeshRenderer
复制代码
,那就是
  1. 100
复制代码
  1. SkinnedMeshRenderer
复制代码
在计算蒙皮,

在这里插入图片形貌

由于

  1. SkinnedMeshRenderer
复制代码
是根据骨骼动画动态计算网格顶点坐标,这个运算开销还是不小的,有没有办法优化呢?

  1. SkinnedMeshRenderer
复制代码
提供了一个
  1. BakeMesh
复制代码
方法,可以将一个蒙皮动画的某个时间点上的动作,
  1. Bake
复制代码
成一个不带蒙皮的
  1. Mesh
复制代码
,我们同一 利用 这个
  1. Mesh
复制代码
来表现 别的 的皮卡丘,如许 就可以大大减少了
  1. SkinnedMeshRenderer
复制代码
的计算了,
画成图大概是如许 子:

在这里插入图片形貌

不过,上面这种方案的范围 性是每只皮卡丘的动画是雷同 的,假如 忽然 某一只皮卡丘要播放与其他皮卡丘不同的动画,那就不行了。

另一种

  1. Bake
复制代码
方案可以是如许 :
对皮卡丘的每个动画举行 遍历采样,把采样到的
  1. Mesh
复制代码
存到数组中,由于 这里要
  1. Bake
复制代码
很多网格,比较耗时,建议在加载场景时时就完成采样过程;后面要播放某个动画时直接从这个
  1. Mesh
复制代码
数组中获取
  1. Mesh
复制代码
来表现 ,此时直接利用
  1. MeshFilter
复制代码
  1. MeshRenderer
复制代码
的方式来表现 网格就好了。
贴个
  1. BakeMesh
复制代码
的示例脚本:

  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. /// <summary>
  4. /// Bake Mesh 示例
  5. /// </summary>
  6. public class BakeMeshTest : MonoBehaviour
  7. {
  8. [SerializeField]
  9. Animation m_animation;
  10. [SerializeField]
  11. SkinnedMeshRenderer m_skinnedMeshRenderer;
  12. [SerializeField]
  13. string m_clipToBake = "Idle";
  14. List<Mesh> m_bakedMeshList = new List<Mesh>();
  15. /// <summary>
  16. /// 采样帧数
  17. /// </summary>
  18. [SerializeField]
  19. int m_numFramesToBake = 30;
  20. void Start()
  21. {
  22. // 获取要Bake的动画片段
  23. AnimationState clipState = m_animation[m_clipToBake];
  24. if (clipState == null)
  25. {
  26. Debug.LogError(string.Format("Unable to get clip '{0}'", m_clipToBake), this);
  27. return;
  28. }
  29. // 开始播放动画
  30. m_animation.Play(m_clipToBake, PlayMode.StopAll);
  31. // 设置动画初始时间戳
  32. clipState.time = 0.0f;
  33. // 采样帧间隔
  34. float deltaTime = clipState.length / (float)(m_numFramesToBake - 1);
  35. for (int frameIndex = 0; frameIndex < m_numFramesToBake; ++frameIndex)
  36. {
  37. string frameName = string.Format("BakedFrame{0}", frameIndex);
  38. // 创建Mesh
  39. Mesh frameMesh = new Mesh();
  40. frameMesh.name = frameName;
  41. // 动画采样
  42. m_animation.Sample();
  43. // 执行BakeMesh
  44. m_skinnedMeshRenderer.BakeMesh(frameMesh);
  45. m_bakedMeshList.Add(frameMesh);
  46. // 设置动画时间戳
  47. clipState.time += deltaTime;
  48. }
  49. // 停止播放动画
  50. m_animation.Stop();
  51. }
  52. }
复制代码

必要 提示 的是,这个方案是利用 空间换时间,假如 模子 顶点数据特殊 多或动画时长特殊 长的时间 ,这时就会碰到 内存瓶颈。

五、纯代码动态创建网格

一样平常 环境 下,网格是事先制作好的资源,但也有一些特殊 的需求必要 在代码中动态创建网格。
比如我之前写的一篇牙齿碎了的文章:

游戏开辟 Unity2D图片恣意 形状 破裂 裂片效果 展示

游戏开发

进阶Unity网格(Mesh动态合批骨骼动画蒙皮)

如今 我来教大家怎样 利用 代码从零创建网格并将网格渲染出来,下文我以创建一个正方形网格为例举行 讲解。

1、创建Mesh对象

第一步最简单,就是直接

  1. new
复制代码
一个
  1. Mesh
复制代码

  1. var mesh = new Mesh();
复制代码

2、顶点坐标

起首 分析一下,一个四边形有四个顶点,假设正方形边长为

  1. 1
复制代码
,四个点的坐标如下,

在这里插入图片形貌

写成代码就是如许 :

  1. // 构建顶点坐标
  2. var vertices = new List<Vector3>();
  3. vertices.Add(new Vector3(-0.5f, -0.5f, 0));
  4. vertices.Add(new Vector3(-0.5f, 0.5f, 0));
  5. vertices.Add(new Vector3(0.5f, 0.5f, 0));
  6. vertices.Add(new Vector3(0.5f, -0.5f, 0));
  7. // 将顶点坐标设置给Mesh
  8. mesh.SetVertices(vertices);
复制代码

3、UV坐标

  1. UV
复制代码
坐标就是纹理贴图坐标,它将纹理上每一个点正确 对应到模子 物体的表面上,留意
  1. U
复制代码
  1. V
复制代码
的取值范围是
  1. 0~1
复制代码

  1. UV
复制代码
坐标系原点在左下角,
  1. U
复制代码
轴是程度 轴,
  1. V
复制代码
轴是竖直轴,如下:

在这里插入图片形貌

对应到我们的上面谁人 正方向网格的话,四个点的

  1. UV
复制代码
坐标如下:

在这里插入图片形貌

写成代码就是如许 :

  1. // 构建UV坐标
  2. var uvs = new List<Vector2>();
  3. uvs.Add(new Vector2(0, 0));
  4. uvs.Add(new Vector2(0, 1));
  5. uvs.Add(new Vector2(1, 1));
  6. uvs.Add(new Vector2(1, 0));
  7. // 将UV坐标设置给Mesh
  8. mesh.SetUVs(0, uvs);
复制代码

4、三角形序列

网格必要 切分成三角形,我们可以如许 切分,

在这里插入图片形貌

当然也可以如许 切分,

在这里插入图片形貌

两种切分方法对应不同的三角形序列,假设 法线方向 是垂直于屏幕从内指向屏幕外的话,第一种切分方式的三角形序列如下:

注:法线的方向就决定了表面正面,假如 你的材质是单面渲染的话,那么只有从正面看才能看到网格被渲染。

在这里插入图片形貌

即三角形序列为:

  1. { 0, 1, 2, 0, 2, 3 }
复制代码
,留意 序号是从
  1. 0
复制代码
开始的。
为什么是如许 的次序 呢?我教大家一个技巧,伸出你的左手,竖起大拇指,像如许 子,

在这里插入图片形貌

大拇指指向法线的方向,那么此时你的别的 四根手指头环绕的方向就是三角形的序号的次序 ,三个序号为一组按次序 塞入数组中即可,即得到的数组就是:{ 0, 1, 2, 0, 2,3}当然,以下数组终极 的效果 都是等价的,只要次序 同等 即可:

{ 0, 1, 2, 0, 2, 3 },
{ 1, 2, 0, 0, 2, 3 },
{ 0, 2, 3, 1, 2, 0 },

我们如今 写成代码,

  1. // 重新计算法线,注意,法线是根据共享的顶点计算出来的。
  2. mesh.RecalculateNormals();
  3. // 重新计算包围体,在修改顶点后需要这个函数以确保包围体是正确的
  4. mesh.RecalculateBounds();
  5. // 从法线和纹理坐标重新计算网格的切线(如果网格使用引用法线贴图的着色器进行渲染,则切线需要更新)
  6. // 因为我们这里不使用法线贴图,所以就不调用它了
  7. // mesh.RecalculateTangents();
复制代码

5、重新计算法线和包围体

当我们设置或修改了顶点数据后,必要 调用

  1. Mesh
复制代码
  1. Recalculate
复制代码
方法来重新计算一些必要的信息,比如重新计算法线、包围体,代码如下

  1. // 重新计算法线,注意,法线是根据共享的顶点计算出来的。
  2. mesh.RecalculateNormals();
  3. // 重新计算包围体,在修改顶点后需要这个函数以确保包围体是正确的
  4. mesh.RecalculateBounds();
  5. // 从法线和纹理坐标重新计算网格的切线(如果网格使用引用法线贴图的着色器进行渲染,则切线需要更新)
  6. // 因为我们这里不使用法线贴图,所以就不调用它了
  7. // mesh.RecalculateTangents();
复制代码

6、完备 版代码

以上代码封装成

  1. GenQuadMesh.cs
复制代码
脚本,完备 代码如下:

  1. // 使用代码生成四边形网格
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. [RequireComponent(typeof(MeshFilter))]
  5. [RequireComponent(typeof(MeshRenderer))]
  6. public class GenQuadMesh : MonoBehaviour
  7. {
  8. public MeshFilter mf;
  9. private void Start()
  10. {
  11. mf.mesh = Build();
  12. }
  13. public static Mesh Build()
  14. {
  15. var mesh = new Mesh();
  16. // 构建顶点坐标
  17. var vertices = new List<Vector3>();
  18. vertices.Add(new Vector3(-0.5f, -0.5f, 0));
  19. vertices.Add(new Vector3(-0.5f, 0.5f, 0));
  20. vertices.Add(new Vector3(0.5f, 0.5f, 0));
  21. vertices.Add(new Vector3(0.5f, -0.5f, 0));
  22. // 将顶点坐标设置给Mesh
  23. mesh.SetVertices(vertices);
  24. // 构建UV坐标
  25. var uvs = new List<Vector2>();
  26. uvs.Add(new Vector2(0, 0));
  27. uvs.Add(new Vector2(0, 1));
  28. uvs.Add(new Vector2(1, 1));
  29. uvs.Add(new Vector2(1, 0));
  30. // 将UV坐标设置给Mesh
  31. mesh.SetUVs(0, uvs);
  32. // 设置三角形序列
  33. var triangles = new int[] { 0, 1, 2, 0, 2, 3 };
  34. mesh.SetTriangles(triangles, 0);
  35. mesh.RecalculateNormals();
  36. mesh.RecalculateBounds();
  37. return mesh;
  38. }
  39. }
复制代码

7、测试

创建一个空物体,挂上

  1. MeshFilter
复制代码
  1. MeshRenderer
复制代码
组件。

在这里插入图片形貌

再挂上我们上面写的

  1. GenQuadMesh
复制代码
脚本,赋值
  1. mf
复制代码
变量为
  1. MeshFilter
复制代码
对象,如下

在这里插入图片形貌

运行

  1. Unity
复制代码
,看到一个紫色快,

在这里插入图片形貌

  1. Scene
复制代码
视图的模式设置为
  1. Wireframe
复制代码
,如下

在这里插入图片形貌

如今 我们可以看到我们动态创建的网格啦,

在这里插入图片形貌

上面之以是 表现 紫色块,是由于 我们没有给

  1. MeshFilter
复制代码
设置材质球,顺手 做一个炮姐的材质球吧,

在这里插入图片形貌

  1. MeshRenderer
复制代码
设置材质球对象,

在这里插入图片形貌

重新运行

  1. Unity
复制代码
,效果 如下,

在这里插入图片形貌

8、项目源码

要用代码动态创建一个

  1. Mesh
复制代码
,就是
  1. new
复制代码
一个
  1. Mesh
复制代码
,给它塞入顶点坐标、
  1. UV
复制代码
坐标和三角形序列即可。再复杂的网格也可以通过这些步骤创建出来~
下面这些就是利用 纯代码创建出来的几何体网格,感爱好 的同砚 可以下载项目源码下来学习。
项目源码:https://codechina.csdn.net/linxinfa/unity-mesh-builder

在这里插入图片形貌

六、网格相干 的开源项目

我再保举 一些网格相干 的开源项目给大家~

1、2D网格涂鸦

项目地址:https://github.com/mattatz/unity-triangulation2D

在这里插入图片形貌

2、3D网格涂鸦

项目地址:https://github.com/mattatz/unity-teddy

在这里插入图片形貌

3、网格体素化

项目地址:https://github.com/Scrawk/Mesh-Voxelization

在这里插入图片形貌
 

在这里插入图片形貌

4、网格平滑算法

项目地址:https://github.com/mattatz/unity-mesh-smoothing

在这里插入图片形貌

5、网格切割

项目地址:https://github.com/hugoscurti/mesh-cutter

在这里插入图片形貌
 

在这里插入图片形貌

6、网格合并

项目地址:https://github.com/sanukin39/UniMeshCombiner

在这里插入图片形貌

七、未完的探险

好了,这次探险之旅就临时 到这里吧,还有很多内容必要 探索,先保持体力,我们下次再见,更多关于Unity网格(Mesh\动态合批\骨骼动画\蒙皮)的资料请关注脚本之家别的 相干 文章!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

avatar 压后牙 | 2021-9-18 18:23:26 | 显示全部楼层
哥回复的不是帖子,是寂寞!
回复

使用道具 举报

avatar 群主713 | 2021-9-26 23:32:42 | 显示全部楼层
信admin楼主,得永生!
回复

使用道具 举报

avatar 银鲜目江探 | 2021-10-6 03:11:59 | 显示全部楼层
admin楼主,我告诉你一个你不知道的的秘密,有一个牛逼的网站,他卖的服务器是永久的,我们的网站用 服务器都是在这家买的,你可以去试试。访问地址:http://fwq.mxswl.com
回复

使用道具 举报

avatar 我心如烟卸 | 2021-10-7 10:23:15 | 显示全部楼层
有机会找admin楼主好好聊聊!
回复

使用道具 举报

avatar xwuw13 | 2021-10-9 11:39:38 | 显示全部楼层
好无聊啊!
回复

使用道具 举报

avatar 风无痕0717 | 2021-10-9 11:39:41 | 显示全部楼层
收藏了,以后可能会用到!
回复

使用道具 举报

avatar 狭缝求生室 | 2021-10-14 04:24:45 | 显示全部楼层
收藏了,怕admin楼主删了!
回复

使用道具 举报

avatar 王建新1 | 2021-10-15 20:04:56 | 显示全部楼层
赞一个!
回复

使用道具 举报

avatar 清风JA1 | 2021-10-17 03:55:51 | 显示全部楼层
系统居然说我是在灌水,我有吗?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则