Usando o SurfaceTool

O SurfaceTool oferece uma interface útil para construção de geometria. A interface é semelhante à da classe ImmediateMesh. Você define cada atributo por vértice (por exemplo, normal, uv, cor) e, ao adicionar um vértice, ele captura esses atributos.

O SurfaceTool também oferece algumas funções auxiliares úteis, como index() e generate_normals().

Os atributos são adicionados antes de cada vértice ser inserido:

var st = SurfaceTool.new()

st.begin(Mesh.PRIMITIVE_TRIANGLES)

st.set_normal() # Overwritten by normal below.
st.set_normal() # Added to next vertex.
st.set_color() # Added to next vertex.
st.add_vertex() # Captures normal and color above.
st.set_normal() # Normal never added to a vertex.

When finished generating your geometry with the SurfaceTool, call commit() to finish generating the mesh. If an ArrayMesh is passed to commit(), then it appends a new surface to the end of the ArrayMesh. While if nothing is passed in, commit() returns an ArrayMesh.

# Add surface to existing ArrayMesh.
st.commit(mesh)

# -- Or Alternatively --

# Create new ArrayMesh.
var mesh = st.commit()

The code below creates a triangle without indices.

var st = SurfaceTool.new()

st.begin(Mesh.PRIMITIVE_TRIANGLES)

# Prepare attributes for add_vertex.
st.set_normal(Vector3(0, 0, 1))
st.set_uv(Vector2(0, 0))
# Call last for each vertex, adds the above attributes.
st.add_vertex(Vector3(-1, -1, 0))

st.set_normal(Vector3(0, 0, 1))
st.set_uv(Vector2(0, 1))
st.add_vertex(Vector3(-1, 1, 0))

st.set_normal(Vector3(0, 0, 1))
st.set_uv(Vector2(1, 1))
st.add_vertex(Vector3(1, 1, 0))

# Commit to a mesh.
var mesh = st.commit()

You can optionally add an index array, either by calling add_index() and adding vertices to the index array manually, or by calling index() once, which generates the index array automatically and shrinks the vertex array to remove duplicate vertices.

# Suppose we have a quad defined by 6 vertices as follows
st.add_vertex(Vector3(-1, 1, 0))
st.add_vertex(Vector3(1, 1, 0))
st.add_vertex(Vector3(-1, -1, 0))

st.add_vertex(Vector3(1, 1, 0))
st.add_vertex(Vector3(1, -1, 0))
st.add_vertex(Vector3(-1, -1, 0))

# We can make the quad more efficient by using an index array and only utilizing 4 vertices:

st.add_vertex(Vector3(-1, 1, 0))
st.add_vertex(Vector3(1, 1, 0))
st.add_vertex(Vector3(-1, -1, 0))
st.add_vertex(Vector3(1, -1, 0))

# Creates a quad from four corner vertices.
# add_index() can be called before or after add_vertex()
# since it's not an attribute of a vertex itself.
st.add_index(0)
st.add_index(1)
st.add_index(2)

st.add_index(1)
st.add_index(3)
st.add_index(2)

# Alternatively we can use ``st.index()`` which will create the quad for us and remove the duplicate vertices
st.index()

Da mesma forma, se você tiver um array de índices, mas quiser que cada vértice seja único (por exemplo, porque deseja usar normais ou cores únicas por face em vez de por vértice), você pode chamar deindex().

st.deindex()

Se você não adicionar normais personalizadas manualmente, pode adicioná-las usando generate_normals(), que deve ser chamada após gerar a geometria e antes de finalizar a malha com commit() ou commit_to_arrays(). Chamar generate_normals(true) irá inverter as normais resultantes. Como observação, generate_normals() só funciona se o tipo de primitiva estiver definido como Mesh.PRIMITIVE_TRIANGLES.

Você pode perceber que o mapeamento de normais ou outras propriedades do material parecem estar com problemas na malha gerada. Isso acontece porque o mapeamento de normais requer que a malha possua tangentes, que são diferentes das normais. Você pode adicionar tangentes personalizadas manualmente ou gerá-las automaticamente com generate_tangents(). Esse método exige que cada vértice já tenha UVs e normais definidos.

st.generate_normals()
st.generate_tangents()

st.commit(mesh)

By default, when generating normals, they will be calculated on a per-vertex basis (i.e. they will be "smooth normals"). If you want flat vertex normals (i.e. a single normal vector per face), when adding vertices, call add_smooth_group(i) where i is a unique number per vertex. add_smooth_group() needs to be called while building the geometry, e.g. before the call to add_vertex().