Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 68 additions & 34 deletions tutorials/3d/procedural_geometry/immediatemesh.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,33 @@
Using ImmediateMesh
===================

Unlike the SurfaceTool or ArrayMesh, :ref:`ImmediateMesh <class_ImmediateMesh>` is an actual
node. Being a node makes it quick to add to a scene and get visual output. It uses an OpenGL 1.x-style
API like SurfaceTool, but it's actually designed to create meshes on the fly.
The :ref:`ImmediateMesh <class_ImmediateMesh>` is a convenient tool to create
dynamic geometry using an OpenGL 1.x-style API. Which makes it both approachable
to use and efficient for meshes which need to be updated every frame.

Generating complex geometry (several thousand vertices) with this node is inefficient, even if it's
Generating complex geometry (several thousand vertices) with this tool is inefficient, even if it's
done only once. Instead, it is designed to generate simple geometry that changes every frame.

Before starting, you should clear the geometry by calling ``clear_surfaces()``. This ensures that
you are not building upon the geometry from the previous frame. If you want to keep geometry between frames, do
not call ``clear_surfaces()``.
First, you need to create a :ref:`MeshInstance3D <class_meshinstance3d>` and add
an :ref:`ImmediateMesh <class_ImmediateMesh>` to it in the Inspector.

To begin generating geometry you must call ``surface_begin()``. ``surface_begin()`` takes a ``PrimitiveType`` as an argument.
``PrimitiveType`` is an OpenGL concept that instructs the GPU how to arrange the primitive based on the
vertices given whether it is triangles, lines, points, etc. A complete list can be found under
Next, add a script to the MeshInstance3D. The code for the ImmediateMesh should
go in the ``_process()`` function if you want it to update each frame, or in the
``_ready()`` function if you want to create the mesh once and not update it. If
you only generate a surface once, the ImmediateMesh is just as efficient as any
other kind of mesh as the generated mesh is cached and reused.

To begin generating geometry you must call ``surface_begin()``.
``surface_begin()`` takes a ``PrimitiveType`` as an argument. ``PrimitiveType``
instructs the GPU how to arrange the primitive based on the vertices given
whether it is triangles, lines, points, etc. A complete list can be found under
the :ref:`Mesh <class_mesh>` class reference page.

Once you have called ``surface_begin()`` you are ready to start adding vertices. You add vertices one at a time.
First you add vertex specific attributes such as normals or UVs using ``surface_set_****()`` (e.g. ``surface_set_normal()``).
Then you call ``surface_add_vertex()`` to add a vertex with those attributes. For example:
Once you have called ``surface_begin()`` you are ready to start adding vertices.
You add vertices one at a time. First you add vertex specific attributes such as
normals or UVs using ``surface_set_****()`` (e.g. ``surface_set_normal()``).
Then you call ``surface_add_vertex()`` to add a vertex with those attributes.
For example:

.. tabs::
.. code-tab:: gdscript GDScript
Expand All @@ -31,37 +39,63 @@ Then you call ``surface_add_vertex()`` to add a vertex with those attributes. Fo
surface_set_uv(Vector2(1, 1))
surface_add_vertex(Vector3(0, 0, 1))

Only attributes added before the call to ``surface_add_vertex()`` will be included in that vertex.
Only attributes added before the call to ``surface_add_vertex()`` will be
included in that vertex. If you add an attribute twice before calling
``surface_add_vertex()``, only the second call will be used.

Finally, once you have added all your vertices call ``surface_end()`` to signal that you have finished generating the mesh.
Finally, once you have added all your vertices call ``surface_end()`` to signal
that you have finished generating the surface. You can call ``surface_begin()``
and ``surface_end()`` multiple times to generate multiple surfaces for the mesh.

The example code below draws a single triangle.
The example code below draws a single triangle in the ``_ready()`` function.

.. tabs::
.. code-tab:: gdscript GDScript

extends ImmediateMesh

func _process(_delta):
# Clean up before drawing.
clear_surfaces()
extends MeshInstance3D

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

# Prepare attributes for surface_add_vertex.
surface_set_normal(Vector3(0, 0, 1))
surface_set_uv(Vector2(0, 0))
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.
surface_add_vertex(Vector3(-1, -1, 0))
mesh.surface_add_vertex(Vector3(-1, -1, 0))

