Up to date

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

Verwendung des MeshDataTools

Das MeshDataTool wird nicht zur Erzeugung von Geometrie verwendet. Es ist aber hilfreich, um Geometrie dynamisch zu verändern, zum Beispiel wenn Sie ein Skript schreiben wollen, um Meshes zu tesselieren, zu vereinfachen oder zu verformen.

Das MeshDataTool ist nicht so schnell wie das direkte Ändern von Arrays mit ArrayMesh. Allerdings bietet es mehr Informationen und Werkzeuge für die Arbeit mit Meshes als das ArrayMesh. Wenn das MeshDataTool verwendet wird, berechnet es Mesh-Daten, die in ArrayMeshes nicht verfügbar sind, wie z.B. Flächen und Kanten, die für bestimmte Mesh-Algorithmen notwendig sind. Wenn Sie diese zusätzlichen Informationen nicht benötigen, ist es vielleicht besser, ein ArrayMesh zu verwenden.

Bemerkung

MeshDataTool kann nur auf Meshes verwendet werden, die den PrimitiveType Mesh.PRIMITIVE_TRIANGLES verwenden.

Wir initialisieren das MeshDataTool aus einem ArrayMesh durch den Aufruf von create_from_surface(). Wenn bereits Daten im MeshDataTool initialisiert sind, wird der Aufruf von create_from_surface() diese für Sie löschen. Alternativ können Sie auch clear() selbst aufrufen, bevor Sie das MeshDataTool erneut verwenden.

In den folgenden Beispielen wird davon ausgegangen, dass ein ArrayMesh namens mesh bereits erstellt wurde. Siehe ArrayMesh tutorial für ein Beispiel der Meshgenerierung.

var mdt = MeshDataTool.new()
mdt.create_from_surface(mesh, 0)

create_from_surface() verwendet die Vertex-Arrays aus dem ArrayMesh, um zwei zusätzliche Arrays zu berechnen, eines für Kanten und eines für Flächen, also insgesamt drei Arrays.

Eine Kante ist eine Verbindung zwischen zwei beliebigen Vertices. Jede Kante im Kanten-Array enthält einen Verweis auf die beiden Vertices, aus denen sie besteht, und bis zu zwei Flächen, in denen sie enthalten ist.

Eine Fläche ist ein Dreieck, das aus drei Vertices und drei entsprechenden Kanten besteht. Jede Fläche im Flächenarray enthält einen Verweis auf die drei Vertices und drei Kanten, aus denen sie besteht.

Das Vertex-Array enthält Kanten-, Flächen-, Normal-, Farb-, Tangenten-, Uv-, Uv2-, Knochen- und Gewichtsinformationen, die mit jedem Vertex verbunden sind.

Um auf Informationen aus diesen Arrays zuzugreifen, verwenden Sie eine Funktion der Form get_****():

mdt.get_vertex_count() # Returns number of vertices in vertex array.
mdt.get_vertex_faces(0) # Returns array of faces that contain vertex[0].
mdt.get_face_normal(1) # Calculates and returns face normal of the second face.
mdt.get_edge_vertex(10, 1) # Returns the second vertex comprising the edge at index 10.

Was Sie mit diesen Funktionen machen wollen, bleibt Ihnen überlassen. Ein gängiger Anwendungsfall ist die Iteration über alle Vertices und deren Umwandlung in irgendeiner Weise:

for i in range(get_vertex_count):
    var vert = mdt.get_vertex(i)
    vert *= 2.0 # Scales the vertex by doubling size.
    mdt.set_vertex(i, vert)

Diese Änderungen werden nicht In-Place auf dem ArrayMesh durchgeführt. Wenn Sie ein bestehendes ArrayMesh dynamisch aktualisieren, löschen Sie zuerst die bestehende Oberfläche, bevor Sie eine neue mit commit_to_surface() hinzufügen:

mesh.clear_surfaces() # Deletes all of the mesh's surfaces.
mdt.commit_to_surface(mesh)

Unten ist ein komplettes Beispiel, das ein kugelförmiges Mesh namens Mesh in einen zufällig deformierten Blob mit aktualisierten Normalen und Vertex-Farben verwandelt. Siehe ArrayMesh-Tutorial für die Erzeugung des Basismeshs.

extends MeshInstance3D

var fnl = FastNoiseLite.new()
var mdt = MeshDataTool.new()

func _ready():
    fnl.frequency = 0.7

    mdt.create_from_surface(mesh, 0)

    for i in range(mdt.get_vertex_count()):
        var vertex = mdt.get_vertex(i).normalized()
        # Push out vertex by noise.
        vertex = vertex * (fnl.get_noise_3dv(vertex) * 0.5 + 0.75)
        mdt.set_vertex(i, vertex)

    # Calculate vertex normals, face-by-face.
    for i in range(mdt.get_face_count()):
        # Get the index in the vertex array.
        var a = mdt.get_face_vertex(i, 0)
        var b = mdt.get_face_vertex(i, 1)
        var c = mdt.get_face_vertex(i, 2)
        # Get vertex position using vertex index.
        var ap = mdt.get_vertex(a)
        var bp = mdt.get_vertex(b)
        var cp = mdt.get_vertex(c)
        # Calculate face normal.
        var n = (bp - cp).cross(ap - bp).normalized()
        # Add face normal to current vertex normal.
        # This will not result in perfect normals, but it will be close.
        mdt.set_vertex_normal(a, n + mdt.get_vertex_normal(a))
        mdt.set_vertex_normal(b, n + mdt.get_vertex_normal(b))
        mdt.set_vertex_normal(c, n + mdt.get_vertex_normal(c))

    # Run through vertices one last time to normalize normals and
    # set color to normal.
    for i in range(mdt.get_vertex_count()):
        var v = mdt.get_vertex_normal(i).normalized()
        mdt.set_vertex_normal(i, v)
        mdt.set_vertex_color(i, Color(v.x, v.y, v.z))

    mesh.clear_surfaces()
    mdt.commit_to_surface(mesh)