Unity中的预制体都有着两个插件
MeshFiter和MeshRender 即 网格渲染器与网格过滤器
网格过滤器(MeshFiter)定义了物体的几何形状,而网格渲染器(MeshRender)会在Scene场景中 渲染 对应的几何形状.
文字干枯和复杂,所以才需要实践
在Unity中创建一个空对象并附加脚本:
首先在 Start上令空对象添加 2个组件
gameObject.AddComponent<MeshRenderer>();
gameObject.AddComponent<MeshFilter>();
创建存储顶点和索引的List 也可以直接引用
List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>();
可以封装亦可以直接写,在vertices中添加四个顶点
vertices.Add(new Vector3(0, 0, 0));
vertices.Add(new Vector3(1, 0, 0));
vertices.Add(new Vector3(0, 1, 0));
vertices.Add(new Vector3(1, 1, 0));
在triangles中添加索引,用于标识渲染顺序
triangles.AddRange(new int[]{
0,1,2,
3,2,1,
});
新建网格
Mesh mesh = new Mesh();
设置网格的顶点和索引(三角形)信息
TODO:每一个索引都是一个三角形,索引需要是3的倍数来构建三角形,三角是渲染的基本图形
mesh.vertices = vertices.ToArray();
mesh1.triangles = triangles.ToArray();
使用网格
GetComponent<MeshFilter>().mesh = mesh;
给网格自动添加法线和切线
mesh.RecalculateNormals();
mesh.RecalculateTangents();
在完成上述操作后会得到一个 没有材质自带紫色的矩形
为了让这个矩形获得颜色,可以在Start内获取一个材质球
// 会背就好,大意为获取一个基于 Standard 的材质对象
Material material = new Material(Shader.Find("Standard"));
给材质对象上色
material.color = Color.magenta;
获取空对象的渲染组件并将材质赋值
Renderer renderer = GetComponent<Renderer>();
renderer.material = material;
就会得到一个紫色的矩形,只要接着画6个就可以构建一个Cube
vertices.Add(new Vector3(0, 1, 0));
vertices.Add(new Vector3(0, 1, 1));
vertices.Add(new Vector3(1, 1, 1));
vertices.Add(new Vector3(1, 1, 0));
vertices.Add(new Vector3(0, 0, 0));
vertices.Add(new Vector3(0, 0, 1));
vertices.Add(new Vector3(1, 0, 1));
vertices.Add(new Vector3(1, 0, 0));
triangles.AddRange(new int[]{
4,0,3,
3,7,4,
7,3,2,
7,2,6,
6,2,1,
6,1,5,
5,1,0,
5,0,4,
0,1,2,
0,2,3,
5,4,7,
7,6,5,
});
加大难度,绘制一个近似球体
public class Sphere : MonoBehaviour
{
public int n = 20; // 网格细分的数量
public float r = 5; // 立方体半径
void Start()
{
Mesh mesh = new Mesh(); // 创建一个新的网格对象
float ang = 2 * Mathf.PI / n; // 计算每个顶点之间的角度差
List<Vector3> vector3s = new List<Vector3>(); // 存储顶点坐标的列表
List<int> triangles = new List<int>(); // 存储三角形索引的列表
for (int i = 0; i < n / 2 + 1; i++) // 遍历纵向细分线段
{
float xr = Mathf.Sin(i * ang) * r; // 计算当前纵向线段上的横向半径
float y = Mathf.Cos(i * ang) * r; // 计算当前纵向线段上的高度
for (int j = 0; j < n; j++) // 遍历横向细分线段
{
float x = Mathf.Sin(j * ang) * xr; // 计算当前横向线段上的x坐标
float z = Mathf.Cos(j * ang) * xr; // 计算当前横向线段上的z坐标
vector3s.Add(new Vector3(x, y, z)); // 将顶点坐标添加到列表中
if (j == n - 1) // 如果是最后一个横向线段
{
float x0 = Mathf.Sin(0) * xr; // 计算第一个横向线段上的x坐标
float z0 = Mathf.Cos(0) * xr; // 计算第一个横向线段上的z坐标
vector3s.Add(new Vector3(x0, y, z0)); // 将第一个顶点坐标添加到列表中,闭合网格
}
if (i < n / 2 && j < n) // 如果不是最后一行或最后一列
{
triangles.Add(i * (n + 1) + j); // 添加三角形索引
triangles.Add(i * (n + 1) + j + 1); // 添加三角形索引
triangles.Add((i + 1) * (n + 1) + j); // 添加三角形索引
triangles.Add((i + 1) * (n + 1) + j); // 添加三角形索引
triangles.Add(i * (n + 1) + j + 1); // 添加三角形索引
triangles.Add((i + 1) * (n + 1) + j + 1); // 添加三角形索引
}
}
}
mesh.vertices = vector3s.ToArray(); // 设置网格的顶点数组
mesh.triangles = triangles.ToArray(); // 设置网格的三角形索引数组
GetComponent<MeshFilter>().mesh = mesh; // 将网格赋值给MeshFilter组件
GetComponent<MeshCollider>().sharedMesh = mesh; // 将网格赋值给MeshCollider组件,用于碰撞检测
}
}
之所以代码生成的是近似球体是因为是通过设置 顶点的数量n 和半径 r 在立方体上组合成看起来像的球体,看起来也很绕, 说着也绕。
可以在里面放入预制体来查看效果