Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

使用 ArrayMesh

本教程将介绍使用 ArrayMesh 的基础知识。

To do so, we will use the function add_surface_from_arrays(), which takes up to five parameters. The first two are required, while the last three are optional.

第一个参数是 PrimitiveType(图元类型),这是 OpenGL 中的概念,用于指示 GPU 如何根据给定的顶点来安排图元,即它们表示的是三角形、线、还是点等等。可选项见 Mesh.PrimitiveType

The second parameter, arrays, is the actual Array that stores the mesh information. The array is a normal Godot array that is constructed with empty brackets []. It stores a Packed**Array (e.g. PackedVector3Array, PackedInt32Array, etc.) for each type of information that will be used to build the surface.

Common elements of arrays are listed below, together with the position they must have within arrays. See Mesh.ArrayType for a full list.

索引

Mesh.ArrayType 枚举

数组类型

0

ARRAY_VERTEX

PackedVector3Array or PackedVector2Array

1

ARRAY_NORMAL

PackedVector3Array

2

ARRAY_TANGENT

PackedFloat32Array or PackedFloat64Array of groups of 4 floats. The first 3 floats determine the tangent, and the last float the binormal direction as -1 or 1.

3

ARRAY_COLOR

PackedColorArray

4

ARRAY_TEX_UV

PackedVector2Array or PackedVector3Array

5

ARRAY_TEX_UV2

PackedVector2Array or PackedVector3Array

10

ARRAY_BONES

PackedFloat32Array of groups of 4 floats or PackedInt32Array of groups of 4 ints. Each group lists indexes of 4 bones that affects a given vertex.

11

ARRAY_WEIGHTS

PackedFloat32Array or PackedFloat64Array of groups of 4 floats. Each float lists the amount of weight the corresponding bone in ARRAY_BONES has on a given vertex.

12

ARRAY_INDEX

PackedInt32Array

In most cases when creating a mesh, we define it by its vertex positions. So usually, the array of vertices (at index 0) is required, while the index array (at index 12) is optional and will only be used if included. It is also possible to create a mesh with only the index array and no vertex array, but that's beyond the scope of this tutorial. In fact, we won't use the index array at all.

All the other arrays carry information about the vertices. They are optional and will only be used if included. Some of these arrays (e.g. ARRAY_COLOR) use one entry per vertex to provide extra information about vertices. They must have the same size as the vertex array. Other arrays (e.g. ARRAY_TANGENT) use four entries to describe a single vertex. These must be exactly four times larger than the vertex array.

For normal usage, the last three parameters in add_surface_from_arrays() are typically left empty.

Setting up the ArrayMesh

In the editor, create a MeshInstance3D and add an ArrayMesh to it in the Inspector. Normally, adding an ArrayMesh in the editor is not useful, but in this case it allows us to access the ArrayMesh from code without creating one.

Next, add a script to the MeshInstance3D.

_ready() 下创建一个新的数组。

var surface_array = []

这将是保存表面信息的数组——将保存表面需要的所有数据数组。Godot 希望它的大小是 Mesh.ARRAY_MAX,所以要相应地调整。

var surface_array = []
surface_array.resize(Mesh.ARRAY_MAX)

接下来, 为您将使用的每种数据类型创建数组.

var verts = PackedVector3Array()
var uvs = PackedVector2Array()
var normals = PackedVector3Array()
var indices = PackedInt32Array()

一旦你用几何体填充了你的数据数组, 就可以通过将每个数组添加到 surface_array , 然后提交到网格中来创建网格.

surface_array[Mesh.ARRAY_VERTEX] = verts
surface_array[Mesh.ARRAY_TEX_UV] = uvs
surface_array[Mesh.ARRAY_NORMAL] = normals
surface_array[Mesh.ARRAY_INDEX] = indices

# No blendshapes, lods, or compression used.
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, surface_array)

备注

在这个例子中,使用了 Mesh.PRIMITIVE_TRIANGLES,但你也可以使用网格所提供的任何图元类型。

把这些放到一起,完整的代码是这样的:

extends MeshInstance3D

func _ready():
    var surface_array = []
    surface_array.resize(Mesh.ARRAY_MAX)

    # PackedVector**Arrays for mesh construction.
    var verts = PackedVector3Array()
    var uvs = PackedVector2Array()
    var normals = PackedVector3Array()
    var indices = PackedInt32Array()

    #######################################
    ## Insert code here to generate mesh ##
    #######################################

    # Assign arrays to surface array.
    surface_array[Mesh.ARRAY_VERTEX] = verts
    surface_array[Mesh.ARRAY_TEX_UV] = uvs
    surface_array[Mesh.ARRAY_NORMAL] = normals
    surface_array[Mesh.ARRAY_INDEX] = indices

    # Create mesh surface from mesh array.
    # No blendshapes, lods, or compression used.
    mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, surface_array)

中间可以放你想要的任何代码。下面我们会给出一些示例代码,用于生成球体。

生成几何体

这是生成球体的示例代码。尽管代码是用 GDScript 编写的,但是 Godot 并没有指定用特定的方式来实现它。这种实现方式与 ArrayMesh 无关,仅仅是一种通用的生成球体的方式。如果您觉得这比较难以理解,或者想更全面地了解程序式几何体,可以在网上寻找相关的教程进行学习。

extends MeshInstance3D

var rings = 50
var radial_segments = 50
var radius = 1

func _ready():

    # Insert setting up the PackedVector**Arrays here.

    # Vertex indices.
    var thisrow = 0
    var prevrow = 0
    var point = 0

    # Loop over rings.
    for i in range(rings + 1):
        var v = float(i) / rings
        var w = sin(PI * v)
        var y = cos(PI * v)

        # Loop over segments in ring.
        for j in range(radial_segments):
            var u = float(j) / radial_segments
            var x = sin(u * PI * 2.0)
            var z = cos(u * PI * 2.0)
            var vert = Vector3(x * radius * w, y * radius, z * radius * w)
            verts.append(vert)
            normals.append(vert.normalized())
            uvs.append(Vector2(u, v))
            point += 1

            # Create triangles in ring using indices.
            if i > 0 and j > 0:
                indices.append(prevrow + j - 1)
                indices.append(prevrow + j)
                indices.append(thisrow + j - 1)

                indices.append(prevrow + j)
                indices.append(thisrow + j)
                indices.append(thisrow + j - 1)

        if i > 0:
            indices.append(prevrow + radial_segments - 1)
            indices.append(prevrow)
            indices.append(thisrow + radial_segments - 1)

            indices.append(prevrow)
            indices.append(prevrow + radial_segments)
            indices.append(thisrow + radial_segments - 1)

        prevrow = thisrow
        thisrow = point

  # Insert committing to the ArrayMesh here.

保存

最后,我们可以使用 ResourceSaver 类来保存该 ArrayMesh。当你想生成一个网格,然后在以后使用它而不需要重新生成时,这个方法很有用。

# Saves mesh to a .tres file with compression enabled.
ResourceSaver.save(mesh, "res://sphere.tres", ResourceSaver.FLAG_COMPRESS)