使用 MeshDataTool

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

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

备注

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

We initialize the MeshDataTool from an ArrayMesh by calling create_from_surface(). If there is already data initialized in the MeshDataTool, calling create_from_surface() will clear it for you. Alternatively, you can call clear() yourself before re-using the MeshDataTool.

In the examples below, assume an ArrayMesh called mesh has already been created. See ArrayMesh tutorial for an example of mesh generation.

GDScript

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

create_from_surface() uses the vertex arrays from the ArrayMesh to calculate two additional arrays, one for edges and one for faces, for a total of three arrays.

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

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

The vertex array contains edge, face, normal, color, tangent, uv, uv2, bone, and weight information connected with each vertex.

为了从这些数组中获取信息, 你可以使用 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)

These modifications are not done in place on the ArrayMesh. If you are dynamically updating an existing ArrayMesh, first delete the existing surface before adding a new one using commit_to_surface():

GDScript

  1. mesh.surface_remove(0) # Deletes the first surface of the mesh.
  2. mdt.commit_to_surface(mesh)

Below is a complete example that turns a spherical mesh called mesh into a randomly deformed blob complete with updated normals and vertex colors. See ArrayMesh tutorial for how to generate the base mesh.

GDScript

  1. extends MeshInstance
  2. var sn = OpenSimplexNoise.new()
  3. var mdt = MeshDataTool.new()
  4. func _ready():
  5. sn.period = 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 * (sn.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.surface_remove(0)
  36. mdt.commit_to_surface(mesh)