surface_set_normal(Vector3(0, 0, 1))
surface_set_uv(Vector2(0, 1))
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))

surface_set_normal(Vector3(0, 0, 1))
surface_set_uv(Vector2(1, 1))
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.
surface_end()
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
``surface_clear()`` before calling ``surface_begin()``.

.. tabs::
.. code-tab:: gdscript GDScript

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()

The above code will dynamically create and draw a single surface each frame.
31 changes: 18 additions & 13 deletions tutorials/3d/procedural_geometry/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,12 @@ by an array of positions called "vertices". In Godot, geometry is represented by
What is a Mesh?
---------------

Many things in Godot have mesh in their name: the :ref:`Mesh <class_Mesh>`, the :ref:`ArrayMesh <class_ArrayMesh>`,
the :ref:`MeshInstance3D <class_MeshInstance3D>`, the :ref:`MultiMesh <class_MultiMesh>`, and
the :ref:`MultiMeshInstance3D <class_MultiMeshInstance3D>`. While they are all related, they have slightly different uses.
Many things in Godot have mesh in their name: the :ref:`Mesh <class_Mesh>`, the
:ref:`ArrayMesh <class_ArrayMesh>`, the :ref:`ImmediateMesh
<class_ImmediateMesh>`, the :ref:`MeshInstance3D <class_MeshInstance3D>`, the
:ref:`MultiMesh <class_MultiMesh>`, and the :ref:`MultiMeshInstance3D
<class_MultiMeshInstance3D>`. While they are all related, they have slightly
different uses.

Meshes and ArrayMeshes are resources that are drawn using a MeshInstance3D node. Resources like
Meshes and ArrayMeshes cannot be added to the scene directly. A MeshInstance3D represents one
Expand Down Expand Up @@ -109,14 +112,16 @@ For more information about the SurfaceTool, please see the :ref:`SurfaceTool tut
ImmediateMesh
^^^^^^^^^^^^^

ImmediateMesh is a node that uses an immediate mode style interface (like SurfaceTool) to draw objects. The
difference between ImmediateMesh and the SurfaceTool is that ImmediateMesh is a node itself that can be
added to the scene tree and is drawn directly from the code, while The SurfaceTool generates a Mesh that needs to be added to
a MeshInstance3D to be seen.
ImmediateMesh is a mesh that uses an immediate mode style interface (like
SurfaceTool) to draw objects. The difference between ImmediateMesh and the
SurfaceTool is that ImmediateMesh is drawn directly with code dynamically, while
the SurfaceTool is used to generated a Mesh that you can do whatever you want
with.

ImmediateMesh is useful for prototyping because of its straightforward API, but it is slow because the geometry
is rebuilt every frame. It is most useful for adding simple geometry for visual debugging (e.g. by drawing lines to
visualize physics raycasts etc.).
ImmediateMesh is useful for prototyping because of its straightforward API, but
it is slow because the geometry is rebuilt each time you make a change. It is
most useful for adding simple geometry for visual debugging (e.g. by drawing
lines to visualize physics raycasts etc.).

For more information about ImmediateMesh, please see the :ref:`ImmediateMesh tutorial <doc_immediatemesh>`.

Expand All @@ -130,9 +135,9 @@ Both SurfaceTool and ArrayMesh are excellent for generating static geometry (mes
Using an ArrayMesh is slightly faster than using a SurfaceTool, but the API is a little more challenging.
Additionally, SurfaceTool has a few quality of life methods such as ``generate_normals()`` and ``index()``.

ImmediateMesh regenerates the mesh every frame, so it is much slower than ArrayMesh or SurfaceTool. However, if you
need the geometry to change every frame anyway, it provides a much easier interface that may even be a little faster than generating
an ArrayMesh every frame.
ImmediateMesh is more limited than both ArrayMesh and SurfaceTool. However, if
you need the geometry to change every frame anyway, it provides a much easier
interface that can be slightly faster than generating an ArrayMesh every frame.

The MeshDataTool is not fast, but it gives you access to all kinds of properties of the mesh that you don't get with the others
(edges, faces, etc.). It is incredibly useful when you need that sort of data to transform the mesh, but it is not a good idea
Expand Down