diff --git a/core/math/quat.cpp b/core/math/quat.cpp
index d67dd2b3e68..fae2e2b78c5 100644
--- a/core/math/quat.cpp
+++ b/core/math/quat.cpp
@@ -33,6 +33,11 @@
#include "core/math/basis.h"
#include "core/print_string.h"
+real_t Quat::angle_to(const Quat &p_to) const {
+ real_t d = dot(p_to);
+ return Math::acos(CLAMP(d * d * 2 - 1, -1, 1));
+}
+
// set_euler_xyz expects a vector containing the Euler angles in the format
// (ax,ay,az), where ax is the angle of rotation around x axis,
// and similar for other axes.
diff --git a/core/math/quat.h b/core/math/quat.h
index ad0b95c75d1..eb68de1dbf3 100644
--- a/core/math/quat.h
+++ b/core/math/quat.h
@@ -48,6 +48,7 @@ public:
bool is_normalized() const;
Quat inverse() const;
_FORCE_INLINE_ real_t dot(const Quat &p_q) const;
+ real_t angle_to(const Quat &p_to) const;
void set_euler_xyz(const Vector3 &p_euler);
Vector3 get_euler_xyz() const;
diff --git a/core/variant_call.cpp b/core/variant_call.cpp
index dd0d110a8ae..0064507ca1f 100644
--- a/core/variant_call.cpp
+++ b/core/variant_call.cpp
@@ -497,6 +497,7 @@ struct _VariantCall {
VCALL_LOCALMEM0R(Quat, is_normalized);
VCALL_LOCALMEM1R(Quat, is_equal_approx);
VCALL_LOCALMEM0R(Quat, inverse);
+ VCALL_LOCALMEM1R(Quat, angle_to);
VCALL_LOCALMEM1R(Quat, dot);
VCALL_LOCALMEM1R(Quat, xform);
VCALL_LOCALMEM2R(Quat, slerp);
@@ -1816,6 +1817,7 @@ void register_variant_methods() {
ADDFUNC0R(QUAT, BOOL, Quat, is_normalized, varray());
ADDFUNC1R(QUAT, BOOL, Quat, is_equal_approx, QUAT, "quat", varray());
ADDFUNC0R(QUAT, QUAT, Quat, inverse, varray());
+ ADDFUNC1R(QUAT, REAL, Quat, angle_to, QUAT, "to", varray());
ADDFUNC1R(QUAT, REAL, Quat, dot, QUAT, "b", varray());
ADDFUNC1R(QUAT, VECTOR3, Quat, xform, VECTOR3, "v", varray());
ADDFUNC2R(QUAT, QUAT, Quat, slerp, QUAT, "to", REAL, "weight", varray());
diff --git a/doc/classes/Quat.xml b/doc/classes/Quat.xml
index 4b4e460b5db..e396d5d474a 100644
--- a/doc/classes/Quat.xml
+++ b/doc/classes/Quat.xml
@@ -57,6 +57,16 @@
Constructs a quaternion defined by the given values.
+
+
+
+
+
+
+ Returns the angle between this quaternion and [code]to[/code]. This is the magnitude of the angle you would need to rotate by to get from one to the other.
+ [b]Note:[/b] This method has an abnormally high amount of floating-point error, so methods such as [method @GDScript.is_zero_approx] will not work reliably.
+
+
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs
index 91c27c39f47..11fee88cad2 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs
@@ -113,6 +113,23 @@ namespace Godot
get { return Dot(this); }
}
+ ///
+ /// Returns the angle between this quaternion and `to`.
+ /// This is the magnitude of the angle you would need to rotate
+ /// by to get from one to the other.
+ ///
+ /// Note: This method has an abnormally high amount
+ /// of floating-point error, so methods such as
+ /// will not work reliably.
+ ///
+ /// The other quaternion.
+ /// The angle between the quaternions.
+ public real_t AngleTo(Quat to)
+ {
+ real_t dot = Dot(to);
+ return Mathf.Acos(Mathf.Clamp(dot * dot * 2 - 1, -1, 1));
+ }
+
///
/// Performs a cubic spherical interpolation between quaternions `preA`,
/// this vector, `b`, and `postB`, by the given amount `t`.