summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRicardo Buring <ricardo.buring@gmail.com>2024-06-19 22:30:00 +0200
committerRicardo Buring <ricardo.buring@gmail.com>2024-06-20 11:35:38 +0200
commit6d35dcf7c529a20f1ea100e770133e66b1c71086 (patch)
tree45bd9149e19d6991cb78dd1ccc632be1ed49e721
parent71699e08c9df78b7203fa4ef9cede28e995d6ace (diff)
downloadredot-engine-6d35dcf7c529a20f1ea100e770133e66b1c71086.tar.gz
Physics interpolation: Fix 2D skinning
Co-authored-by: lawnjelly <lawnjelly@gmail.com>
-rw-r--r--scene/2d/skeleton_2d.cpp69
-rw-r--r--scene/2d/skeleton_2d.h14
2 files changed, 76 insertions, 7 deletions
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index fe21c7f21b..8aa50668eb 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -30,6 +30,8 @@
#include "skeleton_2d.h"
+#include "core/math/transform_interpolator.h"
+
#ifdef TOOLS_ENABLED
#include "editor/editor_data.h"
#include "editor/editor_settings.h"
@@ -634,6 +636,30 @@ Bone2D *Skeleton2D::get_bone(int p_idx) {
return bones[p_idx].bone;
}
+void Skeleton2D::_update_process_mode() {
+ bool process = modification_stack.is_valid() && is_inside_tree();
+ if (!process) {
+ // We might have another reason to process.
+ process = is_physics_interpolated_and_enabled() && is_visible_in_tree();
+ }
+
+ set_process_internal(process);
+ set_physics_process_internal(process);
+}
+
+void Skeleton2D::_ensure_update_interpolation_data() {
+ uint64_t tick = Engine::get_singleton()->get_physics_frames();
+
+ if (_interpolation_data.last_update_physics_tick != tick) {
+ _interpolation_data.xform_prev = _interpolation_data.xform_curr;
+ _interpolation_data.last_update_physics_tick = tick;
+ }
+}
+
+void Skeleton2D::_physics_interpolated_changed() {
+ _update_process_mode();
+}
+
void Skeleton2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
@@ -646,17 +672,47 @@ void Skeleton2D::_notification(int p_what) {
request_ready();
} break;
+ case NOTIFICATION_ENTER_TREE: {
+ _update_process_mode();
+
+ if (is_physics_interpolated_and_enabled()) {
+ _interpolation_data.xform_curr = get_global_transform();
+ _interpolation_data.xform_prev = _interpolation_data.xform_curr;
+ }
+ } break;
+
case NOTIFICATION_TRANSFORM_CHANGED: {
- RS::get_singleton()->skeleton_set_base_transform_2d(skeleton, get_global_transform());
+ if (is_physics_interpolated_and_enabled()) {
+ _ensure_update_interpolation_data();
+ if (Engine::get_singleton()->is_in_physics_frame()) {
+ _interpolation_data.xform_curr = get_global_transform();
+ }
+ } else {
+ RS::get_singleton()->skeleton_set_base_transform_2d(skeleton, get_global_transform());
+ }
+ } break;
+
+ case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: {
+ _interpolation_data.xform_curr = get_global_transform();
+ _interpolation_data.xform_prev = _interpolation_data.xform_curr;
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
+ if (is_physics_interpolated_and_enabled()) {
+ Transform2D res;
+ TransformInterpolator::interpolate_transform_2d(_interpolation_data.xform_prev, _interpolation_data.xform_curr, res, Engine::get_singleton()->get_physics_interpolation_fraction());
+ RS::get_singleton()->skeleton_set_base_transform_2d(skeleton, res);
+ }
if (modification_stack.is_valid()) {
execute_modifications(get_process_delta_time(), SkeletonModificationStack2D::EXECUTION_MODE::execution_mode_process);
}
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
+ if (is_physics_interpolated_and_enabled()) {
+ _ensure_update_interpolation_data();
+ _interpolation_data.xform_curr = get_global_transform();
+ }
if (modification_stack.is_valid()) {
execute_modifications(get_physics_process_delta_time(), SkeletonModificationStack2D::EXECUTION_MODE::execution_mode_physics_process);
}
@@ -666,6 +722,10 @@ void Skeleton2D::_notification(int p_what) {
set_modification_stack(modification_stack);
} break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ _update_process_mode();
+ } break;
+
#ifdef TOOLS_ENABLED
case NOTIFICATION_DRAW: {
if (Engine::get_singleton()->is_editor_hint()) {
@@ -698,22 +758,17 @@ void Skeleton2D::set_modification_stack(Ref<SkeletonModificationStack2D> p_stack
if (modification_stack.is_valid()) {
modification_stack->is_setup = false;
modification_stack->set_skeleton(nullptr);
-
- set_process_internal(false);
- set_physics_process_internal(false);
}
modification_stack = p_stack;
if (modification_stack.is_valid() && is_inside_tree()) {
modification_stack->set_skeleton(this);
modification_stack->setup();
- set_process_internal(true);
- set_physics_process_internal(true);
-
#ifdef TOOLS_ENABLED
modification_stack->set_editor_gizmos_dirty(true);
#endif // TOOLS_ENABLED
}
+ _update_process_mode();
}
Ref<SkeletonModificationStack2D> Skeleton2D::get_modification_stack() const {
diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h
index ad6a47bf43..033bdff41d 100644
--- a/scene/2d/skeleton_2d.h
+++ b/scene/2d/skeleton_2d.h
@@ -137,7 +137,21 @@ class Skeleton2D : public Node2D {
Ref<SkeletonModificationStack2D> modification_stack;
+ ///////////////////////////////////////////////////////
+ // INTERPOLATION
+ struct InterpolationData {
+ Transform2D xform_curr;
+ Transform2D xform_prev;
+ uint32_t last_update_physics_tick = UINT32_MAX; // Ensure tick 0 is detected as a change.
+ } _interpolation_data;
+
+ void _update_process_mode();
+ void _ensure_update_interpolation_data();
+
protected:
+ virtual void _physics_interpolated_changed() override;
+ ///////////////////////////////////////////////////////
+
void _notification(int p_what);
static void _bind_methods();
bool _set(const StringName &p_path, const Variant &p_value);