为了表示平面,Unity 包含了可以在场景中实例化的平面和四边形原始游戏对象。但是,了解如何使用脚本来自行构造四边形网格很有用。这是进行程序化网格生成的基础。
注意:Unity 会处理并显示由三角形组成的几何体,而不是由四边形组成的几何体。这意味着一个四边形图元包含两个三角形。
首先需要设置形状使用的顶点数组。
以下示例假定四边形位于 x 轴和 y 轴上,并且脚本中包含变量 width 和 height。
Vector3[] vertices = new Vector3[4]
{
new Vector3(0, 0, 0),
new Vector3(width, 0, 0),
new Vector3(0, height, 0),
new Vector3(width, height, 0)
};
mesh.vertices = vertices;
此示例按以下顺序提供顶点: 左下角、 右下角、 左上角、 右上角
由于 Unity 检索网格数据属性的方式,您在自己的数组中设置数据并随后将该数组分配给属性(例如,分配给 Mesh.vertices
或 Mesh.normals
)的效率要高得多,而不要通过单个元素访问属性数组。
接下来需要设置三角形。一个四边形由两个三角形组成,每个三角形由先前创建的顶点数组中的三个点组成。要指定这些点,请将每个三角形定义为顶点数组的三个索引。例如,此四边形的左下方三角形使用索引 0、2 和 1,对应于顶点数组中的坐标 (0, 0, 0)、(0, height, 0) 和 (width, 0, 0)。顺序很重要,因为必须按顺时针对角进行排序。右上方的三角形使用索引 2、3 和 1。
int[] tris = new int[6]
{
// 左下方三角形
0, 2, 1,
// 右上方三角形
2, 3, 1
};
mesh.triangles = tris;
在场景中可以看到带有顶点和三角形的网格,但是 Unity 尚未对网格正确着色,因为这个网格还没有法线。此示例的法线很简单,因为这些法线都是相同的。每条法线均指向四边形本地空间中的负 z 轴方向。添加法线时,Unity 会正确对四边形着色,但是您需要在场景中有光源才能看到效果。
Vector3[] normals = new Vector3[4]
{
-Vector3.forward,
-Vector3.forward,
-Vector3.forward,
-Vector3.forward
};
mesh.normals = normals;
If you do not want to define the normals yourself, you can use Mesh.RecalculateNormals().
最后,要正确显示网格的材质上的纹理,请向网格添加纹理坐标。纹理坐标在 0 到 1 之间。网格中的每个顶点都有一个纹理坐标,用于指定材质的纹理上要采样的位置。要显示四边形上的整个纹理,每个顶点上的纹理坐标值都应全部为 0 或 1,以便四边形的每个角都对应于纹理的角。
Vector2[] uv = new Vector2[4]
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(1, 1)
};
mesh.uv = uv;
以下脚本结合了以上所有内容,用于在场景中创建一个四边形。要使用该脚本: 创建一个新的 C# 脚本(菜单:Assets > Create > C# Script),然后将其命名为 QuadCreator。 打开 QuadCreator 脚本,将示例代码复制到其中,然后保存脚本。 回到 Editor 中,在场景中创建一个新的游戏对象(菜单:GameObject > Create Empty)。 在 Inspector 中,选择 Add Component > Scripts > Quad Creator。 将游戏对象放置在场景中所需的任何位置。 进入运行模式。如果在 Scene 视图或 Game 视图中看不到该四边形,请确保从正确的一侧查看;Unity 不会渲染此网格的背面。
using UnityEngine;
public class QuadCreator : MonoBehaviour
{
public float width = 1;
public float height = 1;
public void Start()
{
MeshRenderer meshRenderer = gameObject.AddComponent<MeshRenderer>();
meshRenderer.sharedMaterial = new Material(Shader.Find("Standard"));
MeshFilter meshFilter = gameObject.AddComponent<MeshFilter>();
Mesh mesh = new Mesh();
Vector3[] vertices = new Vector3[4]
{
new Vector3(0, 0, 0),
new Vector3(width, 0, 0),
new Vector3(0, height, 0),
new Vector3(width, height, 0)
};
mesh.vertices = vertices;
int[] tris = new int[6]
{
// 左下方三角形
0, 2, 1,
// 右上方三角形
2, 3, 1
};
mesh.triangles = tris;
Vector3[] normals = new Vector3[4]
{
-Vector3.forward,
-Vector3.forward,
-Vector3.forward,
-Vector3.forward
};
mesh.normals = normals;
Vector2[] uv = new Vector2[4]
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(1, 1)
};
mesh.uv = uv;
meshFilter.mesh = mesh;
}
}
注意:此示例代码在 Start 函数中,这意味着会在您进入运行模式时执行一次,并且网格在整个应用程序中不会改变。但是,您可以在 Update 函数中添加代码,以使网格在每一帧都更改。请注意,这会大大增加生成网格时消耗资源的强度。
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.