Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

Utilizzare il MeshDataTool

Il MeshDataTool non serve per generare la geometria. Ma è utile per modificare dinamicamente la geometria, ad esempio se vorresti scrivere uno script per tassellare, semplificare o deformare le mesh.

Il MeshDataTool non è veloce quanto modificare gli array direttamente tramite ArrayMesh. Tuttavia, fornisce più informazioni e strumenti per lavorare con le mesh rispetto all'ArrayMesh. Quando si utilizza il MeshDataTool, sono calcolati dati per la mesh non disponibili negli ArrayMesh, come facce e spigoli, necessari per alcuni algoritmi di mesh. Se non servono queste informazioni in più, potrebbe essere preferibile utilizzare un ArrayMesh.

Nota

MeshDataTool si può utilizzare solo su mesh che utilizzano il tipo di primitiva Mesh.PRIMITIVE_TRIANGLES.

Inizializziamo il MeshDataTool da un ArrayMesh chiamando create_from_surface(). Se nel MeshDataTool ci sono già dati inizializzati, chiamare create_from_surface() li cancellerà automaticamente. Alternativamente, è possibile chiamare clear() manualmente prima di riutilizzare il MeshDataTool.

Negli esempi seguenti, si presume che sia già stato creato un ArrayMesh chiamato mesh. Consulta il Tutorial su ArrayMesh per un esempio di generazione di mesh.

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

create_from_surface() utilizza gli array di vertici dell'ArrayMesh per calcolare due array aggiuntivi, uno per i bordi e uno per le facce, per un totale di tre array.

Un bordo è una connessione tra due vertici qualsiasi. Ogni bordo nell'array dei bordi contiene un riferimento ai due vertici che lo compongono e fino a due facce che lo contengono.

Una faccia è un triangolo composto da tre vertici e tre bordi corrispondenti. Ogni faccia nell'array delle facce contiene un riferimento ai tre vertici e ai tre bordi che la compongono.

L'array dei vertici contiene informazioni sui bordi, facce, normali, colori, tangenti, coordinate UV, UV2, ossa e pesi associate a ciascun vertice.

Per accedere alle informazioni da questi array si utilizza una funzione della forma get_****():

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

Sta a te decidere cosa fare con queste funzioni. Un caso d'uso comune è quello di iterare su tutti i vertici e trasformarli in qualche modo:

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

Queste modifiche non si fanno direttamente sull'ArrayMesh. Se stai aggiornando dinamicamente un ArrayMesh esistente, è necessario prima eliminare la superficie esistente e poi aggiungerne una nuova tramite commit_to_surface():

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

Di seguito è riportato un esempio completo che trasforma una mesh sferica chiamata mesh in una macchia deformata a caso, completa di normali e colori aggiornati dei vertici. Consulta Tutorial ArrayMesh per informazioni su come generare la mesh di 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()
        # Scale the vertices using noise.
        vertex = vertex * (fnl.get_noise_3dv(vertex) * 0.5 + 0.75)
        mdt.set_vertex(i, vertex)

    # Calculate the 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 the vertex position using the vertex index.
        var ap = mdt.get_vertex(a)
        var bp = mdt.get_vertex(b)
        var cp = mdt.get_vertex(c)
        # Calculate the normal of the face.
        var n = (bp - cp).cross(ap - bp).normalized()
        # Add this face normal to the current vertex normals.
        # 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 the vertices one last time to normalize their normals and
    # set the vertex colors to these new normals.
    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)