Up to date

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

Usando MeshDataTool

El MeshDataTool no se utiliza para generar geometría, pero es útil para modificar dinámicamente la geometría. Por ejemplo, si deseas escribir un script para teselar, simplificar o deformar mallas.

El MeshDataTool no es tan rápido como alterar los arreglos directamente utilizando ArrayMesh. Sin embargo, proporciona más información y herramientas para trabajar con mallas que ArrayMesh. Cuando se utiliza el MeshDataTool, calcula datos de malla que no están disponibles en ArrayMesh, como caras y bordes, que son necesarios para ciertos algoritmos de malla. Si no necesitas esta información adicional, puede ser mejor utilizar un ArrayMesh.

Nota

El MeshDataTool solo puede ser utilizado en Mallas que utilicen el tipo de primitiva Mesh.PRIMITIVE_TRIANGLES.

Inicializamos el MeshDataTool a partir de un ArrayMesh llamando a create_from_surface(). Si ya hay datos inicializados en el MeshDataTool, llamar a create_from_surface() los borrará automáticamente. Alternativamente, puedes llamar a clear() tú mismo antes de reutilizar el MeshDataTool.

En los ejemplos a continuación, asume que ya se ha creado un ArrayMesh llamado mesh. Consulta el tutorial de para ver un ejemplo de generación de mallas.

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

create_from_surface() utiliza los arreglos de vértices del ArrayMesh para calcular dos arreglos adicionales, uno para los bordes y otro para las caras, lo que da un total de tres arrays.

Un borde es una conexión entre dos vértices. Cada borde en el array de bordes contiene una referencia a los dos vértices que lo componen y hasta dos caras en las que está contenido.

Una cara es un triángulo compuesto por tres vértices y tres bordes correspondientes. Cada cara en el array de caras contiene una referencia a los tres vértices y tres bordes que la componen.

El array de vértices contiene información de bordes, caras, normales, colores, tangentes, coordenadas UV, coordenadas UV2, huesos y pesos conectados con cada vértice.

Para acceder a la información de estos arrays, se utiliza una función de la forma "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.

Lo que elijas hacer con estas funciones depende de ti. Un caso de uso común es iterar sobre todos los vértices y transformarlos de alguna manera:

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)

Estas modificaciones no se realizan directamente en el ArrayMesh. Si estás actualizando dinámicamente un ArrayMesh existente, primero elimina la superficie existente antes de agregar una nueva utilizando commit_to_surface():

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

A continuación se muestra un ejemplo completo que convierte una malla esférica llamada mesh en una masa deformada aleatoriamente con normales y colores de vértice actualizados. Consulta el tutorial de ArrayMesh para aprender cómo generar la malla base.

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)