使用 ImmediateMesh

ImmediateMesh 是一个使用 OpenGL 1.x 风格的 API 创建动态几何体的便捷工具。这使得它对于需要每帧更新的网格来说,既易于使用又高效。

使用这个工具生成复杂的几何体(几千个顶点)效率很低,即使只做一次。相反,它的设计是为了生成每一帧变化的简单几何体。

首先,你需要创建一个 MeshInstance3D 并在检查其中向其添加一个 ImmediateMesh

接下来,将脚本添加到 MeshInstance3D 上。如果你希望 ImmediateMesh 每帧都更新,则应该把 ImmediateMesh 的代码放在 _process() 函数中;如果你想创建一次网格体而后不再更新它,则代码应放在 _ready() 函数中。如果仅生成一次表面,则 ImmediateMesh 与任何其他类型的网格一样高效,因为生成的网格会被缓存并重用。

必须调用 surface_begin() 才能开始生成几何体 。surface_begin() 将一个 PrimitiveType 作为参数。PrimitiveType(图元类型)指示 GPU 如何根据给定的顶点来安排图元,可以是三角形、线、点等。完整的列表可以在 Mesh 的类参考页面中找到。

一旦你调用了 surface_begin() ,就可以开始添加顶点了。每次添加一个顶点,首先使用 surface_set_****() (例如 surface_set_normal() )添加顶点的特定属性,如法线或 UV。然后调用 surface_add_vertex() 来添加一个带有这些属性的顶点。例如:

GDScript

  1. # Add a vertex with normal and uv.
  2. surface_set_normal(Vector3(0, 1, 0))
  3. surface_set_uv(Vector2(1, 1))
  4. surface_add_vertex(Vector3(0, 0, 1))

只有在调用 surface_add_vertex() 之前添加的属性才会被包含在该顶点中。如果在调用 surface_add_vertex() 之前添加属性两次,则仅第二次调用才会被使用。

最后,当添加了所有的顶点后,调用 surface_end() 来表示已经完成了网格的生成。你可以多次调用 surface_begin()surface_end() 来为网格生成多个表面。

下面的示例代码在 _ready() 函数中绘制了一个三角形。

GDScript

  1. extends MeshInstance3D
  2. func _ready():
  3. # Begin draw.
  4. mesh.surface_begin(Mesh.PRIMITIVE_TRIANGLES)
  5. # Prepare attributes for add_vertex.
  6. mesh.surface_set_normal(Vector3(0, 0, 1))
  7. mesh.surface_set_uv(Vector2(0, 0))
  8. # Call last for each vertex, adds the above attributes.
  9. mesh.surface_add_vertex(Vector3(-1, -1, 0))
  10. mesh.surface_set_normal(Vector3(0, 0, 1))
  11. mesh.surface_set_uv(Vector2(0, 1))
  12. mesh.surface_add_vertex(Vector3(-1, 1, 0))
  13. mesh.surface_set_normal(Vector3(0, 0, 1))
  14. mesh.surface_set_uv(Vector2(1, 1))
  15. mesh.surface_add_vertex(Vector3(1, 1, 0))
  16. # End drawing.
  17. mesh.surface_end()

The ImmediateMesh can also be used across frames. Each time you call surface_begin() and surface_end(), you are adding a new surface to the ImmediateMesh. If you want to recreate the mesh from scratch each frame, call clear_surfaces() before calling surface_begin().

GDScript

  1. extends MeshInstance3D
  2. func _process(delta):
  3. # Clean up before drawing.
  4. mesh.clear_surfaces()
  5. # Begin draw.
  6. mesh.surface_begin(Mesh.PRIMITIVE_TRIANGLES)
  7. # Draw mesh.
  8. # End drawing.
  9. mesh.surface_end()

上面的代码将在每个帧里动态地创建并绘制一个表面。