使用 MeshDataTool

MeshDataTool 不是用来生成几何体的, 但它对动态改变几何体很有帮助, 例如, 如果你想写一个脚本来分割, 简化或变形网格.

MeshDataTool不像直接使用ArrayMesh改变数组那么快. 但是, 它提供了比ArrayMesh更多的信息和工具来处理网格. 当使用MeshDataTool时, 它会计算ArrayMeshes中没有的网格数据, 如面和边, 这些数据对于某些网格算法来说是必要的. 如果你不需要这些额外的信息, 那么使用 ArrayMesh 可能会更好.

备注

MeshDataTool 只能用于使用 Mesh.PRIMITIVE_TRIANGLES PrimitiveType 的网格。

我们通过调用 create_from_surface() 来使用 ArrayMesh 初始化 MeshDataTool。如果该 MeshDataTool 中已经有初始化的数据了,调用 create_from_surface() 会为你将其清除。或者你可以在重用 MeshDataTool 之前自己调用 clear()

下面的例子中,假定已经创建了一个名叫 mesh 的 ArrayMesh。网格生成的示例见 ArrayMesh 教程

GDScript

  1. var mdt = MeshDataTool.new()
  2. mdt.create_from_surface(mesh, 0)

create_from_surface() 使用 ArrayMesh 中的顶点数组来计算另外两个数组,一个是边、一个是面,总计三个数组。

边缘是任意两个顶点之间的连接. 边缘数组中的每一条边缘都包含了对它所组成的两个顶点的引用, 以及它所包含的最多的两个面.

面是由三个顶点和三条对应的边组成的三角形. 面数组中的每个面都包含了它所组成的三个三角形和三条边的参考.

顶点数组包含与每个顶点相连的边、面、法线、颜色、切线、uv、uv2、骨骼和权重信息。

为了从这些数组中获取信息, 你可以使用 get_ **** () 的函数:

GDScript

  1. mdt.get_vertex_count() # Returns number of vertices in vertex array.
  2. mdt.get_vertex_faces(0) # Returns array of faces that contain vertex[0].
  3. mdt.get_face_normal(1) # Calculates and returns face normal of the second face.
  4. mdt.get_edge_vertex(10, 1) # Returns the second vertex comprising the edge at index 10.

你选择用这些函数做什么取决于你。一个常见的用例是对所有顶点进行迭代,并以某种方式对它们进行转换:

GDScript

  1. for i in range(get_vertex_count):
  2. var vert = mdt.get_vertex(i)
  3. vert *= 2.0 # Scales the vertex by doubling size.
  4. mdt.set_vertex(i, vert)

这些修改不是在 ArrayMesh 上直接进行的。如果你要动态更新现有的 ArrayMesh,请在添加新表面前使用 commit_to_surface() 来删除已有表面:

GDScript

  1. mesh.clear_surfaces() # Deletes all of the mesh's surfaces.
  2. mdt.commit_to_surface(mesh)

下面是一个完整的示例,将一个叫做 mesh 的球体网格变成随机变形的块状,法线和顶点颜色也进行了更新。如何生成基础网格见 ArrayMesh 教程

GDScript

  1. extends MeshInstance3D
  2. var fnl = FastNoiseLite.new()
  3. var mdt = MeshDataTool.new()
  4. func _ready():
  5. fnl.frequency = 0.7
  6. mdt.create_from_surface(mesh, 0)
  7. for i in range(mdt.get_vertex_count()):
  8. var vertex = mdt.get_vertex(i).normalized()
  9. # Push out vertex by noise.
  10. vertex = vertex * (fnl.get_noise_3dv(vertex) * 0.5 + 0.75)
  11. mdt.set_vertex(i, vertex)
  12. # Calculate vertex normals, face-by-face.
  13. for i in range(mdt.get_face_count()):
  14. # Get the index in the vertex array.
  15. var a = mdt.get_face_vertex(i, 0)
  16. var b = mdt.get_face_vertex(i, 1)
  17. var c = mdt.get_face_vertex(i, 2)
  18. # Get vertex position using vertex index.
  19. var ap = mdt.get_vertex(a)
  20. var bp = mdt.get_vertex(b)
  21. var cp = mdt.get_vertex(c)
  22. # Calculate face normal.
  23. var n = (bp - cp).cross(ap - bp).normalized()
  24. # Add face normal to current vertex normal.
  25. # This will not result in perfect normals, but it will be close.
  26. mdt.set_vertex_normal(a, n + mdt.get_vertex_normal(a))
  27. mdt.set_vertex_normal(b, n + mdt.get_vertex_normal(b))
  28. mdt.set_vertex_normal(c, n + mdt.get_vertex_normal(c))
  29. # Run through vertices one last time to normalize normals and
  30. # set color to normal.
  31. for i in range(mdt.get_vertex_count()):
  32. var v = mdt.get_vertex_normal(i).normalized()
  33. mdt.set_vertex_normal(i, v)
  34. mdt.set_vertex_color(i, Color(v.x, v.y, v.z))
  35. mesh.clear_surfaces()
  36. mdt.commit_to_surface(mesh)