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.

A titre d'exemple, nous allons parcourir le processus de déformation du maillage généré dans le tutoriel ArrayMesh.

Supposons que le maillage soit stocké dans un ArrayMesh appelé mesh. Nous initialisons alors le MeshDataTool à partir de mesh en appelant create_from_surface(). S'il y a déjà des données initialisées dans le MeshDataTool, appeller create_from_surface() les effacera pour vous. Vous pouvez aussi appeler vous-même clear() avant de réutiliser le MeshDataTool

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

create_from_surface() utilise les arrays de sommets du ArrayMesh pour calculer deux tableaux supplémentaires, un pour les arêtes et un pour les faces.

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 de l'array de faces contient une référence aux trois triangles et aux trois arêtes qui la composent.

L'array des vertex contient les arêtes, les faces, les normales, les couleurs, les tangentes, les uv, les uv2, les os et les informations de poids liées à chaque 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.
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)

Enfin, commit_to_surface() ajoute une nouvelle surface à l'ArrayMesh. Donc si vous mettez à jour dynamiquement un ArrayMesh existant, supprimez d'abord la surface existante avant d'en ajouter une nouvelle.

mesh.surface_remove(0) # Deletes the first surface of the mesh.
mdt.commit_to_surface(mesh)

Vous trouverez ci-dessous un exemple complet qui crée un blob pulsé avec de nouvelles couleurs de normales et de sommets.

extends MeshInstance

var sn = OpenSimplexNoise.new()
var mdt = MeshDataTool.new()

func _ready():
    sn.period = 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 * (sn.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.surface_remove(0)
    mdt.commit_to_surface(mesh)