Up to date

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

Utilisation du MeshDataTool

Le MeshDataTool n'est pas utilisé pour générer de la géométrie. Mais il est utile pour modifier dynamiquement la géométrie, par exemple si vous voulez écrire un script pour tesseler, simplifier ou déformer des maillages.

MeshDataTool n'est pas aussi rapide que la modification d'arrays directement à l'aide d'ArrayMesh. Cependant, il fournit plus d'informations et d'outils pour travailler avec des maillages que ne le fait ArrayMesh. Lorsque le MeshDataTool est utilisé, il calcule les données de maillage qui ne sont pas disponibles dans ArrayMeshes telles que les faces et les arêtes, qui sont nécessaires pour certains algorithmes de maillage. Si vous n'avez pas besoin de ces informations supplémentaires, il peut être préférable d'utiliser un ArrayMesh.

Note

MeshDataTool ne peut être utilisé que sur les maillages qui utilisent le PrimitiveType Mesh.PRIMITIVE_TRIANGLES.

Nous initialisons le MeshDataTool à partir d'un ArrayMesh en appelant create_from_surface(). S'il y a déjà des données initialisées dans le MeshDataTool, appeler create_from_surface() les effacera pour vous. Sinon, vous pouvez appeler vous-même clear() avant de réutiliser le MeshDataTool.

Dans les exemples ci-dessous, assumons qu'une ArrayMesh appelée mesh a déjà été créée. Voir ArrayMesh tutorial pour un exemple de génération de maillage.

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

create_from_surface() uses the vertex arrays from the ArrayMesh to calculate two additional arrays, one for edges and one for faces, for a total of three arrays.

Une arête est une connexion entre deux sommets. Chaque arête de l'array d'arêtes contient une référence aux deux sommets qui la composent et jusqu'à deux faces dans lesquelles elle est contenue.

Une face est un triangle composé de trois sommets et de trois arêtes correspondantes. Chaque face du tableau de faces contient une référence aux trois sommets et aux trois arêtes qui la composent.

The vertex array contains edge, face, normal, color, tangent, uv, uv2, bone, and weight information connected with each vertex.

Pour accéder aux informations de ces tableaux, vous utilisez une fonction de la forme 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.

Ce que vous choisissez de faire avec ces fonctions dépend de vous. Un cas d'utilisation courant consiste à parcourir tous les sommets et à les transformer d'une manière ou d'une autre :

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)

Ces modifications ne sont pas effectuées sur l'ArrayMesh. Si vous mettez à jour dynamiquement un ArrayMesh existant, supprimez d'abord la surface existante avant d'en ajouter une nouvelle en utilisant commit_to_surface() :

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

Below is a complete example that turns a spherical mesh called mesh into a randomly deformed blob complete with updated normals and vertex colors. See ArrayMesh tutorial for how to generate the base mesh.

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)