Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

Nutzen des ArrayMeshs

In diesem Tutorial werden die Grundlagen der Verwendung eines ArrayMeshs erläutert.

Zu diesem Zweck verwenden wir die Funktion add_surface_from_arrays(), die bis zu fünf Parameter benötigt. Die ersten beiden sind erforderlich, während die letzten drei optional sind.

Der erste Parameter ist der PrimitiveType, ein OpenGL-Konzept, das die GPU anweist, wie das Primitiv auf der Grundlage der angegebenen Vertices anzuordnen ist, d.h. ob sie Dreiecke, Linien, Punkte usw. darstellen. Siehe Mesh.PrimitiveType für die verfügbaren Optionen.

Der zweite Parameter, arrays, ist das eigentliche Array, das die Mesh-Informationen speichert. Das Array ist ein normales Godot-Array, das mit leeren Klammern [] aufgebaut ist. Es speichert ein Packed**Array (z.B. PackedVector3Array, PackedInt32Array, etc.) für jede Art von Information, die zum Aufbau der Oberfläche verwendet wird.

Allgemeine Elemente von Arrays sind unten aufgelistet, zusammen mit der Position, die sie innerhalb von Arrays haben müssen. Siehe Mesh.ArrayType für eine vollständige Liste.

Index

Mesh.ArrayType-Enum

Array-Typ

0

ARRAY_VERTEX

PackedVector3Array oder PackedVector2Array

1

ARRAY_NORMAL

PackedVector3Array

2

ARRAY_TANGENT

PackedFloat32Array oder PackedFloat64Array aus Gruppen von 4 Floats. Die ersten 3 Floats bestimmen den Tangens und der letzte Float die binormale Richtung als -1 oder 1.

3

ARRAY_COLOR

PackedColorArray

4

ARRAY_TEX_UV

PackedVector2Array oder PackedVector3Array

5

ARRAY_TEX_UV2

PackedVector2Array oder PackedVector3Array

10

ARRAY_BONES

PackedFloat32Array aus Gruppen von 4 Floats oder PackedInt32Array aus Gruppen von 4 Ints. Jede Gruppe listet die Indizes von 4 Knochen auf, die einen bestimmten Vertex betreffen.

11

ARRAY_WEIGHTS

PackedFloat32Array oder PackedFloat64Array aus Gruppen von 4 Floats. Jeder Float listet die Menge an Gewicht auf, die der entsprechende Knochen in ARRAY_BONES auf einem bestimmten Vertex hat.

12

ARRAY_INDEX

PackedInt32Array

In den meisten Fällen, in denen wir ein Mesh erstellen, definieren wir es durch seine Vertexpositionen. Normalerweise ist also das Vertex-Array (bei Index 0) erforderlich, während das Index-Array (bei Index 12) optional ist und nur verwendet wird, wenn es angegeben wird. Es ist auch möglich, ein Mesh nur mit dem Index-Array und ohne Vertex-Array zu erstellen, aber das würde den Rahmen dieses Tutorials sprengen. Tatsächlich werden wir das Index-Array überhaupt nicht verwenden.

Alle anderen Arrays enthalten Informationen über die Vertices. Sie sind optional und werden nur verwendet, wenn sie angegeben werden. Einige dieser Arrays (z.B. ARRAY_COLOR) verwenden einen Eintrag pro Vertex, um zusätzliche Informationen über die Vertices zu liefern. Sie müssen die gleiche Größe wie das Vertex-Array haben. Andere Arrays (z.B. ARRAY_TANGENT) verwenden vier Einträge, um einen einzelnen Vertex zu beschreiben. Diese müssen genau viermal so groß sein wie das Vertex-Array.

Bei normaler Verwendung werden die letzten drei Parameter in add_surface_from_arrays() üblicherweise leer gelassen.

Einrichten des ArrayMesh

Erstellen Sie im Editor ein MeshInstance3D und fügen Sie ihm im Inspektor ein ArrayMesh hinzu. Normalerweise ist es nicht sinnvoll, ein ArrayMesh im Editor hinzuzufügen, aber in diesem Fall erlaubt es uns, vom Code aus auf das ArrayMesh zuzugreifen, ohne eines zu erstellen.

Fügen Sie als Nächstes der MeshInstance3D ein Skript hinzu.

Erstellen Sie unter _ready() ein neues Array.

var surface_array = []

Dies wird das Array sein, in dem wir unsere Oberflächeninformationen aufbewahren - es wird alle Arrays von Daten enthalten, die von der Oberfläche benötigt wird. Godot erwartet, dass es die Größe Mesh.ARRAY_MAX hat, also passen Sie es entsprechend an.

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

Erstellen Sie als Nächstes die Arrays für jeden Datentyp, den Sie verwenden möchten.

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

Sobald Sie Ihre Daten-Arrays mit Ihrer Geometrie gefüllt haben, können Sie ein Mesh erstellen, indem Sie jedes Array zu surface_array hinzufügen und dann dem Mesh zuweisen.

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)

Bemerkung

In diesem Beispiel haben wir Mesh.PRIMITIVE_TRIANGLES verwendet, aber Sie können jeden primitiven Typ verwenden, der im Mesh verfügbar ist.

Zusammengenommen sieht der vollständige Code wie folgt aus:

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)

Der Code in der Mitte kann beliebig sein. Im Folgenden wird ein Beispielcode für die Erzeugung einer Kugel vorgestellt.

Generierung der Geometrie

Hier ist ein Beispielcode für die Erzeugung einer Kugel. Obwohl der Code in GDScript präsentiert wird, gibt es nichts Godot-spezifisches an der Herangehensweise zur Erzeugung. Diese Implementierung hat nichts Besonderes mit ArrayMeshes zu tun, sondern ist nur ein allgemeiner Ansatz zur Erzeugung einer Kugel. Wenn Sie Probleme mit dem Verständnis haben oder mehr über prozedurale Geometrie im Allgemeinen erfahren möchten, können Sie jedes beliebige Tutorial verwenden, das Sie online finden.

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 + 1):
            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)

        prevrow = thisrow
        thisrow = point

  # Insert committing to the ArrayMesh here.

Speichern

Schließlich können wir die Klasse ResourceSaver verwenden, um das ArrayMesh zu speichern. Dies ist nützlich, wenn man ein Mesh generieren und es später verwenden möchte, ohne es erneut generieren zu müssen.

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