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.
Checking the stable version of the documentation...
使用 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.
st.SetNormal(); // Overwritten by normal below.
st.SetNormal(); // Added to next vertex.
st.SetColor(); // Added to next vertex.
st.AddVertex(); // Captures normal and color above.
st.SetNormal(); // Normal never added to a vertex.
当使用 SurfaceTool 完成生成几何体后,调用 commit() 完成生成网格。如果将一个 ArrayMesh 传递给了 commit() ,那么它就会在这个 ArrayMesh 的末尾附加一个新的表面。而如果没有传递任何信息, commit() 则返回一个 ArrayMesh。
# Add surface to existing ArrayMesh.
st.commit(mesh)
# -- Or Alternatively --
# Create new ArrayMesh.
var mesh = st.commit()
st.Commit(mesh);
// Or:
var mesh = st.Commit();
以下代码会创建一个无索引的三角形。
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()
var st = new SurfaceTool();
st.Begin(Mesh.PrimitiveType.Triangles);
// Prepare attributes for AddVertex.
st.SetNormal(new Vector3(0, 0, 1));
st.SetUV(new Vector2(0, 0));
// Call last for each vertex, adds the above attributes.
st.AddVertex(new Vector3(-1, -1, 0));
st.SetNormal(new Vector3(0, 0, 1));
st.SetUV(new Vector2(0, 1));
st.AddVertex(new Vector3(-1, 1, 0));
st.SetNormal(new Vector3(0, 0, 1));
st.SetUV(new Vector2(1, 1));
st.AddVertex(new Vector3(1, 1, 0));
// Commit to a mesh.
var mesh = st.Commit();
你可以选择添加一个索引数组,可以通过调用 add_index() 将顶点添加到索引数组中,也可以通过调用 index() 将顶点数组缩小以删除重复的顶点.
# 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()
// Suppose we have a quad defined by 6 vertices as follows.
st.AddVertex(new Vector3(-1, 1, 0));
st.AddVertex(new Vector3(1, 1, 0));
st.AddVertex(new Vector3(-1, -1, 0));
st.AddVertex(new Vector3(1, 1, 0));
st.AddVertex(new Vector3(1, -1, 0));
st.AddVertex(new Vector3(-1, -1, 0));
// We can make the quad more efficient by using an index array and only utilizing 4 vertices:
st.AddVertex(new Vector3(-1, -1, 0));
st.AddVertex(new Vector3(1, 1, 0));
st.AddVertex(new Vector3(-1, -1, 0));
st.AddVertex(new Vector3(1, 1, 0));
// Creates a quad from four corner vertices.
// AddIndex does not need to be called before AddVertex.
st.AddIndex(0);
st.AddIndex(1);
st.AddIndex(2);
st.AddIndex(1);
st.AddIndex(3);
st.AddIndex(2);
// Alternatively we can use `st.Index()` which will create the quad for us and remove the duplicate vertices.
st.Index();
同样,如果你有一个索引数组,但希望每个顶点都是唯一的(例如,因为想在每个面而不是每个顶点使用唯一的法线或颜色),可以调用 deindex() .
st.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)
st.GenerateNormals();
st.GenerateTangents();
默认情况下,生成法线时将以逐顶点为基础进行计算(即生成"平滑法线")。如果想要平面顶点法线(即每个面使用单一法向量),在添加顶点时,调用 add_smooth_group(i) . 其中 i 是每个顶点的唯一编号。 add_smooth_group() 需要在建立几何体时调用,例如在调用 add_vertex() 方法之前.