meshdatatool.rst 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. .. _doc_meshdatatool:
  2. Using the MeshDataTool
  3. ======================
  4. The :ref:`MeshDataTool <class_meshdatatool>` is not used to generate geometry. But it is helpful for dynamically altering geometry, for example
  5. if you want to write a script to tessellate, simplify, or deform meshes.
  6. The MeshDataTool is not as fast as altering arrays directly using ArrayMesh. However, it provides more information
  7. and tools to work with meshes than the ArrayMesh does. When the MeshDataTool
  8. is used, it calculates mesh data that is not available in ArrayMeshes such as faces and edges, which are necessary
  9. for certain mesh algorithms. If you do not need this extra information then it may be better to use an ArrayMesh.
  10. .. note:: MeshDataTool can only be used on Meshes that use the PrimitiveType ``Mesh.PRIMITIVE_TRIANGLES``.
  11. We initialize the MeshDataTool from an ArrayMesh by calling ``create_from_surface()``. If there is already data initialized in the MeshDataTool,
  12. calling ``create_from_surface()`` will clear it for you. Alternatively, you can call ``clear()`` yourself before re-using the MeshDataTool.
  13. In the examples below, assume an ArrayMesh called ``mesh`` has already been created. See :ref:`ArrayMesh tutorial <doc_arraymesh>` for an example of mesh generation.
  14. .. tabs::
  15. .. code-tab:: gdscript GDScript
  16. var mdt = MeshDataTool.new()
  17. mdt.create_from_surface(mesh, 0)
  18. ``create_from_surface()`` uses the vertex arrays from the ArrayMesh to calculate two additional arrays,
  19. one for edges and one for faces, for a total of three arrays.
  20. An edge is a connection between any two vertices. Each edge in the edge array contains a reference to
  21. the two vertices it is composed of, and up to two faces that it is contained within.
  22. A face is a triangle made up of three vertices and three corresponding edges. Each face in the face array contains
  23. a reference to the three vertices and three edges it is composed of.
  24. The vertex array contains edge, face, normal, color, tangent, uv, uv2, bone, and weight information connected
  25. with each vertex.
  26. To access information from these arrays you use a function of the form ``get_****()``:
  27. .. tabs::
  28. .. code-tab:: gdscript GDScript
  29. mdt.get_vertex_count() # Returns number of vertices in vertex array.
  30. mdt.get_vertex_faces(0) # Returns array of faces that contain vertex[0].
  31. mdt.get_face_normal(1) # Calculates and returns face normal of the second face.
  32. mdt.get_edge_vertex(10, 1) # Returns the second vertex comprising the edge at index 10.
  33. What you choose to do with these functions is up to you. A common use case is to iterate over all vertices
  34. and transform them in some way:
  35. .. tabs::
  36. .. code-tab:: gdscript GDScript
  37. for i in range(get_vertex_count):
  38. var vert = mdt.get_vertex(i)
  39. vert *= 2.0 # Scales the vertex by doubling size.
  40. mdt.set_vertex(i, vert)
  41. These modifications are not done in place on the ArrayMesh. If you are dynamically updating an existing ArrayMesh,
  42. first delete the existing surface before adding a new one using :ref:`commit_to_surface() <class_meshdatatool_method_commit_to_surface>`:
  43. .. tabs::
  44. .. code-tab:: gdscript GDScript
  45. mesh.clear_surfaces() # Deletes all of the mesh's surfaces.
  46. mdt.commit_to_surface(mesh)
  47. Below is a complete example that turns a spherical mesh called ``mesh`` into a randomly deformed blob complete with updated normals and vertex colors.
  48. See :ref:`ArrayMesh tutorial <doc_arraymesh>` for how to generate the base mesh.
  49. .. tabs::
  50. .. code-tab:: gdscript GDScript
  51. extends MeshInstance3D
  52. var fnl = FastNoiseLite.new()
  53. var mdt = MeshDataTool.new()
  54. func _ready():
  55. fnl.frequency = 0.7
  56. mdt.create_from_surface(mesh, 0)
  57. for i in range(mdt.get_vertex_count()):
  58. var vertex = mdt.get_vertex(i).normalized()
  59. # Push out vertex by noise.
  60. vertex = vertex * (fnl.get_noise_3dv(vertex) * 0.5 + 0.75)
  61. mdt.set_vertex(i, vertex)
  62. # Calculate vertex normals, face-by-face.
  63. for i in range(mdt.get_face_count()):
  64. # Get the index in the vertex array.
  65. var a = mdt.get_face_vertex(i, 0)
  66. var b = mdt.get_face_vertex(i, 1)
  67. var c = mdt.get_face_vertex(i, 2)
  68. # Get vertex position using vertex index.
  69. var ap = mdt.get_vertex(a)
  70. var bp = mdt.get_vertex(b)
  71. var cp = mdt.get_vertex(c)
  72. # Calculate face normal.
  73. var n = (bp - cp).cross(ap - bp).normalized()
  74. # Add face normal to current vertex normal.
  75. # This will not result in perfect normals, but it will be close.
  76. mdt.set_vertex_normal(a, n + mdt.get_vertex_normal(a))
  77. mdt.set_vertex_normal(b, n + mdt.get_vertex_normal(b))
  78. mdt.set_vertex_normal(c, n + mdt.get_vertex_normal(c))
  79. # Run through vertices one last time to normalize normals and
  80. # set color to normal.
  81. for i in range(mdt.get_vertex_count()):
  82. var v = mdt.get_vertex_normal(i).normalized()
  83. mdt.set_vertex_normal(i, v)
  84. mdt.set_vertex_color(i, Color(v.x, v.y, v.z))
  85. mesh.clear_surfaces()
  86. mdt.commit_to_surface(mesh)