mirror of
https://github.com/Relintai/pandemonium_engine.git
synced 2024-11-22 00:48:09 +01:00
Physics Interpolation - Fix Transform2D::interpolate_with()
Ports the `interpolate_with()` routine from 4.x which works correctly with skew.
This commit is contained in:
parent
e5ec234b16
commit
131880d444
@ -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() +
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user