Fixed Basis -> Quat conversions, added a few safety checks.

Fixes #19027.
This commit is contained in:
tagcup 2018-05-26 23:14:05 -04:00
parent 130fd6bcb8
commit 9d41161596
7 changed files with 40 additions and 21 deletions

View file

@ -356,8 +356,7 @@ void Basis::rotate(const Quat &p_quat) {
*this = rotated(p_quat); *this = rotated(p_quat);
} }
// TODO: rename this to get_rotation_euler Vector3 Basis::get_rotation_euler() const {
Vector3 Basis::get_rotation() const {
// Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S, // Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S,
// and returns the Euler angles corresponding to the rotation part, complementing get_scale(). // and returns the Euler angles corresponding to the rotation part, complementing get_scale().
// See the comment in get_scale() for further information. // See the comment in get_scale() for further information.
@ -371,6 +370,20 @@ Vector3 Basis::get_rotation() const {
return m.get_euler(); return m.get_euler();
} }
Quat Basis::get_rotation_quat() const {
// Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S,
// and returns the Euler angles corresponding to the rotation part, complementing get_scale().
// See the comment in get_scale() for further information.
Basis m = orthonormalized();
real_t det = m.determinant();
if (det < 0) {
// Ensure that the determinant is 1, such that result is a proper rotation matrix which can be represented by Euler angles.
m.scale(Vector3(-1, -1, -1));
}
return m.get_quat();
}
void Basis::get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const { void Basis::get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const {
// Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S, // Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S,
// and returns the Euler angles corresponding to the rotation part, complementing get_scale(). // and returns the Euler angles corresponding to the rotation part, complementing get_scale().
@ -591,10 +604,9 @@ Basis::operator String() const {
} }
Quat Basis::get_quat() const { Quat Basis::get_quat() const {
//commenting this check because precision issues cause it to fail when it shouldn't #ifdef MATH_CHECKS
//#ifdef MATH_CHECKS ERR_FAIL_COND_V(is_rotation() == false, Quat());
//ERR_FAIL_COND_V(is_rotation() == false, Quat()); #endif
//#endif
real_t trace = elements[0][0] + elements[1][1] + elements[2][2]; real_t trace = elements[0][0] + elements[1][1] + elements[2][2];
real_t temp[4]; real_t temp[4];

View file

@ -84,9 +84,11 @@ public:
void rotate(const Quat &p_quat); void rotate(const Quat &p_quat);
Basis rotated(const Quat &p_quat) const; Basis rotated(const Quat &p_quat) const;
Vector3 get_rotation() const; Vector3 get_rotation_euler() const;
void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const; void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const;
void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const; void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const;
Quat get_rotation_quat() const;
Vector3 get_rotation() const { return get_rotation_euler(); };
Vector3 rotref_posscale_decomposition(Basis &rotref) const; Vector3 rotref_posscale_decomposition(Basis &rotref) const;

View file

@ -139,15 +139,15 @@ bool Quat::is_normalized() const {
Quat Quat::inverse() const { Quat Quat::inverse() const {
#ifdef MATH_CHECKS #ifdef MATH_CHECKS
ERR_FAIL_COND_V(is_normalized() == false, Quat(0, 0, 0, 0)); ERR_FAIL_COND_V(is_normalized() == false, Quat());
#endif #endif
return Quat(-x, -y, -z, w); return Quat(-x, -y, -z, w);
} }
Quat Quat::slerp(const Quat &q, const real_t &t) const { Quat Quat::slerp(const Quat &q, const real_t &t) const {
#ifdef MATH_CHECKS #ifdef MATH_CHECKS
ERR_FAIL_COND_V(is_normalized() == false, Quat(0, 0, 0, 0)); ERR_FAIL_COND_V(is_normalized() == false, Quat());
ERR_FAIL_COND_V(q.is_normalized() == false, Quat(0, 0, 0, 0)); ERR_FAIL_COND_V(q.is_normalized() == false, Quat());
#endif #endif
Quat to1; Quat to1;
real_t omega, cosom, sinom, scale0, scale1; real_t omega, cosom, sinom, scale0, scale1;
@ -192,7 +192,10 @@ Quat Quat::slerp(const Quat &q, const real_t &t) const {
} }
Quat Quat::slerpni(const Quat &q, const real_t &t) const { Quat Quat::slerpni(const Quat &q, const real_t &t) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V(is_normalized() == false, Quat());
ERR_FAIL_COND_V(q.is_normalized() == false, Quat());
#endif
const Quat &from = *this; const Quat &from = *this;
real_t dot = from.dot(q); real_t dot = from.dot(q);
@ -211,7 +214,10 @@ Quat Quat::slerpni(const Quat &q, const real_t &t) const {
} }
Quat Quat::cubic_slerp(const Quat &q, const Quat &prep, const Quat &postq, const real_t &t) const { Quat Quat::cubic_slerp(const Quat &q, const Quat &prep, const Quat &postq, const real_t &t) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V(is_normalized() == false, Quat());
ERR_FAIL_COND_V(q.is_normalized() == false, Quat());
#endif
//the only way to do slerp :| //the only way to do slerp :|
real_t t2 = (1.0 - t) * t * 2; real_t t2 = (1.0 - t) * t * 2;
Quat sp = this->slerp(q, t); Quat sp = this->slerp(q, t);

View file

@ -84,7 +84,9 @@ public:
} }
_FORCE_INLINE_ Vector3 xform(const Vector3 &v) const { _FORCE_INLINE_ Vector3 xform(const Vector3 &v) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V(is_normalized() == false, v);
#endif
Vector3 u(x, y, z); Vector3 u(x, y, z);
Vector3 uv = u.cross(v); Vector3 uv = u.cross(v);
return v + ((uv * w) + u.cross(uv)) * ((real_t)2); return v + ((uv * w) + u.cross(uv)) * ((real_t)2);

View file

@ -120,11 +120,11 @@ Transform Transform::interpolate_with(const Transform &p_transform, real_t p_c)
/* not sure if very "efficient" but good enough? */ /* not sure if very "efficient" but good enough? */
Vector3 src_scale = basis.get_scale(); Vector3 src_scale = basis.get_scale();
Quat src_rot = basis.orthonormalized(); Quat src_rot = basis.get_rotation_quat();
Vector3 src_loc = origin; Vector3 src_loc = origin;
Vector3 dst_scale = p_transform.basis.get_scale(); Vector3 dst_scale = p_transform.basis.get_scale();
Quat dst_rot = p_transform.basis; Quat dst_rot = p_transform.basis.get_rotation_quat();
Vector3 dst_loc = p_transform.origin; Vector3 dst_loc = p_transform.origin;
Transform dst; //this could be made faster by using a single function in Basis.. Transform dst; //this could be made faster by using a single function in Basis..

View file

@ -1785,8 +1785,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
} }
} }
Quat q = xform.basis; Quat q = xform.basis.get_rotation_quat();
q.normalize();
Vector3 s = xform.basis.get_scale(); Vector3 s = xform.basis.get_scale();
Vector3 l = xform.origin; Vector3 l = xform.origin;
@ -1838,8 +1837,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
xform = sk->get_bone_rest(nm.bone).affine_inverse() * xform; xform = sk->get_bone_rest(nm.bone).affine_inverse() * xform;
Quat q = xform.basis; Quat q = xform.basis.get_rotation_quat();
q.normalize();
Vector3 s = xform.basis.get_scale(); Vector3 s = xform.basis.get_scale();
Vector3 l = xform.origin; Vector3 l = xform.origin;

View file

@ -1983,8 +1983,7 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye
int bone = node->joints[i].godot_bone_index; int bone = node->joints[i].godot_bone_index;
xform = skeleton->get_bone_rest(bone).affine_inverse() * xform; xform = skeleton->get_bone_rest(bone).affine_inverse() * xform;
rot = xform.basis; rot = xform.basis.get_rotation_quat();
rot.normalize();
scale = xform.basis.get_scale(); scale = xform.basis.get_scale();
pos = xform.origin; pos = xform.origin;
} }