Skip to content

Commit

Permalink
Add a page on large world coordinates (double-precision floats)
Browse files Browse the repository at this point in the history
  • Loading branch information
Calinou committed Oct 15, 2022
1 parent 742b2b1 commit 73d88c9
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 0 deletions.
2 changes: 2 additions & 0 deletions tutorials/3d/standard_material_3d.rst
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,8 @@ Godot supports two UV channels per material. Secondary UV is often useful for
ambient occlusion or emission (baked light). UVs can be scaled and offset,
which is useful when using repeating textures.

.. _doc_standard_material_3d_triplanar_mapping:

Triplanar Mapping
~~~~~~~~~~~~~~~~~

Expand Down
1 change: 1 addition & 0 deletions tutorials/physics/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ Physics
soft_body
collision_shapes_2d
collision_shapes_3d
large_world_coordinates
202 changes: 202 additions & 0 deletions tutorials/physics/large_world_coordinates.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
Large world coordinates
=======================

.. note::

Large world coordinates are mainly useful in 3D projects; they are rarely
required in 2D projects. Also, unlike 3D rendering, 2D rendering currently
doesn't benefit from increased precision when large world coordinates are
enabled.

Why use large world coordinates?
--------------------------------

In Godot, physics simulation and rendering both rely on *floating-point* numbers.
However, in computing, floating-point numbers have **limited precision and range**.
This can be a problem for games with huge worlds, such as space or planetary-scale
simulation games.

Precision is the greatest when the value is close to ``0.0``. Precision becomes
gradually lower as the value increases or decreases away from ``0.0``. This
occurs every time the floating-point number's *exponent* increases, which
happens when the floating-point number surpasses a power of 2 value (2, 4, 8,
16, …). Every time this occurs, the number's minimum step will *increase*,
resulting in a loss of precision.

In practice, this means that as the player moves away from the world origin
(``Vector2(0, 0)`` in 2D games or ``Vector3(0, 0, 0)`` in 3D games), precision
will decrease.

This loss of precision can result in objects appearing to "vibrate" when far
away from the world origin, as the model's vertices will be snapping to the
nearest value that can be represented in a floating-point number. This can also
result in physics glitches that only occur when the player is far from the world
origin.

The range determines the minimum and maximum values that can be stored in the
number. If the player tries to move past this range, they will simply not be
able to. However, in practice, floating-point precision almost always becomes
a problem before the range does.

The range and precision (minimum step between two exponent intervals) are
determined by the floating-point number type. The *theorical* range allows
extremely high values to be stored in single-precision floats, but with very low
precision. In practice, a floating-point type that cannot represent all integer
values is not very useful. At extreme values, precision becomes so low that the
number cannot even distinguish two separate *integer* values from each other.

This is the range where individual integer values can be represented in a
floating-point number:

- **Single-precision float range (represent all integers):** Between -16,777,216 and 16,777,216
- **Double-precision float range (represent all integers):** Between -9 quadrillon and 9 quadrillon

+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| Range | Single step | Double step | Comment |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| [1; 2] | ~0.0000001 | ~1e-15 | Precision becomes greater near 0.0 (this table is abbreviated). |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| [2; 4] | ~0.0000002 | ~1e-15 | |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| [4; 8] | ~0.0000005 | ~1e-15 | |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| [8; 16] | ~0.000001 | ~1e-14 | |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| [16; 32] | ~0.000002 | ~1e-14 | |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| [32; 64] | ~0.000004 | ~1e-14 | |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| [64; 128] | ~0.000008 | ~1e-13 | |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| [128; 256] | ~0.000015 | ~1e-13 | |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| [256; 512] | ~0.00003 | ~1e-13 | |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| [512; 1024] | ~0.00006 | ~1e-12 | |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| [1024; 2048] | ~0.0001 | ~1e-12 | |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| [2048; 4096] | ~0.0002 | ~1e-12 | Maximum *recommended* single-precision range for a first-person 3D game |
| | | | without rendering artifacts or physics glitches. |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| [4096; 8192] | ~0.0005 | ~1e-12 | Maximum *recommended* single-precision range for a third-person 3D game |
| | | | without rendering artifacts or physics glitches. |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| [8192; 16384] | ~0.001 | ~1e-12 | |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| [16384; 32768] | ~0.0019 | ~1e-11 | Maximum *recommended* single-precision range for a top-down 3D game |
| | | | without rendering artifacts or physics glitches. |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| [32768; 65536] | ~0.0039 | ~1e-11 | Maximum *recommended* single-precision range for any 3D game. Double |
| | | | precision (large world coordinates) is usually required past this point. |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| [65536; 131072] | ~0.0078 | ~1e-11 | |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| [131072; 262144] | ~0.0156 | ~1e-10 | |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+
| > 262144 | > ~0.0313 | ~1e-10 (0.0000000001) | Double-precision remains far more precise than single-precision |
| | | | past this value. |
+----------------------+-----------------------+-----------------------+-----------------------------------------------------------------------------+

