physics_interpolation_introduction.rst 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. .. _doc_physics_interpolation_introduction:
  2. Introduction
  3. ============
  4. Physics ticks and rendered frames
  5. ---------------------------------
  6. One key concept to understand in Godot is the distinction between physics ticks
  7. (sometimes referred to as iterations or physics frames), and rendered frames. The
  8. physics proceeds at a fixed tick rate (set in :ref:`Project Settings > Physics > Common > Physics Tick per Second<class_ProjectSettings_property_physics/common/physics_ticks_per_second>`),
  9. which defaults to 60 ticks per second.
  10. However, the engine does not necessarily **render** at the same rate. Although many
  11. monitors refresh at 60 Hz (cycles per second), many refresh at completely different
  12. frequencies (e.g. 75 Hz, 144 Hz, 240 Hz or more). Even though a monitor may be able
  13. to show a new frame e.g. 60 times a second, there is no guarantee that the CPU and
  14. GPU will be able to *supply* frames at this rate. For instance, when running with
  15. V-Sync, the computer may be too slow for 60 and only reach the deadlines for 30
  16. FPS, in which case the frames you see will change at 30 FPS (resulting in
  17. stuttering).
  18. But there is a problem here. What happens if the physics ticks do not coincide with
  19. frames? What happens if the physics tick rate is out of phase with the frame rate?
  20. Or worse, what happens if the physics tick rate is *lower* than the rendered frame
  21. rate?
  22. This problem is easier to understand if we consider an extreme scenario. If you set
  23. the physics tick rate to 10 ticks per second, in a simple game with a rendered
  24. frame rate of 60 FPS. If we plot a graph of the positions of an object against the
  25. rendered frames, you can see that the positions will appear to "jump" every 1/10th
  26. of a second, rather than giving a smooth motion. When the physics calculates a new
  27. position for a new object, it is not rendered in this position for just one frame,
  28. but for 6 frames.
  29. .. image:: img/fti_graph_fixed_ticks.webp
  30. This jump can be seen in other combinations of tick / frame rate as glitches, or
  31. jitter, caused by this staircasing effect due to the discrepancy between physics
  32. tick time and rendered frame time.
  33. What can we do about frames and ticks being out of sync?
  34. --------------------------------------------------------
  35. Lock the tick / frame rate together?
  36. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  37. The most obvious solution is to get rid of the problem, by ensuring there is a
  38. physics tick that coincides with every frame. This used to be the approach on old
  39. consoles and fixed hardware computers. If you know that every player will be using
  40. the same hardware, you can ensure it is fast enough to calculate ticks and frames
  41. at e.g. 50 FPS, and you will be sure it will work great for everybody.
  42. However, modern games are often no longer made for fixed hardware. You will often
  43. be planning to release on desktop computers, mobiles, and more. All of which have
  44. huge variations in performance, as well as different monitor refresh rates. We need
  45. to come up with a better way of dealing with the problem.
  46. Adapt the tick rate?
  47. ~~~~~~~~~~~~~~~~~~~~
  48. Instead of designing the game at a fixed physics tick rate, we could allow the tick
  49. rate to scale according to the end users hardware. We could for example use a fixed
  50. tick rate that works for that hardware, or even vary the duration of each physics
  51. tick to match a particular frame duration.
  52. This works, but there is a problem. Physics (*and game logic*, which is often also
  53. run in the ``_physics_process``) work best and most consistently when run at a
  54. **fixed**, predetermined tick rate. If you attempt to run a racing game physics
  55. that has been designed for 60 TPS (ticks per second) at e.g. 10 TPS, the physics
  56. will behave completely differently. Controls may be less responsive, collisions /
  57. trajectories can be completely different. You may test your game thoroughly at 60
  58. TPS, then find it breaks on end users machines when it runs at a different tick
  59. rate.
  60. This can make quality assurance difficult with hard to reproduce bugs, especially
  61. in AAA games where problems of this sort can be very costly. This can also be
  62. problematic for multiplayer games for competitive integrity, as running the game at
  63. certain tick rates may be more advantageous than others.
  64. Lock the tick rate, but use interpolation to smooth frames in between physics ticks
  65. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  66. This has become one of the most popular approaches to deal with the problem,
  67. although it is optional and disabled by default.
  68. We have established that the most desirable physics/game logic arrangement for
  69. consistency and predictability is a physics tick rate that is fixed at design-time.
  70. The problem is the discrepancy between the physics position recorded, and where we
  71. "want" a physics object to be shown on a frame to give smooth motion.
  72. The answer turns out to be simple, but can be a little hard to get your head around
  73. at first.
  74. Instead of keeping track of just the current position of a physics object in the
  75. engine, we keep track of *both the current position of the object, and the previous
  76. position* on the previous physics tick.
  77. Why do we need the previous position *(in fact the entire transform, including
  78. rotation and scaling)*? By using a little math magic, we can use **interpolation**
  79. to calculate what the transform of the object would be between those two points, in
  80. our ideal world of smooth continuous movement.
  81. .. image:: img/fti_graph_interpolated.webp
  82. Linear interpolation
  83. ~~~~~~~~~~~~~~~~~~~~
  84. The simplest way to achieve this is linear interpolation, or lerping, which you may
  85. have used before.
  86. Let us consider only the position, and a situation where we know that the previous
  87. physics tick X coordinate was 10 units, and the current physics tick X coordinate
  88. is 30 units.
  89. .. note:: Although the maths is explained here, you do not have to worry about the
  90. details, as this step will be performed for you. Under the hood, Godot
  91. may use more complex forms of interpolation, but linear interpolation is
  92. the easiest in terms of explanation.
  93. The physics interpolation fraction
  94. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  95. If our physics ticks are happening 10 times per second (for this example), what
  96. happens if our rendered frame takes place at time 0.12 seconds? We can do some math
  97. to figure out where the object would be to obtain a smooth motion between the two
  98. ticks.
  99. First of all, we have to calculate how far through the physics tick we want the
  100. object to be. If the last physics tick took place at 0.1 seconds, we are 0.02
  101. seconds *(0.12 - 0.1)* through a tick that we know will take 0.1 seconds (10 ticks
  102. per second). The fraction through the tick is thus:
  103. .. code-block:: gdscript
  104. fraction = 0.02 / 0.10
  105. fraction = 0.2
  106. This is called the **physics interpolation fraction**, and is handily calculated
  107. for you by Godot. It can be retrieved on any frame by calling :ref:`Engine.get_physics_interpolation_fraction<class_Engine_method_get_physics_interpolation_fraction>`.
  108. Calculating the interpolated position
  109. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  110. Once we have the interpolation fraction, we can insert it into a standard linear
  111. interpolation equation. The X coordinate would thus be:
  112. .. code-block:: gdscript
  113. x_interpolated = x_prev + ((x_curr - x_prev) * 0.2)
  114. So substituting our ``x_prev`` as 10, and ``x_curr`` as 30:
  115. .. code-block:: gdscript
  116. x_interpolated = 10 + ((30 - 10) * 0.2)
  117. x_interpolated = 10 + 4
  118. x_interpolated = 14
  119. Let's break that down:
  120. - We know the X starts from the coordinate on the previous tick (``x_prev``) which
  121. is 10 units.
  122. - We know that after the full tick, the difference between the current tick and the
  123. previous tick will have been added (``x_curr - x_prev``) (which is 20 units).
  124. - The only thing we need to vary is the proportion of this difference we add,
  125. according to how far we are through the physics tick.
  126. .. note:: Although this example interpolates the position, the same thing can be
  127. done with the rotation and scale of objects. It is not necessary to know
  128. the details as Godot will do all this for you.
  129. Smoothed transformations between physics ticks?
  130. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  131. Putting all this together shows that it should be possible to have a nice smooth
  132. estimation of the transform of objects between the current and previous physics
  133. tick.
  134. But wait, you may have noticed something. If we are interpolating between the
  135. current and previous ticks, we are not estimating the position of the object *now*,
  136. we are estimating the position of the object in the past. To be exact, we are
  137. estimating the position of the object *between 1 and 2 ticks* into the past.
  138. In the past
  139. ~~~~~~~~~~~
  140. What does this mean? This scheme does work, but it does mean we are effectively
  141. introducing a delay between what we see on the screen, and where the objects
  142. *should* be.
  143. In practice, most people won't notice this delay, or rather, it is typically not
  144. *objectionable*. There are already significant delays involved in games, we just
  145. don't typically notice them. The most significant effect is there can be a slight
  146. delay to input, which can be a factor in fast twitch games. In some of these fast
  147. input situations, you may wish to turn off physics interpolation and use a
  148. different scheme, or use a high tick rate, which mitigates these delays.
  149. Why look into the past? Why not predict the future?
  150. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  151. There is an alternative to this scheme, which is: instead of interpolating between
  152. the previous and current tick, we use maths to *extrapolate* into the future. We
  153. try to predict where the object *will be*, rather than show it where it was. This
  154. can be done and may be offered as an option in future, but there are some
  155. significant downsides:
  156. - The prediction may not be correct, especially when an object collides with
  157. another object during the physics tick.
  158. - Where a prediction was incorrect, the object may extrapolate into an "impossible"
  159. position, like inside a wall.
  160. - Providing the movement speed is slow, these incorrect predictions may not be too
  161. much of a problem.
  162. - When a prediction was incorrect, the object may have to jump or snap back onto
  163. the corrected path. This can be visually jarring.
  164. Fixed timestep interpolation
  165. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  166. In Godot this whole system is referred to as physics interpolation, but you may
  167. also hear it referred to as **"fixed timestep interpolation"**, as it is
  168. interpolating between objects moved with a fixed timestep (physics ticks per
  169. second). In some ways the second term is more accurate, because it can also be used
  170. to interpolate objects that are not driven by physics.
  171. .. tip:: Although physics interpolation is usually a good choice, there are
  172. exceptions where you may choose not to use Godot's built-in physics
  173. interpolation (or use it in a limited fashion). An example category is
  174. internet multiplayer games. Multiplayer games often receive tick or timing
  175. based information from other players or a server and these may not
  176. coincide with local physics ticks, so a custom interpolation technique can
  177. often be a better fit.