This article is a work in progress.
math.gl provides a "standard 3D library complement" of mathematical classes for handling rotations in 2D and 3D, such as classes for manipulating Euler
angles and Quaternion
s. As in any 3D math library, the key goals are enabling applications to easily and intuitively specify (parametrize) rotations, combine them with other rotations and other transformations, and ultimately transform points with the rotations or resulting transformations.
While math.gl is intended to help programmers' implement the typical 3D application's rotation functionality with a minimum amount of knowledge, and does not even attempt to support rotations in more than 3 dimensions, it should be pointed out that the mathematical treatment of rotations can be very complicated. For some context on this see the background section at the end of this article.
Also, a simple observation: Rotations around arbitrary points can be treated as rotations around the origin simply by applying a translation before the rotation, and the inverse translation after the rotation. Therefore, for simplicity, this discussion focuses solely on rotations around the origin.
A minimum of three values are required to fully specify a 3D rotation (another result of Euler's), e.g, Euler angles or unit quaternions.
However in many cases the best way to specify a rotation is to use four parameters: an axis and an angle.
Representation | Interpolation | Addition | Transforming points |
---|---|---|---|
Vector/Angle | - | - | Good |
Quaternion | Excellent | Excellent | Good |
4x4 Matrix | - | Excellent | Excellent |
Euler angle | - | - | - |
Per the Euler Rotation Theorem, any two 3D rotations can be combined into a single 3D rotation. A single 3D rotation happens around an axis, and the rotation is a certain angle. This means that it is possible to specify a rotation using four very understanable values: an axis and an angle.
One of the more "human readable" representation of a 3D rotation is the "Euler angle", simplistically, an "Euler angle" completely specifies a rotation using only 3 values, which are all "human readable" angles around the three coordinate axes, which is very appealing.
However, the conventions for Euler angle values can vary in a number of ways. Following three.js, the math.gl Euler
class uses intrinsic Tait-Bryan angles.
Note that the large number of representations means that Euler angles exchanged between e.g. different software systems may not be directly compatible (and in addition, converting between the various representations is not exactly easy), so unless care is taken this can cause "mind-numbing" confusion.
Because of the variability, a good approach is often to be extremely careful when importing and exporting Euler angles from your code, and convert angle Euler angles to Matrix or Quaternion representations (which are much less ambiguous) for further manipulation.
"Unit quaternions" are normally the best representation for "manipulation" of 3D rotations. Manpulation here mainly refers to the "composition" or "addition" and interpolation of rotations.
Note that unit quaternions are simply quaternions of norm (or length) equal to 1
, and while a general quaternion (as the name suggests) contains four components, a unit quaternion needs only three values to be fully specified.
Unit quaternions can be used to model 3 dimensional rotations.
qrvqr-1
Interpolation of quaternions is done using Spherical Linear intERPolation (aka SLERP).
When combining rotations with other transformations (translations, scalings, projections etc), 4x4 matrices are the representation of choice.
A rotation matrix
T RR = I
Note that a matrix R satisfying this can also include an inversion (improper rotation matrix)
new Euler();
new Euler();
While Euler angles are often a good way to specify 3D rotations, they can not directly be used to transfor points or vectors. To do that, they have to be converted to .
A rotation matrix
T RR = I
The fact that rotations. They can either be combined as w
Math with Euler Angles
Math with Quaternions
To avoid issues with gimbal locks and flips, it is recommended to use quaternions when interpolating rotations.
Calculate the quaternion that represents the rotation you want to apply (e.g. moves the start rotation to the target rotation), and then just interpolate q with the identity quaternion using slerp()
. The resulting quaternion can then be used directly to transform Vector
s or it can be transformed into a Matrix4
transformation matrix.
const qUnit = new Quaternion();
const qTarget = new Quaternion(...);
for (let ratio = 0; ratio < 1.0; ratio += 0.1) {
const qInterpolated = new Quaternion().slerp(qUnit, qTarget, ratio);
}
If you are new to working with rotations and the amount of complications outlined in this article seem overwhelming, take some comfort in the fact that rotations in three and higher dimensional spaces are indeed quite complicated to treat mathematically.
As an example, several fundamental properties of rotations are highly dependent on the number of dimensions involved. To help the reader who has not worked extensively with rotations build some "intuition" for the fact that 3D rotations are non-trivial, the following summary shows how the nice, structured properties of 2D rotations gradually disappear as the number of dimensions increase:
In two dimensions, rotations are highly structured and intuitive:
In three dimensions rotation start to loose some structure:
To give some contrast, in four and higher dimensions:
Euler
class uses intrinsic Tait-Bryan angles. "Intrinsic" means that rotations are performed with respect to the local coordinate system. That is, for order 'XYZ', the rotation is first around the local-X axis (which is the same as the world-X axis), then around local-Y (which may now be different from the world Y-axis), then local-Z (which may be different from the world Z-axis).