瀏覽代碼

Merge pull request #93851 from lawnjelly/fti_fix_interpolate_with_2D

[3.x] Physics Interpolation - Fix `Transform2D::interpolate_with()`
lawnjelly 1 年之前
父節點
當前提交
c2a43cb8bd
共有 3 個文件被更改,包括 31 次插入68 次删除
  1. 18 35
      core/math/transform_2d.cpp
  2. 11 1
      core/math/transform_2d.h
  3. 2 32
      core/math/transform_interpolator.cpp

+ 18 - 35
core/math/transform_2d.cpp

@@ -82,6 +82,24 @@ void Transform2D::set_rotation(real_t p_rot) {
 	set_scale(scale);
 	set_scale(scale);
 }
 }
 
 
+void Transform2D::set_skew(real_t p_angle) {
+	real_t det = determinant();
+	elements[1] = SGN(det) * elements[0].rotated(((real_t)Math_PI * 0.5f + p_angle)).normalized() * elements[1].length();
+}
+
+real_t Transform2D::get_skew() const {
+	real_t det = determinant();
+	return Math::acos(elements[0].normalized().dot(SGN(det) * elements[1].normalized())) - (real_t)Math_PI * 0.5f;
+}
+
+Transform2D::Transform2D(real_t p_rot, const Size2 &p_scale, real_t p_skew, const Vector2 &p_pos) {
+	elements[0][0] = Math::cos(p_rot) * p_scale.x;
+	elements[1][1] = Math::cos(p_rot + p_skew) * p_scale.y;
+	elements[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y;
+	elements[0][1] = Math::sin(p_rot) * p_scale.x;
+	elements[2] = p_pos;
+}
+
 Transform2D::Transform2D(real_t p_rot, const Vector2 &p_pos) {
 Transform2D::Transform2D(real_t p_rot, const Vector2 &p_pos) {
 	real_t cr = Math::cos(p_rot);
 	real_t cr = Math::cos(p_rot);
 	real_t sr = Math::sin(p_rot);
 	real_t sr = Math::sin(p_rot);
@@ -221,41 +239,6 @@ real_t Transform2D::determinant() const {
 	return elements[0].x * elements[1].y - elements[0].y * elements[1].x;
 	return elements[0].x * elements[1].y - elements[0].y * elements[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 {
 Transform2D::operator String() const {
 	return String(String() + elements[0] + ", " + elements[1] + ", " + elements[2]);
 	return String(String() + elements[0] + ", " + elements[1] + ", " + elements[2]);
 }
 }

+ 11 - 1
core/math/transform_2d.h

@@ -71,6 +71,8 @@ struct _NO_DISCARD_CLASS_ Transform2D {
 
 
 	void set_rotation(real_t p_rot);
 	void set_rotation(real_t p_rot);
 	real_t get_rotation() const;
 	real_t get_rotation() const;
+	void set_skew(real_t p_angle);
+	real_t get_skew() const;
 	_FORCE_INLINE_ void set_rotation_and_scale(real_t p_rot, const Size2 &p_scale);
 	_FORCE_INLINE_ void set_rotation_and_scale(real_t p_rot, const Size2 &p_scale);
 	void rotate(real_t p_angle);
 	void rotate(real_t p_angle);
 
 
@@ -104,7 +106,13 @@ struct _NO_DISCARD_CLASS_ Transform2D {
 	void operator*=(const Transform2D &p_transform);
 	void operator*=(const Transform2D &p_transform);
 	Transform2D operator*(const Transform2D &p_transform) const;
 	Transform2D operator*(const Transform2D &p_transform) 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(const Vector2 &p_vec) const;
 	_FORCE_INLINE_ Vector2 basis_xform_inv(const Vector2 &p_vec) const;
 	_FORCE_INLINE_ Vector2 basis_xform_inv(const Vector2 &p_vec) const;
@@ -127,6 +135,8 @@ struct _NO_DISCARD_CLASS_ Transform2D {
 	}
 	}
 
 
 	Transform2D(real_t p_rot, const Vector2 &p_pos);
 	Transform2D(real_t p_rot, const Vector2 &p_pos);
+	Transform2D(real_t p_rot, const Size2 &p_scale, real_t p_skew, const Vector2 &p_pos);
+
 	Transform2D() {
 	Transform2D() {
 		elements[0][0] = 1.0;
 		elements[0][0] = 1.0;
 		elements[1][1] = 1.0;
 		elements[1][1] = 1.0;

+ 2 - 32
core/math/transform_interpolator.cpp

@@ -33,46 +33,16 @@
 #include "core/math/transform_2d.h"
 #include "core/math/transform_2d.h"
 
 
 void TransformInterpolator::interpolate_transform_2d(const Transform2D &p_prev, const Transform2D &p_curr, Transform2D &r_result, real_t p_fraction) {
 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.
 	// Special case for physics interpolation, if flipping, don't interpolate basis.
 	// If the determinant polarity changes, the handedness of the coordinate system changes.
 	// If the determinant polarity changes, the handedness of the coordinate system changes.
 	if (_sign(p_prev.determinant()) != _sign(p_curr.determinant())) {
 	if (_sign(p_prev.determinant()) != _sign(p_curr.determinant())) {
 		r_result.elements[0] = p_curr.elements[0];
 		r_result.elements[0] = p_curr.elements[0];
 		r_result.elements[1] = p_curr.elements[1];
 		r_result.elements[1] = p_curr.elements[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;
 		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(const Transform &p_prev, const Transform &p_curr, Transform &r_result, real_t p_fraction) {
 void TransformInterpolator::interpolate_transform(const Transform &p_prev, const Transform &p_curr, Transform &r_result, real_t p_fraction) {