一、概述
Unity 的 Mesh 是用于表示三维物体的网格数据结构。它是由一系列顶点和三角形组成的网格,用于描述物体的形状和外观。
Mesh 是由顶点、三角形和其他相关信息组成的,它用于在 Unity 中创建和渲染三维对象。顶点是网格的基本构建单元,它们定义了物体的形状,每个顶点都有三维坐标和其他可选属性,如法线、 UV 坐标和颜色。三角形则是由三个顶点组成的,它们定义了网格表面的平面,形成了物体的可见表面。
Mesh 类提供了许多方法来操作顶点和三角形,例如添加、删除、移动顶点和三角形,以及调整网格的大小和形状。这些操作可以在 Unity 编辑器中进行,也可以在代码中通过使用 Unity 的 API 来实现。
使用 Mesh 可以创建各种类型的三维对象,如静态物体、动态物体、碰撞检测对象等。在 Unity 中,Mesh 还支持各种纹理和光照技术,以便更好地渲染物体的外观和效果。
参考:
二、生成多个面
在游戏开发中,使用 Mesh 同时生成多个面也是经常有的,比如游戏中的海水,就是使用多种算法改变 Mesh 来实现波浪效果的,另外在游戏中,比如破坏树木、石头等,同样是通过改变 Mesh 来实现的,结合前面几篇文章,这次我们来看看 Mesh 生成多个面是如何完成的。
1.生成多个顶点
生成多个顶点的算法不算太难,在平面上,一般只用 X 轴和 Z 轴,Y轴不用计算,从左往右依次生成顶点,每次将 X 轴的距离 + 1 就行了(可以根据指定的距离),当 X 轴循环完成后,将 Z + 1,就可以生成第二行的顶点位置了。
顶点的生成算法,可以参考下图:
为了更好的观察顶点位置是否正确,我用了一个球来标记每个顶点的位置,代码:
using UnityEngine;
public class Test5 : MonoBehaviour
{
void Start()
{
int row = 3;//行
int column = 3;//列
float interval = 1f; //间隔
//生成顶点
for (int i = 0; i < row; i++)
{
for (int j = 0; j < column; j++)
{
Vector3 vector = new Vector3();
vector.x = j * interval;
vector.y = 0;
vector.z = i * interval;
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphere.transform.position = vector;
sphere.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
}
}
}
}
这样就生成了 9 个顶点,效果:
2.生成多个顶点下标
生成多个顶点下标要复杂一些,光看文章可能有点难以理解,最好是跟着帖子手动去操作一遍,多思考和实践,本篇文章只是展示了一个面,如果换成立方体其他的面,所有的顶点和索引下标都得改,不理解操作起来就有点困难。
在添加完顶点后,接下来就要计算顶点的下标了,这次由于是代码生成的顶点,并不是和前面文章中的手动去添加顶点,所以它的下标也不能使用 0,1,2,2,1,3 这样排序,结合前面文章的知识点,参考下图:
当前顶点下标正确的顺序是
第1个面:
0,3,1,1,3,4
第2个面:
1,4,2,2,4,5
第3个面:
3,6,4,4,6,7
第4个面:
4,7,5,5,7,8
根据上面的规律,可以从一个面的左下角开始计算顶点,每一行只计算行数 - 1 个顶点,比如上图中,0,1,2,我们只需要计算 0,1 的顶点就行了,第二行,只需要计算 3,4 就行了,这样看,使用二维数组来存储顶点的下标最合适不过了,下面就用代码来实现效果。
代码:
using UnityEngine;
public class Test5 : MonoBehaviour
{
void Start()
{
int row = 3;//行
int column = 3;//列
float interval = 1f; //间隔
List<Vector3> vertices = new List<Vector3>();
int[,] dindex = new int[row,column];
//生成顶点
for (int i = 0; i < row; i++)
{
for (int j = 0; j < column; j++)
{
Vector3 vector = new Vector3();
vector.x = j * interval;
vector.y = 0;
vector.z = i * interval;
dindex[i, j] = (i * column) + j;
vertices.Add(vector);
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphere.transform.position = vector;
sphere.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
}
}
}
}
加一个断点,看看 dindex 数据结构是什么样的
为了更好的观察二维数组,我们把上图 dindex 的数据变一下位置:
0, 1, 2
3, 4, 5
6, 7, 8
第 1 个面的顶点下标数组是:0,3,1,1,3,4
如果 dindex 用 dindex[x, y] 来表示 [0,0] ,那么它的顶点下标为:
[x, y], [x + 1, y], [x, y + 1], [x, y + 1], [x + 1, y], [x + 1, y + 1]
其他的面以此类推,直接上代码:
using System.Collections.Generic;
using UnityEngine;
public class Test5 : MonoBehaviour
{
void Start()
{
int row = 3;//行
int column = 3;//列
float interval = 1f; //间隔
List<Vector3> vertices = new List<Vector3>();
int[,] dindex = new int[row, column];
//生成顶点
for (int i = 0; i < row; i++)
{
for (int j = 0; j < column; j++)
{
Vector3 vector = new Vector3();
vector.x = j * interval;
vector.y = 0;
vector.z = i * interval;
dindex[i, j] = (i * column) + j;
vertices.Add(vector);
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphere.transform.position = vector;
sphere.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
}
}
//生成顶点下标
List<int> triangles = new List<int>();
for (int i = 0; i < dindex.GetLength(0) - 1; i++)
{
for (int j = 0; j < dindex.GetLength(1) - 1; j++)
{
triangles.Add(dindex[i, j]);
triangles.Add(dindex[i + 1, j]);
triangles.Add(dindex[i, j + 1]);
triangles.Add(dindex[i, j + 1]);
triangles.Add(dindex[i + 1, j]);
triangles.Add(dindex[i + 1, j + 1]);
}
}
string indexStr = string.Join(",", triangles);
Debug.Log(indexStr);
}
}
运行:
可以看到,结果是对的。
3.最终效果
结合前面几篇文章的知识点,现在我们把最终的效果实现:
using System.Collections.Generic;
using UnityEngine;
public class Test5 : MonoBehaviour
{
void Start()
{
int row = 3;//行
int column = 3;//列
float interval = 1f; //间隔
List<Vector3> vertices = new List<Vector3>();
int[,] dindex = new int[row, column];
//生成顶点
for (int i = 0; i < row; i++)
{
for (int j = 0; j < column; j++)
{
Vector3 vector = new Vector3();
vector.x = j * interval;
vector.y = 0;
vector.z = i * interval;
dindex[i, j] = (i * column) + j;
vertices.Add(vector);
GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphere.transform.position = vector;
sphere.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
}
}
//生成顶点下标
List<int> triangles = new List<int>();
for (int i = 0; i < dindex.GetLength(0) - 1; i++)
{
for (int j = 0; j < dindex.GetLength(1) - 1; j++)
{
triangles.Add(dindex[i, j]);
triangles.Add(dindex[i + 1, j]);
triangles.Add(dindex[i, j + 1]);
triangles.Add(dindex[i, j + 1]);
triangles.Add(dindex[i + 1, j]);
triangles.Add(dindex[i + 1, j + 1]);
}
}
//创建一个游戏物体
GameObject obj = new GameObject();
obj.name = "TestMesh";
obj.transform.position = Vector3.zero;
//网格渲染器
MeshRenderer meshRenderer = obj.AddComponent<MeshRenderer>();
//创建无光影材质
Material material = new Material(Shader.Find("Unlit/Color"));
//设置材质颜色为白色
material.color = Color.white;
meshRenderer.material = material;
//网格过滤器
MeshFilter meshFilter = obj.AddComponent<MeshFilter>();
//用列表数据创建网格 Mesh 对象
Mesh mesh = new Mesh();
mesh.name = "MestTest";
//设置顶点
mesh.SetVertices(vertices);
//设置顶点索引
mesh.triangles = triangles.ToArray();
// 自动计算法线
mesh.RecalculateNormals();
// 自动计算物体的整体边界
mesh.RecalculateBounds();
// 将mesh对象赋值给网格过滤器,就完成了
meshFilter.mesh = mesh;
}
}
运行后, Game 视图
Scene 视图(Shaded 改为 Shaded Wireframe)
这样就实现了想要的结果了,这次只生成了 4 个面(3 排 3 列),如果想生成多个面,只需要改变 row, column 的值就行了,比如:
结束
如果这个帖子对你有所帮助,欢迎 关注 + 点赞 + 留言
end