When using single-precision floats, it is possible to go past the suggested
ranges, but more visible artifacting will occur and physics glitches will be
more common (such as the player not walking straight in certain directions).

.. seealso::

See the `Demistifying Floating Point Precision <https://blog.demofox.org/2017/11/21/>`__
article for more information.

How large world coordinates work
--------------------------------

Large world coordinates (also known as **double-precision physics**) increase
the precision level of all floating-point computations within the engine.

By default, :ref:`class_float` is 64-bit in GDScript, but :ref:`class_Vector2`,
:ref:`class_Vector3` and :ref:`class_Vector4` are 32-bit. This means that the
precision of vector types is much more limited. To resolve this, we can increase
the number of bits used to represent a floating-point number in a Vector type.
This results in an *exponential* increase in precision, which means the final
value is not just twice as precise, but potentially thousands of times more
precise at high values. The maximum value that can be represented is also
greatly increased by going from a single-precision float to a double-precision
float.

To avoid vertex snapping issues when far away from the world origin, Godot's 3D
rendering engine will increase its precision for rendering operations when large
world coordinates are enabled. The shaders do not use double-precision floats
for performance reasons, but an `alternative solution <https://github.com/godotengine/godot/pull/66178>`__
is used to emulate double precision for rendering using single-precision floats.

.. note::

Enabling large world coordinates comes with a performance and memory usage
penalty, especially on 32-bit CPUs. Only enable large world coordinates if
you actually need it.

This feature is tailored towards mid-range/high-end desktop platforms. Large
world coordinates may not perform well on low-end mobile devices, unless you
take steps to reduce CPU usage with other means (such as decreasing the
number of physics ticks per second).

Who are large world coordinates for?
------------------------------------

Large world coordinates are typically required for 3D space or planetary-scale
simulation games. This extends to games that require supporting *very* fast
movement speeds, but also very slow *and* precise movements at times.

On the other hand, it's important to only use large world coordinates when
actually required (for performance reasons). Large world coordinates are usually
**not** required for:

- 2D games, as precision issues are usually less noticeable.
- Games with small-scale or medium-scale worlds.
- Games with large worlds, but split into different levels with loading
sequences in between. You can center each level portion around the world
origin to avoid precision issues without a performance penalty.
- Open world games with a *playable on-foot area* not exceeding 8192×8192 meters
(centered around the world origin). As shown in the above table, the level of
precision remains acceptable within that range, even for a first-person game.

**If in doubt**, you probably don't need to use large world coordinates in your
project. For reference, most modern AAA open world titles don't use a large
world coordinates system and still rely on single-precision floats for both
rendering and physics.

Enabling large world coordinates
--------------------------------

This process requires recompiling the editor and all export template binaries
you intend to use. If you only intend to export your project in release mode,
you can skip the compilation of debug export templates. In any case, you'll need
to compile an editor build so you can test your large precision world without
having to export the project every time.

See the :ref:`Compiling <toc-devel-compiling>` section for compiling
instructions for each target platform. You will need to add the ``float=64``
SCons option when compiling the editor and export templates.

The resulting binaries will be named with a ``.double`` suffix to distinguish
them from single-precision binaries (which lack any precision suffix). You can
then specify the binaries as custom export templates in your project's export
presets in the Export dialog.

Limitations
-----------

Since 3D rendering shaders don't actually use double-precision floats, there are
some limitations when it comes to 3D rendering precision:

- Shaders using the ``skip_vertex_transform`` or ``world_vertex_coords`` don't
benefit from increased precision.
- :ref:`Triplanar mapping <doc_standard_material_3d_triplanar_mapping>` doesn't
benefit from increased precision. Materials using triplanr mapping will exhibit
visible jittering when far away from the world origin.

2D rendering currently doesn't benefit from increased precision when large world
coordinates are enabled. This can cause visible vertex snapping to occur when
far away from the world origin (starting from a few million pixels at typical
zoom levels). 2D physics calculations will still benefit from increased
precision though.

0 comments on commit 73d88c9

Please sign in to comment.