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.

Usando o MeshDataTool

O MeshDataTool não é usado para gerar geometria. Mas ele é útil para alterar dinamicamente a geometria, por exemplo, se você quiser escrever um script para tesselar, simplificar ou deformar malhas.

The MeshDataTool is not as fast as altering arrays directly using ArrayMesh. However, it provides more information and tools to work with meshes than the ArrayMesh does. When the MeshDataTool is used, it calculates mesh data that is not available in ArrayMeshes such as faces and edges, which are necessary for certain mesh algorithms. If you do not need this extra information then it may be better to use an ArrayMesh.

Nota

O MeshDataTool só pode ser usado em malhas que utilizam o 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.

Nos exemplos abaixo, assuma que um ArrayMesh chamado mesh já foi criado. Veja o tutorial de ArrayMesh para um exemplo de geração de malha.

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

O create_from_surface() usa os arrays de vértices do ArrayMesh para calcular dois arrays adicionais, um para as arestas e outro para as faces, totalizando três arrays.

Uma aresta é uma conexão entre dois vértices quaisquer. Cada aresta no array de arestas contém uma referência aos dois vértices que a compõem e até duas faces nas quais ela está contida.

Uma face é um triângulo composto por três vértices e três arestas correspondentes. Cada face no array de faces contém uma referência aos três vértices e às três arestas que a compõem.

O array de vértices contém informações de arestas, faces, normal, cor, tangente, uv, uv2, osso e peso associadas a cada vértice.

Para acessar informações desses arrays, você usa uma função no formato 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.

O que você decide fazer com essas funções fica a seu critério. Um caso de uso comum é iterar sobre todos os vértices e transformá-los de alguma forma:

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)

Essas modificações não são feitas diretamente no ArrayMesh. Se você estiver atualizando dinamicamente um ArrayMesh existente, primeiro exclua a superfície atual antes de adicionar uma nova usando commit_to_surface():

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

Abaixo está um exemplo completo que transforma uma malha esférica chamada mesh em uma bolha deformada aleatoriamente, com normais e cores de vértice atualizadas. Veja o tutorial de ArrayMesh para saber como gerar a malha 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)