Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

使用 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() 来添加一个带有这些属性的顶点。例如:

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

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

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

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

extends MeshInstance3D

func _ready():
    # Begin draw.
    mesh.surface_begin(Mesh.PRIMITIVE_TRIANGLES)

    # Prepare attributes for add_vertex.
    mesh.surface_set_normal(Vector3(0, 0, 1))
    mesh.surface_set_uv(Vector2(0, 0))
    # Call last for each vertex, adds the above attributes.
    mesh.surface_add_vertex(Vector3(-1, -1, 0))

    mesh.surface_set_normal(Vector3(0, 0, 1))
    mesh.surface_set_uv(Vector2(0, 1))
    mesh.surface_add_vertex(Vector3(-1, 1, 0))

    mesh.surface_set_normal(Vector3(0, 0, 1))
    mesh.surface_set_uv(Vector2(1, 1))
    mesh.surface_add_vertex(Vector3(1, 1, 0))

    # End drawing.
    mesh.surface_end()

ImmediateMesh 也可以在帧之间使用。每次调用 surface_begin()surface_end() 时,你都会向 ImmediateMesh 添加一个新表面。如果你想在每一帧从头开始重新创建网格,请在调用 surface_begin() 之前先调用 surface_clear()

extends MeshInstance3D

func _process(delta):

    # Clean up before drawing.
    mesh.clear_surfaces()

    # Begin draw.
    mesh.surface_begin(Mesh.PRIMITIVE_TRIANGLES)

    # Draw mesh.

    # End drawing.
    mesh.surface_end()

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