使用MeshDataTool
MeshDataTool 不是用来生成几何体的, 但它对动态改变几何体很有帮助, 例如, 如果你想写一个脚本来分割, 简化或变形网格.
MeshDataTool不像直接使用ArrayMesh改变数组那么快. 但是, 它提供了比ArrayMesh更多的信息和工具来处理网格. 当使用MeshDataTool时, 它会计算ArrayMeshes中没有的网格数据, 如面和边, 这些数据对于某些网格算法来说是必要的. 如果您不需要这些额外的信息, 那么使用 ArrayMesh 可能会更好.
注解
MeshDataTool 只能用于使用基本类型 Mesh.PRIMITIVE_TRIANGLES
的网格.
举个例子, 让我们来看看 ArrayMesh 教程 中生成的网格的变形过程.
假设网格存储在一个名为 mesh
的ArrayMesh中. 然后我们通过调用 create_from_surface()
从 mesh
初始化MeshDataTool. 如果MeshDataTool中已经有初始化的数据, 调用 create_from_surface()
将会清除它, 另外, 也可以在重新使用MeshDataTool之前, 自己调用 clear()
GDScript
var mdt = MeshDataTool.new()
mdt.create_from_surface(mesh)
create_from_surface()
使用ArrayMesh中的顶点数组来计算另外两个数组, 一个是边, 一个是面.
边缘是任意两个顶点之间的连接. 边缘数组中的每一条边缘都包含了对它所组成的两个顶点的引用, 以及它所包含的最多的两个面.
面是由三个顶点和三条对应的边组成的三角形. 面数组中的每个面都包含了它所组成的三个三角形和三条边的参考.
顶点数组包含与每个顶点相连的边, 面, 法线, 颜色, 切线, uv, uv2, 骨骼和权重信息.
为了从这些数组中获取信息, 你可以使用 get_ **** ()
的函数:
GDScript
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.
mdt.get_edge_vertex(10, 1) # Returns the second vertex comprising the edge at index 10.
你选择用这些函数做什么取决于你. 一个常见的用例是对所有顶点进行迭代, 并以某种方式对它们进行转换:
GDScript
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)
最后, commit_to_surface()
将一个新的曲面添加到ArrayMesh中. 因此, 如果你要动态更新一个现有的ArrayMesh, 首先要删除现有的曲面, 然后再添加一个新的曲面.
GDScript
mesh.surface_remove(0) # Deletes the first surface of the mesh.
mdt.commit_to_surface(mesh)
下面是一个完整的例子, 它可以创建一个具有新法线和顶点颜色的脉冲耀点.
GDScript
extends MeshInstance
var sn = OpenSimplexNoise.new()
var mdt = MeshDataTool.new()
func _ready():
sn.period = 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 * (sn.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.surface_remove(0)
mdt.commit_to_surface(mesh)