Skip to content

Commit

Permalink
doc: add LOD instancer documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
laurentsenta committed Jan 29, 2025
1 parent 7f67809 commit b6dff47
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 8 deletions.
11 changes: 11 additions & 0 deletions doc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,14 @@ help:
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

install:
python -m venv .venv && \
. .venv/bin/activate && \
pip install -r requirements.txt && \
echo "Setup complete. Remember to run 'source .venv/bin/activate' to activate the virtual environment."

serve:
source ./.venv/bin/activate && \
make html && \
python -m http.server --directory _build/html
Binary file added doc/_static/video/lod-001-base.mp4
Binary file not shown.
Binary file added doc/_static/video/lod-002-shadow-maximum-lod.mp4
Binary file not shown.
Binary file added doc/_static/video/lod-003-shadow-minimum-lod.mp4
Binary file not shown.
30 changes: 30 additions & 0 deletions doc/doc_classes/Terrain3DMeshAsset.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,38 @@
<member name="scene_file" type="PackedScene" setter="set_scene_file" getter="get_scene_file">
A packed scene to load the mesh from. See the top description.
</member>
<member name="maximum_lod" type="int" setter="set_maximum_lod" getter="get_maximum_lod" default="0">
Sets the maximum level of detail (LOD) for this mesh asset. LODs above this value will be ignored.
</member>
<member name="maximum_shadow_lod" type="int" setter="set_maximum_shadow_lod" getter="get_maximum_shadow_lod" default="0">
Sets the maximum shadow level of detail (LOD) for this mesh asset. LODs above this value will not cast shadows.
This reduces the performance cost of shadow casting by not casting shadows for distant objects.
</member>
<member name="minimum_shadow_lod" type="int" setter="set_minimum_shadow_lod" getter="get_minimum_shadow_lod" default="0">
Sets the minimum shadow level of detail (LOD) for this mesh asset. When a lower LOD is used, it will cast the shadow of this LOD level.
This reduces the performance cost of shadow casting by using less detailed meshes for shadow rendering.
</member>
<member name="lod_0_visibility_range" type="float" setter="set_lod_0_visibility_range" getter="get_lod_0_visibility_range" default="0.0">
Sets [code skip-lint]GeometryInstance3D.set_visibility_range_end[/code] on all MultiMeshInstances used by this mesh at the first LOD level (the most detailed).
Allows the renderer to cull MMIs beyond this distance. The next LOD level will use this value its [code skip-lint]GeometryInstance3D.set_visibility_range_begin[/code].
Set to 0 to disable culling.
</member>
<member name="lod_1_visibility_range" type="float" setter="set_lod_1_visibility_range" getter="get_lod_1_visibility_range" default="0.0">
See [lod_0_visibility_range]. Applies to the second LOD level.
</member>
<member name="lod_2_visibility_range" type="float" setter="set_lod_2_visibility_range" getter="get_lod_2_visibility_range" default="0.0">
See [lod_0_visibility_range]. Applies to the third LOD level.
</member>
<member name="lod_3_visibility_range" type="float" setter="set_lod_3_visibility_range" getter="get_lod_3_visibility_range" default="0.0">
See [lod_0_visibility_range]. Applies to the fourth and last LOD level.
</member>
<member name="visibility_margin" type="float" setter="set_visibility_margin" getter="get_visibility_margin" default="0.0">
Sets the [code skip-lint]GeometryInstance3D.set_visibility_range_begin_margin[/code] and [code skip-lint]GeometryInstance3D.set_visibility_range_end_margin[/code] on all multimeshes used by this mesh.
We use Godot's default `Disabled` Fade mode, which uses hysteresis to switch between LOD levels. This prevents situations where LOD levels are switched back and forth quickly when the player moves around a transition point.
</member>
<member name="visibility_range" type="float" setter="set_visibility_range" getter="get_visibility_range" default="100.0">
Sets [code skip-lint]GeometryInstance3D.visibility_range_end[/code] on all MultiMeshInstances used by this mesh. Allows the renderer to cull MMIs beyond this distance. Set to 0 to disable culling.
Deprecated, see [lod_0_visibility_range].
</member>
</members>
<signals>
Expand Down
55 changes: 47 additions & 8 deletions doc/docs/instancer.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The instancer uses Godot's [MultiMesh](https://docs.godotengine.org/en/stable/cl
**Table of Contents**
* [How To Use The Instancer](#how-to-use-the-instancer)
* [Limitations](#limitations)
* [LOD Support](#lod-support)
* [Wind and Player Interaction](#wind-player-interaction)
* [Procedural Placement](#procedural-placement)
* [Importing From Other Tools](#importing-from-other-tools)
Expand Down Expand Up @@ -75,7 +76,7 @@ There are some caveats and limitations built into the engine that you should be

### Simple Objects

Some 3D assets are complex objects with multiple, separate meshes, such as a tree trunk and leaves, a chest and lid, or a door frame and door. MultiMeshes support only one mesh. Our system scans the provided scene file and uses the first mesh it finds. If you give it a complex object with separate trunk and leaves, it will use only the trunk.
Some 3D assets are complex objects with multiple, separate meshes, such as a tree trunk and leaves, a chest and lid, or a door frame and door. MultiMeshes support only one mesh per LOD. Our system scans the provided scene file and uses the first mesh it finds for LOD0, the second mesh as LOD1, and so on up to LOD3. If you give it a complex object with separate trunk and leaves, it won't work as expected.

Either combine your complex objects into one (easy to do with the Join operation in Blender, while maintaining separate materials), or use another method of placement, such as AssetPlacer, Scatter, or manual placement.

Expand All @@ -85,13 +86,7 @@ If you use a mesh with multiple materials, make sure they are connected to the M

A MultiMesh renders all instances in one draw call and does not cull individual instances via frustum, occlusion, nor distance.

We mitigate this by generating multiple MultiMeshes, one per region, so that large blocks can be culled by frustum or occlusion. Later we'll likely expose distance culling, and will increase the number of MultiMeshes, reducing the size of each so they can be more finely culled by the engine.

### Limited LOD Support

MultiMeshes do work with the auto LODs generated by the import system. There are some bugs in the engine so you may find the meshes generated are sub par. If so, the only way to fix it is by disabling the auto LOD generation on that mesh in the Godot importer and reimporting. This can be done with existing mesh instances on the ground.

There is no facility within MultiMeshes to insert artist created LODs, stored as separate objects within your scene file. Currently, separate LODs are not supported. In the future we will generate additional MultiMeshes for these LODs. The entire LOD0 MultiMesh will be hidden, while LOD1 is shown, switching potentially 10s of thousands of instances at once. So this will only be usable once the smaller MultiMesh grid is implemented.
We mitigate this by generating multiple MultiMeshes. Each region is divided into smaller cells so that these smallers MultiMeshes can be culled by frustum or occlusion. We expose distance culling parameters (visibility ranges) in the asset's settings.

### No Collision

Expand All @@ -113,6 +108,50 @@ Godot currently has no protection against filling up your VRAM. You could do so

----------------------------------

## LOD Support

#### Auto LODs

MultiMeshes do work with the auto LODs generated by the import system. There are some bugs in the engine so you may find the meshes generated are sub par. If so, the only way to fix it is by disabling the auto LOD generation on that mesh in the Godot importer and reimporting. This can be done with existing mesh instances on the ground.

#### Artist Created LODs

We also provide a way to insert artist created LODs, stored as separate meshes within your scene file. We generate a multimesh for each LOD, from LOD0 up to LOD3. The visiliby range of each LOD level can be set in the instancer options. The engine will automatically switch between LOD levels based on the distance from the camera.

<figure class="video_container">
<video width="600px" controls="true" allowfullscreen="true">
<source src="../_static/video/lod-001-base.mp4" type="video/mp4">
</video>
</figure>

#### Shadows LODs

When using artist created LODs, we provide various option for shadow LODs.

The `Maximum Shadow LOD` option lets you set the maximum LOD level that will cast shadows. Objects with higher LOD levels (further away) will not cast shadows. This is used to improve performance in case where shadows are not visible in the distance (blades of grass for example).

In the following video, note how the shadows disappear as we lower the `Maximum Shadow LOD` value.

<figure class="video_container">
<video width="600px" controls="true" allowfullscreen="true">
<source src="../_static/video/lod-002-shadow-maximum-lod.mp4" type="video/mp4">
</video>
</figure>

The `Minimum Shadow LOD` option lets you set the minimum LOD level that will cast shadows. Objects with lower LOD levels (closer) will appear as if they are casting the shadow of this LOD level. This is used to improve performance in case where shadows don't need as much detail as the object itself.

In the following video, note how shadows are using the (simpler) cube mesh for LODs 0 and 1 when we set the `Minimum Shadow LOD` to 2.

<figure class="video_container">
<video width="600px" controls="true" allowfullscreen="true">
<source src="../_static/video/lod-003-shadow-minimum-lod.mp4" type="video/mp4">
</video>
</figure>

Be wary of double checking your LODs configuration in the editor, as we don't validate nonsensical settings for now (e.g. LOD0 range is greater than LOD1 range, or `Maximum Shadow LOD` is less than `Minimum Shadow LOD`). In the future we may provide warning once [Configuration Warnings for Resources](https://github.com/godotengine/godot/pull/90049) makes its way into the engine.

----------------------------------

## Wind, Player Interaction

These features can be implemented by having a wind shader or player interaction (grass flattening) shader in a ShaderMaterial attached to your mesh. We don't currently provide these shaders, but you can find both online. We may provide these shaders in the future. The instancer will use whatever material you've attached to the mesh or placed in the override slot, and the MultiMesh will automatically apply it to all instances.
Expand Down

0 comments on commit b6dff47

Please sign in to comment.