From 131880d444ab3675b68a32e36fc2520a90ac38b8 Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Tue, 2 Jul 2024 07:42:08 +0100 Subject: [PATCH] Physics Interpolation - Fix `Transform2D::interpolate_with()` Ports the `interpolate_with()` routine from 4.x which works correctly with skew. --- core/math/transform_2d.cpp | 35 ---------------------------- core/math/transform_2d.h | 8 ++++++- core/math/transform_interpolator.cpp | 34 ++------------------------- 3 files changed, 9 insertions(+), 68 deletions(-) diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp index 9df4894ac..7d5625684 100644 --- a/core/math/transform_2d.cpp +++ b/core/math/transform_2d.cpp @@ -295,41 +295,6 @@ real_t Transform2D::basis_determinant() const { return columns[0].x * columns[1].y - columns[0].y * columns[1].x; } -Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, real_t p_c) const { - //extract parameters - Vector2 p1 = get_origin(); - Vector2 p2 = p_transform.get_origin(); - - real_t r1 = get_rotation(); - real_t r2 = p_transform.get_rotation(); - - Size2 s1 = get_scale(); - Size2 s2 = p_transform.get_scale(); - - //slerp rotation - Vector2 v1(Math::cos(r1), Math::sin(r1)); - Vector2 v2(Math::cos(r2), Math::sin(r2)); - - real_t dot = v1.dot(v2); - - dot = CLAMP(dot, -1, 1); - - Vector2 v; - - if (dot > 0.9995f) { - v = Vector2::linear_interpolate(v1, v2, p_c).normalized(); //linearly interpolate to avoid numerical precision issues - } else { - real_t angle = p_c * Math::acos(dot); - Vector2 v3 = (v2 - v1 * dot).normalized(); - v = v1 * Math::cos(angle) + v3 * Math::sin(angle); - } - - //construct matrix - Transform2D res(Math::atan2(v.y, v.x), Vector2::linear_interpolate(p1, p2, p_c)); - res.scale_basis(Vector2::linear_interpolate(s1, s2, p_c)); - return res; -} - Transform2D::operator String() const { return "[X: " + columns[0].operator String() + ", Y: " + columns[1].operator String() + diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h index a961d1be5..8148596b0 100644 --- a/core/math/transform_2d.h +++ b/core/math/transform_2d.h @@ -132,7 +132,13 @@ struct _NO_DISCARD_CLASS_ Transform2D { void operator*=(const real_t p_val); Transform2D operator*(const real_t p_val) const; - Transform2D interpolate_with(const Transform2D &p_transform, real_t p_c) const; + Transform2D interpolate_with(const Transform2D &p_transform, real_t p_c) const { + return Transform2D( + Math::lerp_angle(get_rotation(), p_transform.get_rotation(), p_c), + get_scale().linear_interpolate(p_transform.get_scale(), p_c), + Math::lerp_angle(get_skew(), p_transform.get_skew(), p_c), + get_origin().linear_interpolate(p_transform.get_origin(), p_c)); + } _FORCE_INLINE_ Vector2 basis_xform(const Vector2 &p_vec) const; _FORCE_INLINE_ Vector2 basis_xform_inv(const Vector2 &p_vec) const; diff --git a/core/math/transform_interpolator.cpp b/core/math/transform_interpolator.cpp index 647954073..84a8597c2 100644 --- a/core/math/transform_interpolator.cpp +++ b/core/math/transform_interpolator.cpp @@ -44,46 +44,16 @@ void TransformInterpolator::interpolate_basis(const Basis &p_prev, const Basis & } void TransformInterpolator::interpolate_transform_2d(const Transform2D &p_prev, const Transform2D &p_curr, Transform2D &r_result, real_t p_fraction) { - // Extract parameters. - Vector2 p1 = p_prev.get_origin(); - Vector2 p2 = p_curr.get_origin(); - // Special case for physics interpolation, if flipping, don't interpolate basis. // If the determinant polarity changes, the handedness of the coordinate system changes. if (_sign(p_prev.basis_determinant()) != _sign(p_curr.basis_determinant())) { r_result.columns[0] = p_curr.columns[0]; r_result.columns[1] = p_curr.columns[1]; - r_result.set_origin(Vector2::linear_interpolate(p1, p2, p_fraction)); + r_result.set_origin(Vector2::linear_interpolate(p_prev.get_origin(), p_curr.get_origin(), p_fraction)); return; } - real_t r1 = p_prev.get_rotation(); - real_t r2 = p_curr.get_rotation(); - - Size2 s1 = p_prev.get_scale(); - Size2 s2 = p_curr.get_scale(); - - // Slerp rotation. - Vector2 v1(Math::cos(r1), Math::sin(r1)); - Vector2 v2(Math::cos(r2), Math::sin(r2)); - - real_t dot = v1.dot(v2); - - dot = CLAMP(dot, -1, 1); - - Vector2 v; - - if (dot > 0.9995f) { - v = Vector2::linear_interpolate(v1, v2, p_fraction).normalized(); // Linearly interpolate to avoid numerical precision issues. - } else { - real_t angle = p_fraction * Math::acos(dot); - Vector2 v3 = (v2 - v1 * dot).normalized(); - v = v1 * Math::cos(angle) + v3 * Math::sin(angle); - } - - // Construct matrix. - r_result = Transform2D(Math::atan2(v.y, v.x), Vector2::linear_interpolate(p1, p2, p_fraction)); - r_result.scale_basis(Vector2::linear_interpolate(s1, s2, p_fraction)); + r_result = p_prev.interpolate_with(p_curr, p_fraction); } void TransformInterpolator::interpolate_transform_via_method(const Transform &p_prev, const Transform &p_curr, Transform &r_result, real_t p_fraction, Method p_method) {