summaryrefslogtreecommitdiff
path: root/core/math
diff options
context:
space:
mode:
authorlawnjelly <lawnjelly@gmail.com>2023-05-09 13:49:26 +0100
committerRĂ©mi Verschelde <rverschelde@gmail.com>2023-05-12 12:31:23 +0200
commitefbb28d09a2a4aaa53875edd827e08137f9f19f4 (patch)
tree01516ffb51e02974f48ac1643f38de29396ec6fd /core/math
parentb91b8fce43ab9cb9f8c96f8c640acc801774b6b5 (diff)
Make acos and asin safe
A common bug with using acos and asin is that input outside -1 to 1 range will result in Nan output. This can occur due to floating point error in the input. The standard solution is to provide safe_acos function with clamped input. For Godot it may make more sense to make the standard functions safe. (cherry picked from commit 50c5ed4876250f785be54b8f6124e7663afa38dc)
Diffstat (limited to 'core/math')
-rw-r--r--core/math/basis.cpp4
-rw-r--r--core/math/math_funcs.h10
-rw-r--r--core/math/quaternion.cpp3
3 files changed, 10 insertions, 7 deletions
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index 95a4187062..bfd902c7e2 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -807,8 +807,8 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
z = (rows[1][0] - rows[0][1]) / s;
r_axis = Vector3(x, y, z);
- // CLAMP to avoid NaN if the value passed to acos is not in [0,1].
- r_angle = Math::acos(CLAMP((rows[0][0] + rows[1][1] + rows[2][2] - 1) / 2, (real_t)0.0, (real_t)1.0));
+ // acos does clamping.
+ r_angle = Math::acos((rows[0][0] + rows[1][1] + rows[2][2] - 1) / 2);
}
void Basis::set_quaternion(const Quaternion &p_quaternion) {
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 078320d620..f96d3a909f 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -74,11 +74,13 @@ public:
static _ALWAYS_INLINE_ double tanh(double p_x) { return ::tanh(p_x); }
static _ALWAYS_INLINE_ float tanh(float p_x) { return ::tanhf(p_x); }
- static _ALWAYS_INLINE_ double asin(double p_x) { return ::asin(p_x); }
- static _ALWAYS_INLINE_ float asin(float p_x) { return ::asinf(p_x); }
+ // Always does clamping so always safe to use.
+ static _ALWAYS_INLINE_ double asin(double p_x) { return p_x < -1 ? (-Math_PI / 2) : (p_x > 1 ? (Math_PI / 2) : ::asin(p_x)); }
+ static _ALWAYS_INLINE_ float asin(float p_x) { return p_x < -1 ? (-Math_PI / 2) : (p_x > 1 ? (Math_PI / 2) : ::asinf(p_x)); }
- static _ALWAYS_INLINE_ double acos(double p_x) { return ::acos(p_x); }
- static _ALWAYS_INLINE_ float acos(float p_x) { return ::acosf(p_x); }
+ // Always does clamping so always safe to use.
+ static _ALWAYS_INLINE_ double acos(double p_x) { return p_x < -1 ? Math_PI : (p_x > 1 ? 0 : ::acos(p_x)); }
+ static _ALWAYS_INLINE_ float acos(float p_x) { return p_x < -1 ? Math_PI : (p_x > 1 ? 0 : ::acosf(p_x)); }
static _ALWAYS_INLINE_ double atan(double p_x) { return ::atan(p_x); }
static _ALWAYS_INLINE_ float atan(float p_x) { return ::atanf(p_x); }
diff --git a/core/math/quaternion.cpp b/core/math/quaternion.cpp
index 34e212a5b6..e4ad17c8ef 100644
--- a/core/math/quaternion.cpp
+++ b/core/math/quaternion.cpp
@@ -35,7 +35,8 @@
real_t Quaternion::angle_to(const Quaternion &p_to) const {
real_t d = dot(p_to);
- return Math::acos(CLAMP(d * d * 2 - 1, -1, 1));
+ // acos does clamping.
+ return Math::acos(d * d * 2 - 1);
}
Vector3 Quaternion::get_euler(EulerOrder p_order) const {