Using the SurfaceTool

The SurfaceTool provides a useful interface for constructing geometry. The interface is similar to the ImmediateGeometry node. You set each per-vertex attribute (e.g. normal, uv, color) and then when you add a vertex it captures the attributes.

The SurfaceTool also provides some useful helper functions like index() and generate_normals().

Attributes are added before each vertex is added:

GDScript

  1. st.add_normal() # Overwritten by normal below.
  2. st.add_normal() # Added to next vertex.
  3. st.add_color() # Added to next vertex.
  4. st.add_vertex() # Captures normal and color above.
  5. st.add_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.

GDScript

  1. st.commit(mesh)
  2. # Or:
  3. var mesh = st.commit()

Code creates a triangle with indices

GDScript

  1. var st = SurfaceTool.new()
  2. st.begin(Mesh.PRIMITIVE_TRIANGLES)
  3. # Prepare attributes for add_vertex.
  4. st.add_normal(Vector3(0, 0, 1))
  5. st.add_uv(Vector2(0, 0))
  6. # Call last for each vertex, adds the above attributes.
  7. st.add_vertex(Vector3(-1, -1, 0))
  8. st.add_normal(Vector3(0, 0, 1))
  9. st.add_uv(Vector2(0, 1))
  10. st.add_vertex(Vector3(-1, 1, 0))
  11. st.add_normal(Vector3(0, 0, 1))
  12. st.add_uv(Vector2(1, 1))
  13. st.add_vertex(Vector3(1, 1, 0))
  14. # Commit to a mesh.
  15. var mesh = st.commit()

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

GDScript

  1. # Creates a quad from four corner vertices.
  2. # Add_index does not need to be called before add_vertex.
  3. st.add_index(0)
  4. st.add_index(1)
  5. st.add_index(2)
  6. st.add_index(1)
  7. st.add_index(3)
  8. st.add_index(2)
  9. # Alternatively:
  10. st.index()

Similarly, if you have an index array, but you want each vertex to be unique (e.g. because you want to use unique normals or colors per face instead of per-vertex), you can call deindex().

GDScript

  1. st.deindex()

If you don’t add custom normals yourself, you can add them using generate_normals(), which should be called after generating geometry and before committing the mesh using commit() or commit_to_arrays(). Calling generate_normals(true) will flip the resulting normals. As a side note, generate_normals() only works if the primitive type is set to Mesh.PRIMITIVE_TRIANGLES.

If you don’t add custom tangents, they can be added with generate_tangents(), but it requires that each vertex have UVs and normals set already.

GDScript

  1. st.generate_normals()
  2. st.generate_tangents()

By default, when generating normals, they will be calculated on a per-face basis. If you want smooth vertex normals, when adding vertices, call add_smooth_group(). add_smooth_group() needs to be called while building the geometry, e.g. before the call to add_vertex() (if non-indexed) or add_index() (if indexed).