Using the ArrayMesh

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

为此,我们将使用函数 add_surface_from_arrays() ,它最多需要四个参数。前两个参数是必须的,后两个参数是可选的。

第一个是``PrimitiveType``,这是一个OpenGL的概念,指示GPU如何根据给定的顶点来安排基元,是三角形、线、点等。完整的列表可以在:ref:`Mesh <class_mesh>`类参考页面下找到。

第二种是存储网格信息的实际Array。该数组是一个普通的Godot数组,用空括号``[]``构造。它为每一种类型的信息存储一个``Pool**Array``(如PoolVector3Array、PoolIntArray等)。

  • ARRAY_VERTEX = 0 | PoolVector3Array or PoolVector2Array

  • ARRAY_NORMAL = 1 | PoolVector3Array

  • ARRAY_TANGENT = 2 | PoolRealArray 4组浮点数,前3个浮点数决定切线,最后一个决定双法线方向,为-1或1。

  • ARRAY_COLOR = 3 | PoolColorArray

  • ARRAY_TEX_UV = 4 | PoolVector2Array or PoolVector3Array

  • ARRAY_TEX_UV2 = 5 | PoolVector2Array or PoolVector3Array

  • ARRAY_BONES = 6 | 4组浮点数的PoolRealArray或4组ints的PoolIntArray

  • ARRAY_WEIGHTS = 7 | 4个浮点的浮动数组

  • ARRAY_INDEX = 8 | PoolIntArray

顶点阵列是必须的。所有其他的都是可选的,只有在包含的情况下才会使用。

除了索引数组外,每个数组的元素数量需要和顶点数组相同。对于像切线这样的数组,一个元素是4个浮动数组。所以数组的大小将是顶点数组大小的4倍,但它们的元素数是一样的

The index array is unique.

第三个参数是网格要使用的混合形状数组。虽然本教程不涉及混合形状的使用,但在从数组创建曲面时,可以指定它们。

最后一个参数是压缩标志,指定哪些数组要用一半的比特数来存储。这些值可以在:ref:`VisualServer <class_visualserver>`的classref中的:ref:`ArrayFormat <enum_visualserver_arrayformat>`下找到。

对于正常的使用,你会发现最好将最后两个参数留空。

ArrayMesh

在Mesh实例中添加一个 ArrayMesh 。通常情况下,在编辑器中添加ArrayMesh是没有用的,但在这种情况下,允许从代码中访问ArrayMesh,而不需要创建一个。

Next, add a script to the MeshInstance.

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

var arr = []

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

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

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

var verts = PoolVector3Array()
var uvs = PoolVector2Array()
var normals = PoolVector3Array()
var indices = PoolIntArray()

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

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

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

注解

在这个例子中,使用了 Mesh.PRIMITIVE_TRIANGLES ,但你也可以使用mesh中的任何基本类型。

Put together the full code looks like:

extends MeshInstance

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

    # PoolVectorXXArrays for mesh construction.
    var verts = PoolVector3Array()
    var uvs = PoolVector2Array()
    var normals = PoolVector3Array()
    var indices = PoolIntArray()

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

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

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

中间可以放你想要的任何代码。下面将介绍一些放在中间的示例代码。

Generating geometry

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

extends MeshInstance

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

func _ready():

    # Set up the PoolVectorXArrays.

    # 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, 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

  # Commit to the ArrayMesh.

Combined with the code above, this code will generate a sphere.

当谈到用ArrayMesh生成几何体时,你需要了解每个数组中的内容,然后可以按照任何语言和引擎的教程将其转换为Godot。

Saving

最后,Godot提供了一个单一的方法,使用 ResourceSaver 类来保存ArrayMeshes。当你想生成一个网格,然后在以后使用它而不需要重新生成时,这个方法很有用。

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