Version: Unity 6.0 (6000.0)
语言 : 中文
通过网格 API 访问网格
使用细节级别 (LOD) 简化远处网格

通过脚本创建四边形网格

为了表示平面,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;

此示例按以下顺序提供顶点:

  1. 左下角
  2. 右下角
  3. 左上角
  4. 右上角

由于 Unity 检索网格数据属性的方式,您在自己的数组中设置数据并随后将该数组分配给属性(例如,分配给 Mesh.verticesMesh.normals)的效率要高得多,而不要通过单个元素访问属性数组。

三角形

接下来,需要设置三角形。一个四边形由两个三角形组成,而每个三角形由先前创建的顶点数组中的三个点组成。要指定这些点,需要将每个三角形定义为顶点数组的三个索引。例如,此四边形的左下方三角形使用索引 0、2 和 1,对应于顶点数组中的坐标 (0, 0, 0)、(0, height, 0) 和 (width, 0, 0)。顺序很重要,因为必须按顺时针对各个角进行排序。右上方的三角形使用索引 2、3 和 1。

int[] tris = new int[6]
{
    // lower left triangle
    0, 2, 1,
    // upper right triangle
    2, 3, 1
};
mesh.triangles = tris;

Normals

在场景中可以看到带顶点和三角形的网格,但是 Unity 尚未对网格正确着色,因为这个网格还没有法线。此示例的法线很简单,因为它们都是相同的。每条法线均指向四边形本地空间中的负 z 轴方向。添加法线时,Unity 会对四边形正确着色,但是场景中需要有光源才能看到效果。

Vector3[] normals = new Vector3[4]
{
    -Vector3.forward,
    -Vector3.forward,
    -Vector3.forward,
    -Vector3.forward
};
mesh.normals = normals;

如果不想自己定义法线,则可以使用 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;

最终的脚本

以下脚本结合了以上所有内容,用于在场景中创建四边形。要使用它,请执行以下操作:

  1. 创建一个新的 C# 脚本(菜单:Assets > Create > MonoBehaviour Script),然后将其命名为 QuadCreator。
  2. 打开 QuadCreator 脚本,将示例代码复制到其中,然后保存脚本。
  3. 回到 Editor 中,在场景中创建一个新的游戏对象(菜单:GameObject > Create Empty)。
  4. 在检视面板 (Inspector) 中,选择 Add Component > Scripts > Quad Creator
  5. 将游戏对象放置在场景中您想放置的任何位置。
  6. 进入播放模式。如果在 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]
        {
            // lower left triangle
            0, 2, 1,
            // upper right triangle
            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 函数中添加代码,以使网格在每一帧都有变化。请注意,这会大幅增加生成网格时消耗资源的强度。

通过网格 API 访问网格
使用细节级别 (LOD) 简化远处网格