ソースを参照

Add pages on mesh LOD and visibility ranges

Hugo Locurcio 2 年 前
コミット
a4391f1473

BIN
tutorials/3d/img/mesh_lod_comparison_shaded.png


BIN
tutorials/3d/img/mesh_lod_comparison_wireframe.png


BIN
tutorials/3d/img/mesh_lod_disable_lod.png


BIN
tutorials/3d/img/mesh_lod_obj_import.png


+ 2 - 0
tutorials/3d/index.rst

@@ -20,3 +20,5 @@
    csg_tools
    procedural_geometry/index
    3d_text
+   mesh_lod
+   visibility_ranges

+ 177 - 0
tutorials/3d/mesh_lod.rst

@@ -0,0 +1,177 @@
+.. _doc_mesh_lod:
+
+Mesh level of detail (LOD)
+==========================
+
+Level of detail (LOD) is one of the most important ways to optimize rendering
+performance in a 3D project, along with occlusion culling.
+
+On this page, you'll learn:
+
+- How mesh LOD can improve your 3D project's rendering performance.
+- How to set up mesh LOD in Godot.
+- How to measure mesh LOD's effectiveness in your project
+  (and alternatives you can explore if it doesn't meet your expectations).
+
+Introduction
+-------
+
+Historically, level of detail in 3D games involved manually authoring meshes
+with lower geometry density, then configuring the distance thresholds at which
+these lower-detailed meshes should be drawn. This approach is still used today
+when increased control is needed.
+
+However, in projects that have a large amount of detailed 3D assets, setting up
+LOD manually can be a very time-consuming process. As a result, automatic mesh
+decimation and LOD configuration is becoming increasingly popular.
+
+Godot provides a way to automatically generate less detailed meshes for LOD
+usage on import, then use those LOD meshes when needed automatically. This is
+completely transparent to the user.
+The `meshoptimizer <https://meshoptimizer.org/>`__ library is used for LOD mesh
+generation behind the scenes.
+
+Mesh LOD works with any node that draws 3D meshes. This includes MeshInstance3D,
+MultiMeshInstance3D, GPUParticles3D and CPUParticles3D.
+
+Visual comparison
+-----------------
+
+Here is an example of LOD meshes generated on import. Lower detailed meshes
+will be used when the camera is far away from the object:
+
+.. figure:: img/mesh_lod_comparison_shaded.png
+   :align: center
+   :alt: From most detailed (left) to least detailed (right), shaded view
+
+   From most detailed (left) to least detailed (right), shaded view
+
+Here's the same image with wireframe rendering to make the decimation easier to see:
+
+.. figure:: img/mesh_lod_comparison_wireframe.png
+   :align: center
+   :alt: From most detailed (left) to least detailed (right), wireframe view
+
+   From most detailed (left) to least detailed (right), wireframe view
+
+.. seealso::
+
+    If you need to manually configure level of detail with artist-created meshes,
+    use :ref:`doc_visibility_ranges` instead of automatic mesh LOD.
+
+Generating mesh LOD
+-------------------
+
+By default, mesh LOD generation happens automatically for imported 3D scenes
+(glTF, .blend, Collada, FBX). Once LOD meshes are generated, they will
+automatically be used when rendering the scene. You don't need to configure
+anything manually.
+
+However, mesh LOD generation does **not** automatically happen for imported 3D
+meshes (OBJ). This is because OBJ files are not imported as full 3D scenes by
+default, but only as individual mesh resources to load into a MeshInstance3D
+node (or GPUParticles3D, CPUParticles3D, ...).
+
+To make an OBJ file have mesh LOD generated for it, select it in the FileSystem
+dock, go to the Import dock, change its **Import As** option to **Scene** then
+click **Reimport**:
+
+.. figure:: img/mesh_lod_obj_import.png
+   :align: center
+   :alt: Changing the import type on an OBJ file in the Import dock
+
+   Changing the import type on an OBJ file in the Import dock
+
+This will require restarting the editor after clicking **Reimport**.
+
+Comparing mesh LOD visuals and performance
+------------------------------------------
+
+To disable mesh LOD in the editor for comparison purposes, use the
+**Disable Mesh LOD** advanced debug draw mode. This can be done using the menu
+in the top-left corner of the 3D viewport (labeled **Perspective** or
+**Orthogonal** depending on camera mode):
+
+.. figure:: img/mesh_lod_disable_lod.png
+   :align: center
+   :alt: Disabling mesh LOD in the 3D viewport's top-left menu
+
+   Disabling mesh LOD in the 3D viewport's top-left menu
+
+Enable **View Frame Time** in the same menu to view FPS in the top-right corner.
+Also enable **View Information** in the same menu to view the number of primitives
+(vertices + indices) rendered in the bottom-right corner.
+
+If mesh LOD is working correctly in your scene and your camera is far away
+enough from the mesh, you should notice the number of drawn primitives
+decreasing and FPS increasing when mesh LOD is left enabled (unless you are
+CPU-bottlenecked).
+
+To see mesh LOD decimation in action, change the debug draw mode to
+**Display Wireframe** in the menu specified above, then adjust the
+**Rendering > Mesh LOD > LOD Change > Threshold Pixels** project setting.
+
+Configuring mesh LOD performance and quality
+--------------------------------------------
+
+You can adjust how aggressive mesh LOD transitions should be in the root viewport
+by changing the **Rendering > Mesh LOD > LOD Change > Threshold Pixels** project
+setting. To change this value at run-time, set ``mesh_lod_threshold`` on the
+root viewport as follows:
+
+::
+
+    get_tree().root.mesh_lod_threshold = 4.0
+
+Each viewport has its own ``mesh_lod_threshold`` property, which can be set
+independently from other viewports.
+
+The default mesh LOD threshold of 1 pixel is tuned to look *perceptually*
+lossless; it provides a significant performance gain with an unnoticeable loss
+in quality. Higher values will make LOD transitions happen sooner when the
+camera moves away, resulting in higher performance but lower quality.
+
+If you need to perform per-object adjustments to mesh LOD, you can adjust how
+aggressive LOD transitions should be by adjusting the **LOD Bias** property on
+any node that inherits from GeometryInstance3D. Positive values will make LOD
+transitions happen sooner than usual (resulting in lower quality but higher
+performance). Negative values will make LOD transitions happen earlier than
+usual (resulting in higher quality but lower performance).
+
+Additionally, ReflectionProbe nodes have their own **Mesh LOD Threshold** property
+that can be adjusted to improve rendering performance when the reflection probe
+updates. This is especially important for ReflectionProbes that use the **Always**
+update mode.
+
+.. note::
+
+    When rendering the scene, mesh LOD selection uses a screen-space metric.
+    This means it automatically takes camera field of view and viewport
+    resolution into account. Higher camera FOV and lower viewport resolutions
+    will make LOD selection more aggressive; the engine will display heavily
+    decimated models earlier when the camera moves away.
+
+    As a result, unlike :ref:`doc_visibility_ranges`, you don't need to do
+    anything specific in your project to take camera FOV and viewport resolution
+    into account.
+
+Using mesh LOD with MultiMesh and particles
+-------------------------------------------
+
+For LOD selection, the point of the node's :abbr:`AABB (Axis-Aligned Bounding Box)`
+that is the closest to the camera is used as a basis. This applies to any kind
+of mesh LOD (including for individual MeshInstance3D)s, but this has some implications
+for nodes that display multiple meshes at once, such as MultiMeshInstance3D,
+GPUParticles3D and GPUParticles3D. Most importantly, this means that all
+instances will be drawn with the same LOD level at a given time.
+
+If you are noticing incorrect LOD selection with GPUParticles3D, make sure
+the node's visibility AABB is configured by selecting the GPUParticles3D
+node and using **GPUParticles3D > Generate AABB** at the top of the 3D
+viewport.
+
+If you have instances in a MultiMesh that are far away from each other, they
+should be placed in a separate MultiMeshInstance3D node. Doing so will also
+improve rendering performance, as frustum and occlusion culling will be able to
+cull individual nodes (while they can't cull individual instances in a
+MultiMesh).

+ 189 - 0
tutorials/3d/visibility_ranges.rst

@@ -0,0 +1,189 @@
+.. _doc_visibility_ranges:
+
+Visibility ranges (HLOD)
+========================
+
+Along with mesh LOD and occlusion culling, visibility ranges are another tool
+to improve performance in large, complex 3D scenes.
+
+On this page, you'll learn:
+
+- What visibility ranges can do and which scenarios they are useful in.
+- How to set up visibility ranges (manual LOD) in Godot.
+- How to tune visibility ranges for best performance and quality.
+
+.. seealso::
+
+    If you only need meshes to become less detailed over distance but don't have
+    manually authored LOD meshes, consider relying on automatic
+    :ref:`doc_mesh_lod` instead.
+
+    Note that automatic mesh LOD and visibility ranges can be used at the same
+    time, even on the same mesh.
+
+How it works
+------------
+
+Visibility ranges can be used with any node that inherits from GeometryInstance3D.
+This means they can be used not only with MeshInstance3D and MultiMeshInstance3D
+for artist-controlled :abbr:`HLOD (Hierarchical Level of Detail)`, but also
+GPUParticles3D, CPUParticles3D, Label3D, Sprite3D, AnimatedSprite3D and CSGShape3D.
+
+Since visibility ranges are configured on a per-node basis, this makes it possible
+to use different node types as part of a :abbr:`LOD (Level of Detail)` system.
+For example, you could display a MeshInstance3D representing a tree when up close,
+and replace it with a Sprite3D impostor in the distance to improve performance.
+
+The benefit of :abbr:`HLOD (Hierarchical Level of Detail)` over a traditional
+:abbr:`LOD (Level of Detail)` system is its hierarchical nature. A single larger
+mesh can replace several smaller meshes, so that the number of draw calls can be
+reduced at a distance, but culling opportunities can be preserved when up close.
+For example, you can have a group of houses that uses individual MeshInstance3D
+nodes (one for each house) when up close, but turns into a single MeshInstance3D
+that represents a less detailed group of houses (or use a MultiMeshInstance3D).
+
+Lastly, visibility ranges can also be used to fade certain objects entirely when
+the camera gets too close or too far. This can be used for gameplay purposes,
+but also to reduce visual clutter. For example, Label3D nodes can be faded using
+visibility ranges when they're too far away to be readable or relevant to the
+player.
+
+Setting up visibility range
+---------------------------
+
+This is a quick-start guide for configuring a basic LOD system. After following
+this guide, this LOD system will display a SphereMesh when up close and a
+BoxMesh when the camera is far away enough. A small hysteresis margin is also
+configured via the **Begin Margin** and **End Margin** properties. This prevents
+LODs from popping back and forth too quickly when the camera is moving at the
+"edge" of the LOD transition.
+
+The visibility range properties can be found in the **Visibility Range** section
+of the GeometryInstance3D inspector after selecting the MeshInstance3D Node.
+
+- Add a Node3D node that will be used to group the two MeshInstance3D nodes
+  together.
+- Add a first MeshInstance3D node as a child of the Node3D. Assign a new
+  SphereMesh to its Mesh property.
+- Set the first MeshInstance3D's visibility range **End** to ``10.0`` and **End
+  Margin** to ``1.0``.
+- Add a second MeshInstance3D node as a child of the Node3D. Assign a new
+  BoxMesh to its Mesh property.
+- Set the second MeshInstance3D's visibility range **Begin** to ``10.0`` and
+  **Begin Margin** to ``1.0``.
+- Move the camera away and back towards the object. Notice how the object will
+  transition from a sphere to a box as the camera moves away.
+
+Visibility range properties
+---------------------------
+
+In the inspector of any node that inherits from GeometryInstance3D, you can adjust
+the following properties in the GeometryInstance3D's **Visibility Range** section:
+
+- **Begin:** The instance will be hidden when the camera is closer to the
+  instance's *origin* than this value (in 3D units).
+- **Begin Margin:** The hysteresis or alpha fade transition distance to use for
+  the close-up transition (in 3D units). The behavior of this property depends
+  on **Fade Mode**.
+- **End:** The instance will be hidden when the camera is further away from the
+  instance's *origin* than this value (in 3D units).
+- **End Margin:** The hysteresis or alpha fade transition distance to use for
+  the far-away transition (in 3D units). The behavior of this property depends
+  on **Fade Mode**.
+- **Fade Mode:** Controls how the transition between LOD levels should be performed.
+  See below for details.
+
+Fade mode
+^^^^^^^^^
+
+.. note::
+
+    The fade mode chosen only has a visible impact if either
+    **Visibility Range > Begin Margin** or **Visibility Range > End Margin** is
+    greater than ``0.0``.
+
+In the inspector's **Visibility Range** section, there are 3 fade modes to
+choose from:
+
+- **Disabled:** Uses hysteresis to switch between LOD levels instantly. This
+  prevents situations where LOD levels are switched back and forth quickly when
+  the player moves forward and then backward at the LOD transition point. The
+  hystereis distance is determined by **Visibility Range > Begin Margin** and
+  **Visibility Range > End Margin**. This mode provides the best performance as
+  it doesn't force rendering to become transparent during the fade transition.
+- **Self:** Uses alpha blending to smoothly fade between LOD levels. The fade
+  transition distance is determined by **Visibility Range > Begin Margin** and
+  **Visibility Range > End Margin**. This mode forces transparent rendering on
+  the object during its fade transition, so it has a performance impact.
+- **Dependencies:** This is intended for hierarchical LOD systems, and acts the
+  same as **Self** if visibility ranges are used to perform non-hierarchical
+  LOD.
+
+Configuration tips
+------------------
+
+Use simpler materials at a distance to improve performance
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+One way to further improve performance is to use simpler materials for distant
+LOD meshes. While using LOD meshes will reduce the number of vertices that need
+to be rendered, the per-pixel shading load for materials remains identical.
+However, per-pixel shading load is regularly a bottleneck on the GPU in complex
+3D scenes. One way to reduce this shading load on the GPU is to use simpler
+materials when they don't make much of a visual difference.
+
+Performance gains when doing so should be carefully measured, as
+increasing the number of *unique* materials in a scene has a performance cost on
+its own. Still, using simpler materials for distant LOD meshes can still result
+in a net performance gain as a result of the fewer per-pixel calculations
+required.
+
+For example, on the materials used by distant LOD meshes, you can disable
+expensive material features such as:
+
+- Normal Map (especially on mobile platforms)
+- Rim
+- Clearcoat
+- Anisotropy
+- Height
+- Subsurface Scattering
+- Back Lighting
+- Refraction
+- Proximity Fade
+
+Use dithering for LOD transitions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Godot currently only supports alpha-based fading for visibility ranges. You can
+however use dithering instead by using several different materials for different
+LOD levels.
+
+There are two advantages to using dithering over alpha blending for LOD transitions:
+
+- Higher performance, as dithering transparency is faster to render compared to
+  alpha blending.
+- No visual glitches due to
+  :ref:`transparency sorting issues <doc_3d_rendering_limitations_transparency_sorting>`
+  during LOD transitions.
+
+The downside of dithering is that a "noisy" pattern is visible during LOD fade
+transitions. This may not be as noticeable at higher viewport resolutions or
+when temporal antialiasing is enabled.
+
+Also, as distance fade in BaseMaterial3D only supports fading up close *or*
+fading when far away, this setup is best used with only two LODs as part of the
+setup.
+
+- Ensure **Begin Margin** and **End Margin** is set to ``0.0`` on both
+  MeshInstance3D nodes, as hysteresis or alpha fade are not desired here.
+- On both MeshInstance3D nodes, *decrease* **Begin** by the desired fade transition
+  distance and *increase* **End** by the same distance. This is required for the
+  dithering transition to actually be visible.
+- On the MeshInstance3D that is displayed up close, edit its material in the inspector.
+  Set its **Distance Fade** mode to **Object Dither**. Set **Min Distance** to
+  the same value as the visibility range **End**. Set **Max Distance** to the
+  same value *minus* the fade transition distance.
+- On the MeshInstance3D that is displayed far away, edit its material in the inspector.
+  Set its **Distance Fade** mode to **Object Dither**. Set **Min Distance** to
+  the same value as the visibility range **Begin**. Set **Max Distance** to the
+  same value *plus* the fade transition distance.