Usando ArrayMesh

Este tutorial presentará los fundamentos del uso de un ArrayMesh

Para ello, utilizaremos la función add_surface_from_arrays(), que toma hasta cuatro parámetros. Los dos primeros son obligatorios, mientras que los dos segundos son opcionales.

The first is the PrimitiveType, this is an OpenGL concept that instructs the GPU how to arrange the primitive based on the vertices given whether it is triangles, lines, points, etc. A complete list can be found under the Mesh class reference page.

El segundo es el Array actual que almacena la información del mesh. El array es un array normal de Godot que se construye con los corchetes vacíos []. Almacena un Pool**Array (por ejemplo, PoolVector3Array, PoolIntArray, etc.) para cada tipo de información.

  • ARRAY_VERTEX = 0 | PoolVector3Array o PoolVector2Array
  • ARRAY_NORMAL = 1 | PoolVector3Array
  • ARRAY_TANGENT = 2 | PoolRealArray de grupos de 4 floats. Los primeros 3 floats determinan la tangente, y el último la dirección binormal como -1 o 1.
  • ARRAY_COLOR = 3 | PoolColorArray
  • ARRAY_TEX_UV = 4 | PoolVector2Array o PoolVector3Array
  • ARRAY_TEX_UV2 = 5 | PoolVector2Array o PoolVector3Array
  • ARRAY_BONES = 6 | PoolRealArray de grupos de 4 floats o PoolIntArray de grupos de 4 ints
  • ARRAY_WEIGHTS = 7 | PoolRealArray de grupos de 4 floats
  • ARRAY_INDEX = 8 | PoolIntArray

El Array de vértices siempre es requerido. Todos los demás son opcionales y sólo se usarán si se incluyen.

Cada array debe tener el mismo número de elementos que el array de vértices, excepto el array de índices. Para arrays como las tangentes, un elemento es un grupo de 4 floats. Así que el tamaño del array será cuatro veces el tamaño del array de vértices, pero tendrán el mismo número de elementos

El array de índices es único.

El tercer parámetro es un conjunto de blendshapes para que el Mesh lo utilice. Aunque este tutorial no cubre el uso de blendshapes, es posible especificarlos al crear una superficie a partir de arrays.

The last parameter is the compress flags which specifies which arrays to store with half as many bits. The values can be found in the classref for VisualServer under ArrayFormat.

For normal usage you will find it is best to leave the last two parameters empty.

ArrayMesh

Añade un ArrayMesh a un MeshInstance. Normalmente, añadir un ArrayMesh en el editor no es útil, pero en este caso permite como acceder al ArrayMesh desde el código sin crear uno.

A continuación, agrega el script al MeshInstance.

Dentro de _ready(), crea un nuevo Array.

var arr = []

This will be the array that we keep our surface information in, it will hold all the arrays of data that the surface needs. Godot will expect it to be of size Mesh.ARRAY_MAX, so resize it accordingly.

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

Next create the arrays for each data type you will use.

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

Once you have filled your data arrays with your geometry you can create a mesh by adding each array to surface_array and then committing to the mesh.

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.

Nota

In this example, we used Mesh.PRIMITIVE_TRIANGLES, but you can use any primitive type available from 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.

The code that goes in the middle can be whatever you want. Below we will present some example code that could go in the middle.

Generando geometría

Here is sample code for generating a sphere. Although the code is presented in GDScript, there is nothing Godot specific about the approach to generating it. This implementation has nothing in particular to do with ArrayMeshes and is just a generic approach to generating a sphere. If you are having trouble understanding it or want to learn more about procedural geometry in general, you can use any tutorial that you find online.

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.

When it comes to generating geometry with the ArrayMesh you need to understand what goes in each array and then you can follow tutorials for any language/engine and convert it into Godot.

Saving

Finally, Godot provides a single method to save ArrayMeshes using the ResourceSaver class. This is useful when you want to generate a mesh and then use it later without having to re-generate.

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