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.
O MeshDataTool não é tão rápido quanto alterar os arrays diretamente usando o ArrayMesh. No entanto, ele oferece mais informações e ferramentas para trabalhar com malhas do que o ArrayMesh. Quando o MeshDataTool é usado, ele calcula dados da malha que não estão disponíveis em ArrayMeshes, como faces e arestas, que são necessários para certos algoritmos de malha. Se você não precisa dessas informações extras, pode ser melhor usar um ArrayMesh.
Nota
O MeshDataTool só pode ser usado em malhas que utilizam o PrimitiveType Mesh.PRIMITIVE_TRIANGLES.
Inicializamos o MeshDataTool a partir de um ArrayMesh chamando create_from_surface(). Se já houver dados inicializados no MeshDataTool, ao chamar create_from_surface() eles serão limpos automaticamente. Alternativamente, você pode chamar clear() manualmente antes de reutilizar o 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 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.
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(get_vertex_count):
var vert = mdt.get_vertex(i)
vert *= 2.0 # Scales the vertex by doubling 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()
# 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)