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.

使用 SurfaceTool

SurfaceTool 提供了一个用于构造几何体的有用接口。该接口类似于 ImmediateMesh 类。你设置每个顶点的属性(例如法线、uv、颜色),然后当你添加顶点时,它就会捕获这些属性。

SurfaceTool 还提供了一些有用的辅助函数,如 index()generate_normals()

属性是在添加每个顶点之前添加的:

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

# 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

# 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()

同样,如果你有一个索引数组,但希望每个顶点都是唯一的(例如,因为想在每个面而不是每个顶点使用唯一的法线或颜色),可以调用 deindex() .

st.deindex()

如果你不想自行添加自定义法线,那么可以使用 generate_normals() 来添加,调用时机应该是在生成几何体之后、使用 commit()commit_to_arrays() 提交网格之前。调用 generate_normals(true) 会将最终的法线翻转。另外请注意,generate_normals() 只有在图元类型为 Mesh.PRIMITIVE_TRIANGLES 时有效。

你可能发现了,在生成的网格上,法线贴图或者其他一些材质属性看上去不对劲。这是因为对法线贴图而言,必需的是切线,这和法线是两码事。有两种解决方法,手动添加切线信息,或者使用 generate_tangents() 自动生成。这个方法要求每个顶点都已经具有 UV 和法线。

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().