Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save davidfoster/6d01f61d7476ed077e8225672340591c to your computer and use it in GitHub Desktop.
Save davidfoster/6d01f61d7476ed077e8225672340591c to your computer and use it in GitHub Desktop.
Understanding Quaternions Programmatically
// deconstruct our rotation into angle/axis formation.
float rotationAngle;
Vector3 rotationAxis;
transform.rotation.ToAngleAxis(out rotationAngle, out rotationAxis);
// construct a new rotation from axis and angle.
// Qv,θ = |v * sin(θ/2), cos(θ/2)|, where v = axis, θ = angle in radians.
float sinThetaOver2 = Mathf.Sin((rotationAngle * Mathf.Deg2Rad) / 2f);
float cosThetaOver2 = Mathf.Cos((rotationAngle * Mathf.Deg2Rad) / 2f);
Quaternion newRotation = new Quaternion(
rotationAxis.x * sinThetaOver2,
rotationAxis.y * sinThetaOver2,
rotationAxis.z * sinThetaOver2,
cosThetaOver2
);
// these quaternions are now the same.
Debug.Log(transform.rotation == newRotation);
// we can now deconstruct our new rotation to find our axis and angle.
// Q.w = cos(θ/2) => θ = arcos(Q.w * 2).
float theta = (Mathf.Acos(newRotation.w) * 2f) * Mathf.Rad2Deg;
// these angles are now the same.
Debug.Log(rotationAngle == theta);
// and now work out the axis using the known angle.
// Qx = vx * sin(θ/2) => vx = Qx / sin(θ/2).
Vector3 axis = new Vector3(
newRotation.x / (Mathf.Sin((theta * Mathf.Deg2Rad) / 2f)),
newRotation.y / (Mathf.Sin((theta * Mathf.Deg2Rad) / 2f)),
newRotation.z / (Mathf.Sin((theta * Mathf.Deg2Rad) / 2f))
);
// note that there is a special case where the axis should point right if the rotation is identity, in which case the above
// calculations resolve NaN.
if (newRotation == Quaternion.identity) {
axis = Vector3.right;
}
// these axes are now the same.
Debug.Log(rotationAxis == axis);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment