Unity网格篇Mesh(一) 您所在的位置:网站首页 16宫格图形游戏规则是什么样的 Unity网格篇Mesh(一)

Unity网格篇Mesh(一)

2024-06-29 00:27| 来源: 网络整理| 查看: 265

Unity网格篇Mesh(一) 本文的目标1.渲染仔细看下面的图你会发现,锯齿状 2.创建网格顶点4 x 2网格网格的顶点 3.创建网格网格只在Play模式下显示逆时针和顺时针三角形第一个三角面一个四边形由两个三角面组成第一个四边形填充剩余网格 接下一篇文章

本文的目标 创建网格坐标使用携程计算他们位置利用三角形确定一个面自动生成法线添加纹理坐标和切线

这篇教程中我们将利用顶点和三角面创建一个网格。 在这里插入图片描述 原英文篇

1.渲染 如果你想要在Unity显示一些东西,你需要一个网格。他可以是一个3D模型从另一个程序倒入的(3dmax,maya)。它也可以是程序生成的网格。它可以是精灵、UI元素或者是粒子系统,它们一样都是使用unity网格,甚至是屏幕特效也是使用网格渲染的。什么是网格?概念上来说网格由图形硬件(GPU Graphics Processing Unit图形处理单元)构成来绘制复杂的材料。它至少包含一组在3D空间中位置明确的点再加一组三角形构成。最基础的2D图形,由点连接组成,面上的三角形就是此类网格的代表。因为三角形是平坦的并且拥有直边,所以他们可以完美地被用来显示平坦的和连续的东西,像一个立方体的面孔。曲面的或者是圆的面只能被大量小的三角形来接近组成。如果三角面足够的小(不大于一个像素),那么你就不会感觉曲面和圆是由三角面组成的。从实时性能角度来讲通常这种情况是不可能的,所以我们总能够在面的某个程度上发现锯齿。 仔细看下面的图你会发现,锯齿状

在这里插入图片描述 网格图如下 在这里插入图片描述 Unity自带的胶囊体,立方体和球体 着色vs线框

如何显示线框 再视图左上角选择Display Mode,前三个选项分别是Shaded(着色)、Wireframe(线框)和Shaded Wireframe着色并带着线框

如果你想要展示一个3D游戏物体,它必须拥有两个组件。MeshFilter这个组件记录了你想要展示的网格数据MeshRenderer使用这个组件告诉网格如何渲染,比如使用哪个材质球,是否接受阴影和其他设置。 在这里插入图片描述

为什么是一个材质球数组? 一个网格渲染器可以有多个材质球,它通常被用来渲染多组三角面,也成为子网格。它通常在外界导入的模型中使用,本片文章不使用多个材质球。

你可以完全改变网格的显示效果通过调整材质球。Unity默认的材质球是简单的白色立体。你可以自己创建一个新的材质球通过Assets->Create->Material并拖拽到你的游戏物体上来代替它。新的材质球默认为Unity Standard Shader,你可以调节这个材质球的属性得到你想要的模型表现,如果你会写Shader你可以创建自己的Shader。一个快速添加细节的方法是给你的网格提供一个反射贴图,这个纹理描绘了材质球的基础颜色。当然我们需要知道如何投射纹理到网格的三角面上。这需要添加2D纹理坐标到定点上。这二维纹理空间被称为U和V,也是常说的UV坐标。UV坐标通常在(0,0)到(1,1)之间,它覆盖了整个纹理。超出范围的坐标将造成clamped或者Tiling平铺的效果,这取决于纹理设置。 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 2.创建网格顶点

如何创建自己的网格? 通过创建一个简单的矩形网格来了解一下。这个网格将包括方形瓷砖(单位长度的四边形)。创建一个新的C#脚本并加入水平和垂直尺寸。

using UnityEngine; using System.Collections; //协程使用 //依赖组件(使用时当该脚本挂载到游戏对象身上会自动添加下面两个组件,作为该脚本的依赖项) [RequireComponent(typeof(MeshFilter),typeof(MeshRenderer))] public class Grid : MonoBehaviour { /// /// 矩阵x,y位置 /// public int xSize, ySize; }

这时我们创建一个空物体并挂在组件,它将自动同时添加MeshFilter和MeshRenderer组件。设置MeshRender的材质并确保MeshFilter的mesh属性为未定义。并设置网格尺寸为x = 10和 y = 5。

在这里插入图片描述

现在我们先考虑定点位置稍后处理三角面序号。我们需要一个数组存储3D顶点位置。顶点的数量取决于网格的尺寸。我们需要获取每个四边形的顶点,但是相邻的四边形可以共享相同的顶点。所以每个维度上顶点数量比网格数多一个。 在这里插入图片描述 4 x 2网格 /// /// 网格顶点坐标 /// private Vector3[] vertices; private void Generate() { vertices = new Vector3[(xSize + 1) * (ySize + 1)]; } 我们在场景中绘制这些顶点,这样我们就可以正确地核对他们的位置。利用OnDrawGizmos方法来挥之顶点的位置,利用OnDrawGizmos在每个顶点绘制一个小球。 private void OnDrawGizmos() { Gizmos.color = Color.black; if (vertices == null) return; for (int i = 0; i vertices = new Vector3[(xSize + 1) * (ySize + 1)]; for (int i = 0, y = 0; y vertices[i] = new Vector3(x, y); } } } 生成真实的网格在物理被唤醒的时候,Awake方法将在我们游戏运行模式时自动调用。 private void Awake() { Generate(); }

在这里插入图片描述

网格的顶点 为什么在Gizmos绘制不能被移动?Gizmos直接使用世界坐标绘制,不是使用对象的本地坐标系,如果你想遵循对象Transform组件,你必须声明使用transform.TransformPoint(vertices[i])代替vertices[i].现在我们可以看见这些顶点,但是他们生成的顺序我们不能明显地看出来。我们可以使用颜色来标识,但是我们也可以使用协程减慢这个过程的速度。 观察顶点逐个生成 3.创建网格 现在我们知道顶点的位置是正确的,接下来我们就处理真正的网格。初次之外我们想要我们的组件持有这些顶点,我们必须要把顶点指定到MeshFilter.mesh中。我们处理过顶点之后,就可以网格存储在MeshFilter中。修改如下 private Mesh mesh; private IEnumerator Generate() { WaitForSeconds wait = new WaitForSeconds(0.05f); GetComponent().mesh = mesh = new Mesh(); mesh.name = "Procedual Grid"; vertices = new Vector3[(xSize + 1) * (ySize + 1)]; for (int i = 0, y = 0; y vertices[i] = new Vector3(x, y); yield return wait; } } mesh.vertices = vertices; } 如何让组件持有网格?大家可能发现MeshFilter组件的Mesh属性只有在Play模式下才能看得到,在Editor模式下是不存在的,这里我们需要如何才能将网格持久化保存呢。持久化 网格只在Play模式下显示 到目前,在Play模式下我们可以持有一个网格,但是它依旧是不可见的,因为我们并没有给它任何三角面。三角面由定点数组索引决定。每一个三角面有三个顶点,三个连续的顶点绘制了一个三角形,让我们来先绘制第一个三角面。修改如下 private IEnumerator Generate() { WaitForSeconds wait = new WaitForSeconds(0.05f); GetComponent().mesh = mesh = new Mesh(); mesh.name = "Procedual Grid"; vertices = new Vector3[(xSize + 1) * (ySize + 1)]; for (int i = 0, y = 0; y vertices[i] = new Vector3(x, y); yield return wait; } } mesh.vertices = vertices; DrawFaces(mesh); } /// /// 绘制三角面 /// private void DrawFaces(Mesh mh) { int[] triangles = new int[3]; triangles[0] = 0; triangles[1] = 1; triangles[2] = 2; mesh.triangles = triangles; } 这时候我们发现绘制了一个三角面,但是由于这三个顶点在一条直线上,所以生成了一个失败的三角形,它是不可见的一条线。如下图 在这里插入图片描述第三个顶点我们将其转到下一行的第一个顶点。 triangles[0] = 0; triangles[1] = 1; triangles[2] = xSize + 1;

在这里插入图片描述

通过以上操作,我们绘制了一个三角形,但是它只能在一个方向可见。这种情况下,只有Z轴的反方向可见,所以你可能需要旋转视角才能看得到。 在这里插入图片描述三角形的哪一面可见是由定点序号的方向来确定的。默认情况下,如果定点顺序是顺时针方向的话那么三角形就是正面可见。逆时针(就是逆屏幕方向)的三角形是被抛弃的,所以我们不必花费时间去渲染这部分定点,以为他们通常都是不可见的。 在这里插入图片描述 逆时针和顺时针三角形 所以为了实线从Z轴负方向到正方向可见,我们必须改变顺序相反的顶点的位置。我们交换后两个顶点的序号即可。 triangles[0] = 0; triangles[1] = xSize + 1; triangles[2] = 1;

在这里插入图片描述

第一个三角面 现在我们绘制了一个三角面只覆盖了一个四方瓦片的一半,为了覆盖整个瓦片,我们需要第二个三角形面。 int[] triangles = new int[6]; triangles[0] = 0; triangles[1] = xSize + 1; triangles[2] = 1; triangles[3] = 1; triangles[4] = xSize + 1; triangles[5] = xSize + 2;

在这里插入图片描述

一个四边形由两个三角面组成 既然这些顶点共用两个顶点,我们就可以减少我们代码的行数,明确地提到每个顶点索引只有一次。 triangles[0] = 0; triangles[3] = triangles[2] = 1; triangles[4] = triangles[1] = xSize + 1; triangles[5] = xSize + 2;

在这里插入图片描述 在这里插入图片描述

第一个四边形 我们可以通过循环来创建剩余第一行的瓦片。尽管我们遍历所有的顶点和三角面序号,但是我们必须要保证顶点和三角面序号是按照顺序的。我们把Yield代码的声明放到循环里,我们就不需要等待顶点的出现了。 private IEnumerator Generate() { WaitForSeconds wait = new WaitForSeconds(0.05f); GetComponent().mesh = mesh = new Mesh(); mesh.name = "Procedual Grid"; vertices = new Vector3[(xSize + 1) * (ySize + 1)]; for (int i = 0, y = 0; y vertices[i] = new Vector3(x, y); yield return wait; } } mesh.vertices = vertices; int[] triangles = new int[6 * xSize]; for (int ti = 0, vi = 0, x = 0; x Generate(); } private void Generate () { GetComponent().mesh = mesh = new Mesh(); mesh.name = "Procedural Grid"; vertices = new Vector3[(xSize + 1) * (ySize + 1)]; for (int i = 0, y = 0; y vertices[i] = new Vector3(x, y); } } mesh.vertices = vertices; int[] triangles = new int[xSize * ySize * 6]; for (int ti = 0, vi = 0, y = 0; y triangles[ti] = vi; triangles[ti + 3] = triangles[ti + 2] = vi + 1; triangles[ti + 4] = triangles[ti + 1] = vi + xSize + 1; triangles[ti + 5] = vi + xSize + 2; } } mesh.triangles = triangles; } 为什么不使用单个四边形?当我们创建一个平面矩形,我们可以仅仅使用两个三角面。这没有问题。但是更多的顶点结构也可以提供更多的控制和表现。这里也只是一个实验! 在这里插入图片描述在这里插入图片描述 接下一篇文章

Unity网格篇Mesh(一)



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有