Files
glitchy-engine-beef/GlitchyEngineHelper/DotNetScriptingHelper/QuaternionExtensions.cs
T

69 lines
2.1 KiB
C#

using System.Numerics;
namespace DotNetScriptingHelper;
public static class QuaternionExtensions
{
public static (Vector3 Axis, float Angle) ToAxisAngle(this Quaternion quat)
{
// scalar part = cos(θ/2)
// So, we can extract the angle directly.
float angle = 2.0f * MathF.Acos(quat.W);
// vector part = axis * sin(θ/2)
// In other words, the vector part is the axis, but with length of sin(θ/2).
// We assume quaternion is unit length, so subtracting w^2 gives us length of just vector part (aka sin(θ/2)).
float length = MathF.Sqrt(1.0f - (quat.W * quat.W));
Vector3 axis;
// Normalize vector part to get the axis!
if (length == 0)
{
axis = Vector3.Zero;
}
else
{
length = 1.0f / length;
axis.X = quat.X * length;
axis.Y = quat.Y * length;
axis.Z = quat.Z * length;
}
return (axis, angle);
}
public static Vector3 ToEulerAngles(this Quaternion q)
{
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/
Vector3 result;
float sqw = q.W * q.W;
float sqx = q.X * q.X;
float sqy = q.Y * q.Y;
float sqz = q.Z * q.Z;
float unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
float test = q.X * q.Y + q.Z * q.W;
if (test > 0.4999f * unit)
{ // singularity at north pole
result.Y = 2.0f * MathF.Atan2(q.X, q.W);
result.Z = MathF.PI / 2.0f;
result.X = 0.0f;
return result;
}
if (test < -0.4999f * unit)
{ // singularity at south pole
result.Y = -2.0f * MathF.Atan2(q.X, q.W);
result.Z = -MathF.PI / 2.0f;
result.X = 0.0f;
return result;
}
result.Y = MathF.Atan2(2 * q.Y * q.W - 2 * q.X * q.Z, sqx - sqy - sqz + sqw);
result.Z = MathF.Asin(2 * test / unit);
result.X = MathF.Atan2(2 * q.X * q.W - 2 * q.Y * q.Z, -sqx + sqy - sqz + sqw);
return result;
}
}