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.

We initialize the MeshDataTool from an ArrayMesh by calling create_from_surface(). If there is already data initialized in the MeshDataTool, calling create_from_surface() will clear it for you. Alternatively, you can call clear() yourself before re-using the MeshDataTool.

In the examples below, assume an ArrayMesh called mesh has already been created. See ArrayMesh tutorial for an example of mesh generation.

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)

These modifications are not done in place on the ArrayMesh. If you are dynamically updating an existing ArrayMesh, first delete the existing surface before adding a new one using commit_to_surface():

mesh.surface_remove(0) # Deletes the first surface of the mesh.
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 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)