Fix Basis::get_euler incorrectly simplifying rotations in some cases.

This commit is contained in:
Adam
2025-01-28 21:41:31 -06:00
parent a013481b09
commit d56cbd374b
2 changed files with 29 additions and 18 deletions

View File

@@ -455,6 +455,11 @@ void Basis::get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) cons
}
Vector3 Basis::get_euler(EulerOrder p_order) const {
// This epsilon value results in angles within a +/- 0.04 degree range being simplified/truncated.
// Based on testing, this is the largest the epsilon can be without the angle truncation becoming
// visually noticeable.
const real_t epsilon = 0.00000025;
switch (p_order) {
case EulerOrder::XYZ: {
// Euler angles in XYZ convention.
@@ -466,8 +471,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
Vector3 euler;
real_t sy = rows[0][2];
if (sy < (1.0f - (real_t)CMP_EPSILON)) {
if (sy > -(1.0f - (real_t)CMP_EPSILON)) {
if (sy < (1.0f - epsilon)) {
if (sy > -(1.0f - epsilon)) {
// is this a pure Y rotation?
if (rows[1][0] == 0 && rows[0][1] == 0 && rows[1][2] == 0 && rows[2][1] == 0 && rows[1][1] == 1) {
// return the simplest form (human friendlier in editor and scripts)
@@ -501,8 +506,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
Vector3 euler;
real_t sz = rows[0][1];
if (sz < (1.0f - (real_t)CMP_EPSILON)) {
if (sz > -(1.0f - (real_t)CMP_EPSILON)) {
if (sz < (1.0f - epsilon)) {
if (sz > -(1.0f - epsilon)) {
euler.x = Math::atan2(rows[2][1], rows[1][1]);
euler.y = Math::atan2(rows[0][2], rows[0][0]);
euler.z = Math::asin(-sz);
@@ -532,8 +537,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
real_t m12 = rows[1][2];
if (m12 < (1 - (real_t)CMP_EPSILON)) {
if (m12 > -(1 - (real_t)CMP_EPSILON)) {
if (m12 < (1 - epsilon)) {
if (m12 > -(1 - epsilon)) {
// is this a pure X rotation?
if (rows[1][0] == 0 && rows[0][1] == 0 && rows[0][2] == 0 && rows[2][0] == 0 && rows[0][0] == 1) {
// return the simplest form (human friendlier in editor and scripts)
@@ -568,8 +573,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
Vector3 euler;
real_t sz = rows[1][0];
if (sz < (1.0f - (real_t)CMP_EPSILON)) {
if (sz > -(1.0f - (real_t)CMP_EPSILON)) {
if (sz < (1.0f - epsilon)) {
if (sz > -(1.0f - epsilon)) {
euler.x = Math::atan2(-rows[1][2], rows[1][1]);
euler.y = Math::atan2(-rows[2][0], rows[0][0]);
euler.z = Math::asin(sz);
@@ -596,8 +601,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
// -cx*sy sx cx*cy
Vector3 euler;
real_t sx = rows[2][1];
if (sx < (1.0f - (real_t)CMP_EPSILON)) {
if (sx > -(1.0f - (real_t)CMP_EPSILON)) {
if (sx < (1.0f - epsilon)) {
if (sx > -(1.0f - epsilon)) {
euler.x = Math::asin(sx);
euler.y = Math::atan2(-rows[2][0], rows[2][2]);
euler.z = Math::atan2(-rows[0][1], rows[1][1]);
@@ -624,8 +629,8 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
// -sy cy*sx cy*cx
Vector3 euler;
real_t sy = rows[2][0];
if (sy < (1.0f - (real_t)CMP_EPSILON)) {
if (sy > -(1.0f - (real_t)CMP_EPSILON)) {
if (sy < (1.0f - epsilon)) {
if (sy > -(1.0f - epsilon)) {
euler.x = Math::atan2(rows[2][1], rows[2][2]);
euler.y = Math::asin(-sy);
euler.z = Math::atan2(rows[1][0], rows[0][0]);