From d80b206643cc6a7b62f17886856ae08c9b553bbc Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Wed, 19 Jun 2024 07:36:06 +0100 Subject: [PATCH] Physics Interpolation - refactor client interpolation pump * Move client interpolation pump to earlier in the iteration before 3D physics synced * Allow `get_global_transform_interpolated()` to prime the client interpolation inside a physics tick --- doc/classes/Spatial.xml | 1 + main/main.cpp | 6 +++--- scene/3d/spatial.cpp | 9 ++++++++- scene/main/scene_tree.cpp | 10 +++++----- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/doc/classes/Spatial.xml b/doc/classes/Spatial.xml index 97c566bc552..db206cf9f68 100644 --- a/doc/classes/Spatial.xml +++ b/doc/classes/Spatial.xml @@ -24,6 +24,7 @@ When using physics interpolation, there will be circumstances in which you want to know the interpolated (displayed) transform of a node rather than the standard transform (which may only be accurate to the most recent physics tick). This is particularly important for frame-based operations that take place in [method Node._process], rather than [method Node._physics_process]. Examples include [Camera]s focusing on a node, or finding where to fire lasers from on a frame rather than physics tick. + [b]Note:[/b] This function creates an interpolation pump on the [Spatial] the first time it is called, which can respond to physics interpolation resets. If you get problems with "streaking" when initially following a [Spatial], be sure to call [method get_global_transform_interpolated] at least once [i]before[/i] resetting the [Spatial] physics interpolation. diff --git a/main/main.cpp b/main/main.cpp index 37e386e6f87..9553e90bc53 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2367,14 +2367,14 @@ bool Main::iteration() { uint64_t physics_begin = OS::get_singleton()->get_ticks_usec(); - PhysicsServer::get_singleton()->flush_queries(); - // Prepare the fixed timestep interpolated nodes - // BEFORE they are updated by the physics 2D, + // BEFORE they are updated by the physics, // otherwise the current and previous transforms // may be the same, and no interpolation takes place. OS::get_singleton()->get_main_loop()->iteration_prepare(); + PhysicsServer::get_singleton()->flush_queries(); + Physics2DServer::get_singleton()->sync(); Physics2DServer::get_singleton()->flush_queries(); diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index 60b729467ce..cac9673bfa0 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -407,7 +407,14 @@ Transform Spatial::get_global_transform_interpolated() { // Pass through if physics interpolation is switched off. // This is a convenience, as it allows you to easy turn off interpolation // without changing any code. - if (Engine::get_singleton()->is_in_physics_frame() || !is_physics_interpolated_and_enabled()) { + if (!is_physics_interpolated_and_enabled()) { + return get_global_transform(); + } + + // If we are in the physics frame, the interpolated global transform is meaningless. + // However, there is an exception, we may want to use this as a means of starting off the client + // interpolation pump if not already started (when _is_physics_interpolated_client_side() is false). + if (Engine::get_singleton()->is_in_physics_frame() && _is_physics_interpolated_client_side()) { return get_global_transform(); } diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 48335922454..3c1809c3586 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -559,6 +559,11 @@ void SceneTree::iteration_prepare() { // are flushed before pumping the interpolation prev and currents. flush_transform_notifications(); VisualServer::get_singleton()->tick(); + + // Any objects performing client physics interpolation + // should be given an opportunity to keep their previous transforms + // up to date before each new physics tick. + _client_physics_interpolation.physics_process(); } } @@ -575,11 +580,6 @@ bool SceneTree::iteration(float p_time) { current_frame++; - // Any objects performing client physics interpolation - // should be given an opportunity to keep their previous transforms - // up to take before each new physics tick. - _client_physics_interpolation.physics_process(); - flush_transform_notifications(); if (MainLoop::iteration(p_time)) {