Skip to content

Commit 6b4a2c9

Browse files
committed
Port physics interpolation docs from 3.6
1 parent 53ce972 commit 6b4a2c9

11 files changed

+658
-0
lines changed

tutorials/physics/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ Physics
1919
collision_shapes_3d
2020
large_world_coordinates
2121
troubleshooting_physics_issues
22+
interpolation/index
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
.. _doc_2d_and_3d_physics_interpolation:
2+
3+
2D and 3D physics interpolation
4+
===============================
5+
6+
Generally 2D and 3D physics interpolation work in very similar ways. However, there
7+
are a few differences, which will be described here.
8+
9+
Global versus local interpolation
10+
---------------------------------
11+
12+
- In 3D, physics interpolation is performed *independently* on the **global
13+
transform** of each 3D instance.
14+
- In 2D by contrast, physics interpolation is performed on the **local transform**
15+
of each 2D instance.
16+
17+
This has some implications:
18+
19+
- In 3D, it is easy to turn interpolation on and off at the level of each ``Node``,
20+
via the ``physics_interpolation_mode`` property in the Inspector, which can be
21+
set to ``On``, ``Off``, or ``Inherited``.
22+
23+
.. figure:: img/physics_interpolation_mode.webp
24+
:align: center
25+
26+
- However this means that in 3D, pivots that occur in the ``SceneTree`` (due to
27+
parent child relationships) can only be interpolated **approximately** over the
28+
physics tick. In most cases this will not matter, but in some situations the
29+
interpolation can look slightly wrong.
30+
- In 2D, interpolated local transforms are passed down to children during
31+
rendering. This means that if a parent is set to ``physics_interpolation_mode``
32+
``On``, but the child is set to ``Off``, the child will still be interpolated if
33+
the parent is moving. *Only the child's local transform is uninterpolated.*
34+
Controlling the on / off behavior of 2D nodes therefore requires a little more
35+
thought and planning.
36+
- On the positive side, pivot behavior in the scene tree is perfectly preserved
37+
during interpolation in 2D, which gives super smooth behaviour.
38+
39+
Resetting physics interpolation
40+
-------------------------------
41+
42+
Whenever objects are moved to a completely new position, and interpolation is not
43+
desired (so as to prevent a "streaking" artefact), it is the responsibility of the
44+
user to call ``reset_physics_interpolation()``.
45+
46+
The good news is that in 2D, this is automatically done for you when nodes first
47+
enter the tree. This reduces boiler plate, and reduces the effort required to get
48+
an existing project working.
49+
50+
.. note:: If you move objects *after* adding to the scene tree, you will still need
51+
to call ``reset_physics_interpolation()`` as with 3D.
52+
53+
2D Particles
54+
------------
55+
56+
Currently only ``CPUParticles2D`` are supported for physics interpolation in 2D. It
57+
is recommended to use a physics tick rate of at least 20-30 ticks per second to
58+
keep particles looking fluid.
59+
60+
``Particles2D`` (GPU particles) are not yet interpolated, so for now it is
61+
recommended to convert to ``CPUParticles2D`` (but keep a backup of your
62+
``Particles2D`` in case we get these working).
63+
64+
Other
65+
-----
66+
67+
- ``get_global_transform_interpolated()`` - this is currently only available for 3D.
68+
- ``MultiMeshes`` - these should be supported in both 2D and 3D.
69+
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
.. _doc_advanced_physics_interpolation:
2+
3+
Advanced physics interpolation
4+
==============================
5+
6+
Although the previous instructions will give satisfactory results in a lot of games,
7+
in some cases you will want to go a stage further to get the best possible results
8+
and the smoothest possible experience.
9+
10+
Exceptions to automatic physics interpolation
11+
---------------------------------------------
12+
13+
Even with physics interpolation active, there may be some local situations where
14+
you would benefit from disabling automatic interpolation for a
15+
:ref:`Node<class_Node>` (or branch of the :ref:`SceneTree<class_SceneTree>`), and
16+
have the finer control of performing interpolation manually.
17+
18+
This is possible using the :ref:`Node.physics_interpolation_mode<class_Node_property_physics_interpolation_mode>`
19+
property which is present in all Nodes. If you for example, turn off interpolation
20+
for a Node, the children will recursively also be affected (as they default to
21+
inheriting the parent setting). This means you can easily disable interpolation for
22+
an entire subscene.
23+
24+
The most common situation where you may want to perform your own interpolation is
25+
Cameras.
26+
27+
Cameras
28+
~~~~~~~
29+
30+
In many cases, a :ref:`Camera3D<class_Camera3D>` can use automatic interpolation
31+
just like any other node. However, for best results, especially at low physics tick
32+
rates, it is recommended that you take a manual approach to camera interpolation.
33+
34+
This is because viewers are very sensitive to camera movement. For instance, a
35+
Camera3D that realigns slightly every 1/10th of a second (at 10tps tick rate) will
36+
often be noticeable. You can get a much smoother result by moving the camera each
37+
frame in ``_process``, and following an interpolated target manually.
38+
39+
Manual camera interpolation
40+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
41+
42+
Ensure the camera is using global coordinate space
43+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
44+
45+
The very first step when performing manual camera interpolation is to make sure the
46+
Camera3D transform is specified in *global space* rather than inheriting the
47+
transform of a moving parent. This is because feedback can occur between the
48+
movement of a parent node of a Camera3D and the movement of the camera Node itself,
49+
which can mess up the interpolation.
50+
51+
There are two ways of doing this:
52+
53+
1) Move the Camera3D so it is independent on its own branch, rather than being a child of a moving object.
54+
55+
.. image:: img/fti_camera_worldspace.webp
56+
57+
2) Call :ref:`Node3D.top_level<class_Node3D_property_top_level>` and set this to ``true``, which will make the Camera ignore the transform of its parent.
58+
59+
Typical example
60+
^^^^^^^^^^^^^^^
61+
62+
A typical example of a custom approach is to use the ``look_at`` function in the
63+
Camera3D every frame in ``_process()`` to look at a target node (such as the player).
64+
65+
But there is a problem. If we use the traditional ``get_global_transform()`` on a
66+
Camera3D "target" node, this transform will only focus the Camera3D on the target *at
67+
the current physics tick*. This is *not* what we want, as the camera will jump
68+
about on each physics tick as the target moves. Even though the camera may be
69+
updated each frame, this does not help give smooth motion if the *target* is only
70+
changing each physics tick.
71+
72+
get_global_transform_interpolated()
73+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
74+
75+
What we really want to focus the camera on, is not the position of the target on
76+
the physics tick, but the *interpolated* position, i.e. the position at which the
77+
target will be rendered.
78+
79+
We can do this using the :ref:`Spatial.get_global_transform_interpolated<class_Node3D_method_get_global_transform_interpolated>`
80+
function. This acts exactly like getting :ref:`Spatial.global_transform<class_Node3D_property_global_transform>`
81+
but it gives you the *interpolated* transform (during a ``_process()`` call).
82+
83+
.. important:: ``get_global_transform_interpolated()`` should only be used once or
84+
twice for special cases such as cameras. It should **not** be used
85+
all over the place in your code (both for performance reasons, and
86+
to give correct gameplay).
87+
88+
.. note:: Aside from exceptions like the camera, in most cases, your game logic
89+
should be in ``_physics_process()``. In game logic you should be calling
90+
``get_global_transform()`` or ``get_transform()``, which will give the
91+
current physics transform (in global or local space respectively), which
92+
is usually what you will want for gameplay code.
93+
94+
Example manual camera script
95+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
96+
97+
Here is an example of a simple fixed camera which follows an interpolated target:
98+
99+
.. code-block:: gdscript
100+
101+
extends Camera3D
102+
103+
# Node that the camera will follow
104+
var _target
105+
106+
# We will smoothly lerp to follow the target
107+
# rather than follow exactly
108+
var _target_pos : Vector3 = Vector3()
109+
110+
func _ready() -> void:
111+
# Find the target node
112+
_target = get_node("../Player")
113+
114+
# Turn off automatic physics interpolation for the Camera3D,
115+
# we will be doing this manually
116+
set_physics_interpolation_mode(Node.PHYSICS_INTERPOLATION_MODE_OFF)
117+
118+
func _process(delta: float) -> void:
119+
# Find the current interpolated transform of the target
120+
var tr : Transform = _target.get_global_transform_interpolated()
121+
122+
# Provide some delayed smoothed lerping towards the target position
123+
_target_pos = lerp(_target_pos, tr.origin, min(delta, 1.0))
124+
125+
# Fixed camera position, but it will follow the target
126+
look_at(_target_pos, Vector3(0, 1, 0))
127+
128+
Mouse look
129+
^^^^^^^^^^
130+
131+
Mouse look is a very common way of controlling cameras. But there is a problem.
132+
Unlike keyboard input which can be sampled periodically on the physics tick, mouse
133+
move events can come in continuously. The camera will be expected to react and
134+
follow these mouse movements on the next frame, rather than waiting until the next
135+
physics tick.
136+
137+
In this situation, it can be better to disable physics interpolation for the camera
138+
node (using :ref:`Node.physics_interpolation_mode<class_Node_property_physics_interpolation_mode>`)
139+
and directly apply the mouse input to the camera rotation, rather than apply it in
140+
``_physics_process``.
141+
142+
Sometimes, especially with cameras, you will want to use a combination of
143+
interpolation and non-interpolation:
144+
145+
* A first person camera may position the camera at a player location (perhaps using :ref:`Spatial.get_global_transform_interpolated<class_Node3D_method_get_global_transform_interpolated>`), but control the Camera rotation from mouse look *without* interpolation.
146+
* A third person camera may similarly determine the look at (target location) of the camera using :ref:`Spatial.get_global_transform_interpolated<class_Node3D_method_get_global_transform_interpolated>`, but position the camera using mouse look *without* interpolation.
147+
148+
There are many permutations and variations of camera types, but it should be clear
149+
that in many cases, disabling automatic physics interpolation and handling this
150+
yourself can give a better result.
151+
152+
Disabling interpolation on other nodes
153+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
154+
155+
Although cameras are the most common example, there are a number of cases when you
156+
may wish other nodes to control their own interpolation, or be non-interpolated.
157+
Consider for example, a player in a top view game whose rotation is controlled by
158+
mouse look. Disabling physics rotation allows the player rotation to match the
159+
mouse in real-time.
160+
161+
162+
MultiMeshes
163+
~~~~~~~~~~~
164+
165+
Although most visual Nodes follow the single Node single visual instance paradigm,
166+
MultiMeshes can control several instances from the same Node. Therefore, they have
167+
some extra functions for controlling interpolation functionality on a
168+
*per-instance* basis. You should explore these functions if you are using
169+
interpolated MultiMeshes.
170+
171+
- :ref:`MultiMesh.reset_instance_physics_interpolation<class_MultiMesh_method_reset_instance_physics_interpolation>`
172+
- :ref:`MultiMesh.set_buffer_interpolated<class_MultiMesh_method_set_buffer_interpolated>`
173+
174+
Full details are in the :ref:`MultiMesh<class_MultiMesh>` documentation.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.. _doc_physics_interpolation:
2+
3+
Physics Interpolation
4+
=====================
5+
6+
.. toctree::
7+
:maxdepth: 1
8+
:name: toc-physics-interpolation
9+
10+
physics_interpolation_quick_start_guide
11+
physics_interpolation_introduction
12+
using_physics_interpolation
13+
advanced_physics_interpolation
14+
2d_and_3d_physics_interpolation

0 commit comments

Comments
 (0)