From 37a70edc116b1e28926c027ca64890bf799e5678 Mon Sep 17 00:00:00 2001 From: Thaddeus Crews Date: Tue, 22 Apr 2025 12:58:29 -0500 Subject: [PATCH] Nearest and linear interpolation optimization Nearest and linear interpolation optimization --- scene/resources/animation.cpp | 74 ++++++++++++++++++++++++++--------- scene/resources/animation.h | 8 ++-- 2 files changed, 59 insertions(+), 23 deletions(-) diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 0c1d2f40a0d..2b415c923d9 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -4105,7 +4105,7 @@ void Animation::clear() { emit_changed(); } -bool Animation::_float_track_optimize_key(const TKey t0, const TKey t1, const TKey t2, real_t p_allowed_velocity_err, real_t p_allowed_precision_error) { +bool Animation::_float_track_optimize_key(const TKey t0, const TKey t1, const TKey t2, real_t p_allowed_velocity_err, real_t p_allowed_precision_error, bool p_is_nearest) { // Remove overlapping keys. if (Math::is_equal_approx(t0.time, t1.time) || Math::is_equal_approx(t1.time, t2.time)) { return true; @@ -4113,6 +4113,9 @@ bool Animation::_float_track_optimize_key(const TKey t0, const TKey t0, const TKey t0, const TKey t1, const TKey t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error) { +bool Animation::_vector2_track_optimize_key(const TKey t0, const TKey t1, const TKey t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error, bool p_is_nearest) { // Remove overlapping keys. if (Math::is_equal_approx(t0.time, t1.time) || Math::is_equal_approx(t1.time, t2.time)) { return true; @@ -4141,6 +4144,9 @@ bool Animation::_vector2_track_optimize_key(const TKey t0, const TKey t0, const TKey t0, const TKey t1, const TKey t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error) { +bool Animation::_vector3_track_optimize_key(const TKey t0, const TKey t1, const TKey t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error, bool p_is_nearest) { // Remove overlapping keys. if (Math::is_equal_approx(t0.time, t1.time) || Math::is_equal_approx(t1.time, t2.time)) { return true; @@ -4172,6 +4178,10 @@ bool Animation::_vector3_track_optimize_key(const TKey t0, const TKey t0, const TKey t0, const TKey t1, const TKey t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error) { +bool Animation::_quaternion_track_optimize_key(const TKey t0, const TKey t1, const TKey t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error, bool p_is_nearest) { // Remove overlapping keys. if (Math::is_equal_approx(t0.time, t1.time) || Math::is_equal_approx(t1.time, t2.time)) { return true; @@ -4203,6 +4213,9 @@ bool Animation::_quaternion_track_optimize_key(const TKey t0, const if ((t0.value - t1.value).length() < p_allowed_precision_error && (t1.value - t2.value).length() < p_allowed_precision_error) { return true; } + if (p_is_nearest) { + return false; + } // Check axis. Quaternion q0 = t0.value * t1.value * t0.value.inverse(); Quaternion q1 = t1.value * t2.value * t1.value.inverse(); @@ -4232,15 +4245,19 @@ bool Animation::_quaternion_track_optimize_key(const TKey t0, const void Animation::_position_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) { ERR_FAIL_INDEX(p_idx, tracks.size()); ERR_FAIL_COND(tracks[p_idx]->type != TYPE_POSITION_3D); + bool is_nearest = false; + if (tracks[p_idx]->interpolation == INTERPOLATION_NEAREST) { + is_nearest = true; + } else if (tracks[p_idx]->interpolation != INTERPOLATION_LINEAR) { + return; + } PositionTrack *tt = static_cast(tracks[p_idx]); - int i = 0; while (i < tt->positions.size() - 2) { TKey t0 = tt->positions[i]; TKey t1 = tt->positions[i + 1]; TKey t2 = tt->positions[i + 2]; - - bool erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error); + bool erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error, is_nearest); if (erase) { tt->positions.remove_at(i + 1); } else { @@ -4258,15 +4275,19 @@ void Animation::_position_track_optimize(int p_idx, real_t p_allowed_velocity_er void Animation::_rotation_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) { ERR_FAIL_INDEX(p_idx, tracks.size()); ERR_FAIL_COND(tracks[p_idx]->type != TYPE_ROTATION_3D); + bool is_nearest = false; + if (tracks[p_idx]->interpolation == INTERPOLATION_NEAREST) { + is_nearest = true; + } else if (tracks[p_idx]->interpolation != INTERPOLATION_LINEAR) { + return; + } RotationTrack *rt = static_cast(tracks[p_idx]); - int i = 0; while (i < rt->rotations.size() - 2) { TKey t0 = rt->rotations[i]; TKey t1 = rt->rotations[i + 1]; TKey t2 = rt->rotations[i + 2]; - - bool erase = _quaternion_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error); + bool erase = _quaternion_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error, is_nearest); if (erase) { rt->rotations.remove_at(i + 1); } else { @@ -4284,15 +4305,19 @@ void Animation::_rotation_track_optimize(int p_idx, real_t p_allowed_velocity_er void Animation::_scale_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) { ERR_FAIL_INDEX(p_idx, tracks.size()); ERR_FAIL_COND(tracks[p_idx]->type != TYPE_SCALE_3D); + bool is_nearest = false; + if (tracks[p_idx]->interpolation == INTERPOLATION_NEAREST) { + is_nearest = true; + } else if (tracks[p_idx]->interpolation != INTERPOLATION_LINEAR) { + return; + } ScaleTrack *st = static_cast(tracks[p_idx]); - int i = 0; while (i < st->scales.size() - 2) { TKey t0 = st->scales[i]; TKey t1 = st->scales[i + 1]; TKey t2 = st->scales[i + 2]; - - bool erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error); + bool erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error, is_nearest); if (erase) { st->scales.remove_at(i + 1); } else { @@ -4310,15 +4335,20 @@ void Animation::_scale_track_optimize(int p_idx, real_t p_allowed_velocity_err, void Animation::_blend_shape_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_precision_error) { ERR_FAIL_INDEX(p_idx, tracks.size()); ERR_FAIL_COND(tracks[p_idx]->type != TYPE_BLEND_SHAPE); + bool is_nearest = false; + if (tracks[p_idx]->interpolation == INTERPOLATION_NEAREST) { + is_nearest = true; + } else if (tracks[p_idx]->interpolation != INTERPOLATION_LINEAR) { + return; + } BlendShapeTrack *bst = static_cast(tracks[p_idx]); - int i = 0; while (i < bst->blend_shapes.size() - 2) { TKey t0 = bst->blend_shapes[i]; TKey t1 = bst->blend_shapes[i + 1]; TKey t2 = bst->blend_shapes[i + 2]; - bool erase = _float_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_precision_error); + bool erase = _float_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_precision_error, is_nearest); if (erase) { bst->blend_shapes.remove_at(i + 1); } else { @@ -4336,6 +4366,12 @@ void Animation::_blend_shape_track_optimize(int p_idx, real_t p_allowed_velocity void Animation::_value_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) { ERR_FAIL_INDEX(p_idx, tracks.size()); ERR_FAIL_COND(tracks[p_idx]->type != TYPE_VALUE); + bool is_nearest = false; + if (tracks[p_idx]->interpolation == INTERPOLATION_NEAREST) { + is_nearest = true; + } else if (tracks[p_idx]->interpolation != INTERPOLATION_LINEAR && tracks[p_idx]->interpolation != INTERPOLATION_LINEAR_ANGLE) { + return; + } ValueTrack *vt = static_cast(tracks[p_idx]); if (vt->values.is_empty()) { return; @@ -4367,7 +4403,7 @@ void Animation::_value_track_optimize(int p_idx, real_t p_allowed_velocity_err, break; // Rotation is more than 180 deg, keep key. } } - erase = _float_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_precision_error); + erase = _float_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_precision_error, is_nearest); } break; case Variant::VECTOR2: { TKey t0; @@ -4379,7 +4415,7 @@ void Animation::_value_track_optimize(int p_idx, real_t p_allowed_velocity_err, t0.value = vt->values[i].value; t1.value = vt->values[i + 1].value; t2.value = vt->values[i + 2].value; - erase = _vector2_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error); + erase = _vector2_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error, is_nearest); } break; case Variant::VECTOR3: { TKey t0; @@ -4391,7 +4427,7 @@ void Animation::_value_track_optimize(int p_idx, real_t p_allowed_velocity_err, t0.value = vt->values[i].value; t1.value = vt->values[i + 1].value; t2.value = vt->values[i + 2].value; - erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error); + erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error, is_nearest); } break; case Variant::QUATERNION: { TKey t0; @@ -4403,7 +4439,7 @@ void Animation::_value_track_optimize(int p_idx, real_t p_allowed_velocity_err, t0.value = vt->values[i].value; t1.value = vt->values[i + 1].value; t2.value = vt->values[i + 2].value; - erase = _quaternion_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error); + erase = _quaternion_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error, is_nearest); } break; default: { } break; diff --git a/scene/resources/animation.h b/scene/resources/animation.h index bc6f48bfeaa..6cf43262790 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -373,10 +373,10 @@ private: // bind helpers private: - bool _float_track_optimize_key(const TKey t0, const TKey t1, const TKey t2, real_t p_allowed_velocity_err, real_t p_allowed_precision_error); - bool _vector2_track_optimize_key(const TKey t0, const TKey t1, const TKey t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error); - bool _vector3_track_optimize_key(const TKey t0, const TKey t1, const TKey t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error); - bool _quaternion_track_optimize_key(const TKey t0, const TKey t1, const TKey t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error); + bool _float_track_optimize_key(const TKey t0, const TKey t1, const TKey t2, real_t p_allowed_velocity_err, real_t p_allowed_precision_error, bool p_is_nearest); + bool _vector2_track_optimize_key(const TKey t0, const TKey t1, const TKey t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error, bool p_is_nearest); + bool _vector3_track_optimize_key(const TKey t0, const TKey t1, const TKey t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error, bool p_is_nearest); + bool _quaternion_track_optimize_key(const TKey t0, const TKey t1, const TKey t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error, bool p_is_nearest); void _position_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error); void _rotation_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error);