Pārlūkot izejas kodu

Merge pull request #93309 from lawnjelly/fti_skinning

[3.x] Physics Interpolation - Fix 2D skinning
lawnjelly 1 gadu atpakaļ
vecāks
revīzija
12781e4554
2 mainītis faili ar 80 papildinājumiem un 11 dzēšanām
  1. 69 11
      scene/2d/skeleton_2d.cpp
  2. 11 0
      scene/2d/skeleton_2d.h

+ 69 - 11
scene/2d/skeleton_2d.cpp

@@ -29,6 +29,8 @@
 /**************************************************************************/
 
 #include "skeleton_2d.h"
+#include "core/engine.h"
+#include "core/math/transform_interpolator.h"
 
 void Bone2D::_order_changed_in_parent() {
 	if (skeleton) {
@@ -270,20 +272,76 @@ Bone2D *Skeleton2D::get_bone(int p_idx) {
 	return bones[p_idx].bone;
 }
 
-void Skeleton2D::_notification(int p_what) {
-	if (p_what == NOTIFICATION_READY) {
-		if (bone_setup_dirty) {
-			_update_bone_setup();
-		}
-		if (transform_dirty) {
-			_update_transform();
-		}
+void Skeleton2D::_update_process_mode() {
+	bool process = is_physics_interpolated_and_enabled() && is_visible_in_tree();
+
+	set_process_internal(process);
+	set_physics_process_internal(process);
+}
 
-		request_ready();
+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;
 	}
+}
 
-	if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
-		VS::get_singleton()->skeleton_set_base_transform_2d(skeleton, get_global_transform());
+void Skeleton2D::_physics_interpolated_changed() {
+	_update_process_mode();
+}
+
+void Skeleton2D::_notification(int p_what) {
+	switch (p_what) {
+		case NOTIFICATION_READY: {
+			if (bone_setup_dirty) {
+				_update_bone_setup();
+			}
+			if (transform_dirty) {
+				_update_transform();
+			}
+
+			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: {
+			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 {
+				VS::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_PHYSICS_PROCESS: {
+			if (is_physics_interpolated_and_enabled()) {
+				_ensure_update_interpolation_data();
+				_interpolation_data.xform_curr = get_global_transform();
+			}
+		} 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());
+				VS::get_singleton()->skeleton_set_base_transform_2d(skeleton, res);
+			}
+		} break;
+		case NOTIFICATION_VISIBILITY_CHANGED: {
+			_update_process_mode();
+		} break;
 	}
 }
 

+ 11 - 0
scene/2d/skeleton_2d.h

@@ -101,10 +101,21 @@ class Skeleton2D : public Node2D {
 
 	RID skeleton;
 
+	void _update_process_mode();
+	void _ensure_update_interpolation_data();
+
+	struct InterpolationData {
+		Transform2D xform_curr;
+		Transform2D xform_prev;
+		uint32_t last_update_physics_tick = UINT32_MAX;
+	} _interpolation_data;
+
 protected:
 	void _notification(int p_what);
 	static void _bind_methods();
 
+	virtual void _physics_interpolated_changed();
+
 public:
 	int get_bone_count() const;
 	Bone2D *get_bone(int p_idx);