public static Vector3 QuaternionToEuler(Quaternion q)
{
Vector3 euler;
// if the input quaternion is normalized, this is exactly one. Otherwise, this acts as a correction factor for the quaternion's not-normalizedness
float unit = (q.x * q.x) + (q.y * q.y) + (q.z * q.z) + (q.w * q.w);
// this will have a magnitude of 0.5 or greater if and only if this is a singularity case
float test = q.x * q.w - q.y * q.z;
if (test > 0.4995f * unit) // singularity at north pole
{
euler.x = Mathf.PI / 2;
euler.y = 2f * Mathf.Atan2(q.y, q.x);
euler.z = 0;
}
else if (test < -0.4995f * unit) // singularity at south pole
{
euler.x = -Mathf.PI / 2;
euler.y = -2f * Mathf.Atan2(q.y, q.x);
euler.z = 0;
}
else // no singularity - this is the majority of cases
{
euler.x = Mathf.Asin(2f * (q.w * q.x - q.y * q.z));
euler.y = Mathf.Atan2(2f * q.w * q.y + 2f * q.z * q.x, 1 - 2f * (q.x * q.x + q.y * q.y));
euler.z = Mathf.Atan2(2f * q.w * q.z + 2f * q.x * q.y, 1 - 2f * (q.z * q.z + q.x * q.x));
}
// all the math so far has been done in radians. Before returning, we convert to degrees...
euler *= Mathf.Rad2Deg;
//...and then ensure the degree values are between 0 and 360
euler.x %= 360;
euler.y %= 360;
euler.z %= 360;
return euler;
}
public static Quaternion EulerToQuaternion(Vector3 euler)
{
float xOver2 = euler.x * Mathf.Deg2Rad * 0.5f;
float yOver2 = euler.y * Mathf.Deg2Rad * 0.5f;
float zOver2 = euler.z * Mathf.Deg2Rad * 0.5f;
float sinXOver2 = Mathf.Sin(xOver2);
float cosXOver2 = Mathf.Cos(xOver2);
float sinYOver2 = Mathf.Sin(yOver2);
float cosYOver2 = Mathf.Cos(yOver2);
float sinZOver2 = Mathf.Sin(zOver2);
float cosZOver2 = Mathf.Cos(zOver2);
Quaternion result;
result.x = cosYOver2 * sinXOver2 * cosZOver2 + sinYOver2 * cosXOver2 * sinZOver2;
result.y = sinYOver2 * cosXOver2 * cosZOver2 - cosYOver2 * sinXOver2 * sinZOver2;
result.z = cosYOver2 * cosXOver2 * sinZOver2 - sinYOver2 * sinXOver2 * cosZOver2;
result.w = cosYOver2 * cosXOver2 * cosZOver2 + sinYOver2 * sinXOver2 * sinZOver2;
return result;
}