When simulating rigid-body dynamics in three dimensions, we quickly run into an issue that’s not present in two: rotating objects in three dimensions behave in ways that can be surprising and are kind of weird. In this post I’ll present a theoretical framework for describing this behaviour, then look at some existing approaches to simulating the motion of rotating rigid bodies and finally suggest a method with improved energy conservation properties, which I believe to be novel.

First Principles

In this post I’ll describe the three classes of rotating objects, how they behave and how we can treat them. The dynamics of a freely rotating body can be derived from the following:

  1. An object has a moment of inertia , the rotational analog of mass, which is constant and fixed to the object itself. The moment of inertia is a symmetric positive-definite matrix, meaning that in some frame of reference it is a diagonal matrix with positive entries. This frame of reference rotates with the body, so I’ll denote it the body frame. The coordinate axes of the body frame (the eigenvalues of the moment of inertia) are called the body’s principal axes. It’s not really relevant here, but it makes most sense to place the origin of the body frame at the object’s centre of mass, as this is the point a free object will rotate around. As it is symmetric positive-definite, The moment of inertia matrix is always invertible. I will use its inverse in this post a lot, so I will give it its own symbol: .
  2. An object has an angular momentum , which is a conserved quantity for free motion (torque-free, drag-free, contact-free, you know the drill). Its length is constant in any frame of reference, and its direction is constant in any frame of reference that is not itself rotating (being a physicist, I may call such a frame of reference the lab frame, and I’ll use this fairly interchangeably with world-space).
  3. The object’s orientation , at any instantaneous point in time, rotates with an angular velocity of . In the lab frame, is constant but (and therefore ) is not. In the body frame, and are constant but is not. is not necessarily constant in either frame of reference, though it can be if is aligned with one of the object’s principal axes.
  4. The final conserved quantity is the rotational energy, half the dot product of the angular velocity and the angular momentum: .

Rotations

Something I’ll use throughout this post is Rodrigues’ rotation formula, which expresses a rotation matrix as a function of its “scaled axis” representation (i.e. ). In several equivalent forms:

A first interesting result here is that, if you’re happy to conflate with (which is common for many finite-difference rotation methods that do first order update followed by normalisation), you can get to a length-preserving rotation operation without the need for any transcendental (e.g. trigonometric or exponential) or even square root calculations! (for more on this see Fast, Approximate Rotation Operators)

For a typical “rotate vector according to a given angular velocity” situation we have:

That’s two cross products, a squared magnitude, some additions and a vector-scalar division, for a length-preserving rotation operation! The only compromise is that it slightly distorts time, rotating for a modified time , meaning about 5% of the rotation angle is lost if you rotate by an eighth of a full turn in a single iteration, or about 15% for a quarter-turn per iteration.

As noted earlier this is an equivalent loss of angular velocity to the explicit integration of rotations by doing and then renormalising the quaternion.

Something that’s rotating very fast will be limited to a maximum of a half-turn per iteration, but that’s already the case for many low-order rotation approximations. I assume this formula isn’t novel, but I’ve never seen it before and I was surprised to see it drop out like that! I’d always assumed either trig functions or square roots would be required for length-preserving rotations.

Anyway, back to rigid-body dynamics. I’ll start by going over some background, deriving the usual formulas from the conservation laws I proposed above.

Euler’s Equations

Call the (constant) body-frame inertia and its inverse and respectively. If the body has an orientation (or “attitude”) given by the rotation matrix , then in the lab frame, we can compute the world-space inertia matrix (and its inverse):

is (by definition) not a constant for a rotating body, so the lab-frame inertias may not be either. We can also calculate the body-space angular momentum:

The evolution of the angular velocity follows from angular momentum conservation :

In body coordinates, similarly:

In the above I have used the derivative of the body’s orientation, referencing point 3 above and Rodrigues’ formula:

The differential equation for the angular velocity comes out the same in both cases:

These are the famous Euler’s equations for rigid body dynamics (not to be confused with Euler’s equation, which describes incompressible fluids. Give someone else a go, Leonhard). In their usual formulation they’re stated component-wise, in the body frame:

In the body frame, the constancy of the moment of inertia lets us get a differential equation for the evolution of the angular momentum (in world space, this is just the conservation law ):

We can write an analogous set of equations for the angular momentum in body space:

I like these equations because they involve only quantities that are constant in one frame or the other: as changes in the body frame, it’s clear that the body must have rotated in world space such that remains unchanged.

An interesting thing to note here is that the body-space evolution of the angular momentum is insensitive to the absolute values of the three principal inverse inertias, as it only depends on differences between them. Any multiple of the identity matrix can be added to and the trajectory of the vector in the body frame remains unchanged. Furthermore, because each term in the Euler momentum equations is either a time derivative, proportional to the components, or zero, constant multiples of the same matrix all produce the same overall trajectory of in body space with the only difference being a scaling of the time evolution: the angular momentum of a body with inverse inertia will take the same path through body-space as that of a body with inverse inertia , but the vector of the first body will move through its local frame twice as fast as that of the second body.

Note however that even knowing the exact evolution of the angular momentum vector in body space does not fully specify the solution we’re looking for, that is the evolution of the object’s orientation in world space. The body-space solution is blind to rotations of the body around the angular momentum, as these do not affect the body-space angular momentum.

A full solution can be obtained by choosing a unit vector orthogonal to the angular momentum, call it . Then, the motion of the body consists of choosing the rotation which both fulfils the Euler equations and maintains the direction of in world-space. The evolution of in world-space is constrained to the plane perpendicular to the angular momentum, so it can be described as a rotation around the angular momentum. Composing the rotation induced by evolving the Euler equations (to keep and constant in world-space) with a rotation around itself (to match the needed evolution of in world-space) produces the full dynamics.

It is this additional rotation around that is affected by offsets to : compared to a body with inverse inertia , a body with inverse inertia (where is a scalar and still the identity matrix) rotates with an additional angular velocity . As with the body-space evolution, scaling applies a similar scaling to the speed of the rotation component around .

An analytic solution to Euler’s equations is attributed to Jacobi, and is expressed in terms of the Jacobi elliptic functions, defined by of integrals. Full solutions based on the Jacobi solution to the Euler equations are presented in - for example - Numerical implementation of the exact dynamics of free rigid bodies and The Exact Computation of the Free Rigid Body Motion and Its Use in Splitting Methods (preprint available). In particular, the approach proposed in the latter paper, using a unit vector proportional to the time derivative of (body-space) angular momentum as , stands out to me as particularly elegant. We’ll rediscover it later.

Now I’ve covered the general shape of the problem, I will focus on the three particular special cases: the spherical top, the symmetric top and the asymmetric top.

The Spherical Top

If we’re just thinking about the most symmetric objects, everything is fine. Spheres and cubes fit into this category, as do other platonic solids and anything that has the right symmetries. The moment of inertia of an object in this category is isotropic - a scalar multiple of the identity matrix - which means that their angular velocity and angular momentum are always parallel to one another. In the absence of external torques, these objects will just spin around that common axis forever perfectly happily, with constant angular velocity.

Euler’s equations become trivial in this case, because :

To advance a simulated body by a time , we can just rotate it by :

The Symmetric Top

The next simplest category of objects are those with two of their principal angular inertia values identical, and one different, exemplified by the cylinder. You could imagine that it makes a difference whether the cylinder is a long rod (with its unique principal inertia greater than the others) or a disc (with unique inertia less than the other two), and while these cases look quite different the mathematics works out mostly the same in both cases. The cylindrical object will, if its angular momentum is oblique (neither parallel nor perpendicular) to its special axis, spin in a precessing pattern. It’s easiest to think about this motion as spinning at a particular speed around the axis of the object, composed with a rotation of that axis around the angular momentum vector (which, as a conserved quantity, remains constant).

Looking at the Euler equation, set and :

The angular momentum component along the special axis, , is constant. The other two components look like a planar oscillation with frequency :

Substituting each equation into the time derivative of the other yields an oscillator ODE for each component, indicating that the “perpendicular” component of the angular momentum, in body space, rotates around its special axis with frequency .

To advance the simulated body in world space, rotate by about the object’s unique axis ( in world space). I note here that this axial angular velocity is that obtained from the world-space angular momentum and a modified inverse inertia tensor - where the subtraction of a scalar from a matrix implicitly multiplies the scalar by the identity matrix, such that .

Then rotate the body around its angular momentum vector by an angle . Rotating the body around the angular momentum in world space leaves the body-space angular momentum unchanged, so we still satisfy Euler’s equations. Note that the “precession” angular velocity and the previous, “axial” angular velocity sum to . That means the instantaneous rotation of the body has angular velocity , as required by point 3 above.

All in all, we have:

This amounts to a “splitting” the contribution of the total angular velocity into the “axial” rotation (which solves the Euler equation, rotating the angular momentum in body space (or equivalently the body in world space) in a way that preserves the rotational energy of the body) and the “precessional” rotation , which rotates the body around the angular momentum vector and therefore does not affect any of our conserved quantities. This matches the body-space/world-space splitting discussed in the previous section.

The Asymmetric Top

The most complicated, and most general type of body is referred to as the asymmetric top. Bodies in this category have three distinct principal moments of inertia, and can “tumble” in ways that appear unpredictable and chaotic. If you’re reading this, and have got this far, you’re probably already aware of the Dzhanibekov effect/Tennis racquet theorem/intermediate axis theorem. If not, the linked Wikipedia page has a bunch of nice demonstrations of it.

The long and short of it is: an asymmetric object that’s rotating with angular momentum mostly aligned to its “shortest” or “longest” axis will precess in a little ellipse, similar to the way a symmetric object precesses in a circle. As the angular momentum approaches the intermediate axis, the nice ellipse distorts into a weird shape (Wikipedia compares it to a taco, I’d more readily reach for pringles as a comparison). If its angular momentum is close enough to the “intermediate” axis, the precessions are less like a steady, gentle rocking back and forth, and more like a periodic, violent inversion of the object. An analytic solution for this motion (the equivalent to what I presented above for the more symmetric classes of body) does exist, but it uses significantly more exotic special functions than the trig functions I’ve been relying on thus far (in Rodrigues’ formulas for rotation operators). The papers mentioned above go through the exact solution using the Jacobi elliptic functions , and which roughly resemble , and respectively. Their behaviour is modified by a parameter which quantifies how “taco-like” the precessions are, and increases as the angular momentum gets closer to the intermediate axis.

I’ll review some prior art for solving this general case, talking through how well they obey the conservation laws I detailed at the top of this post.

Forward Euler

The most naïve approach possible is good old Forward Euler, no mitigations.

This was approximately the method used in the earliest versions of Avian physics (back when it was bevy_xpbd, and up to Avian 0.1.0) It was abandoned on account of being massively unstable for asymmetric objects: look at the evolution of the magnitude of the angular momentum (a quantity that should be conserved!):

The quantity is going to appear repeatedly, so I’ve given it a shorthand name, . As the squared magnitude of a vector, is non-negative, so the magnitude of the angular momentum increases monotonically. This is actually worse than it looks: As is quadratic in the magnitude of the angular momentum, - the growth in the angular momentum is faster than exponential. It blows up to infinity in finite time - both analytically and in my numerical tests

Needless to say, energy conservation also doesn’t come out of this well:

Its not as obvious, but because is positive-definite, is positive whenever is nonzero. The energy also blows up to infinity. Not ideal.

The “Jolt” method

After some time using an implicit method for its rotational integration (which I won’t go into here - being implicit makes it harder to analyse!) in response to the instability of the explicit method, Avian has now switched to using a method borrowed from the Jolt physics engine. This method is conceptually pretty simple: just apply an explicit update to the angular momentum, then renormalise it!

The magnitude of the angular momentum is explicitly conserved, so that resolves the first of the blow-ups we saw in the explicit method. Looking at the energy:

Here I have introduced the notation and similarly . The and values are the effective scalar magnitude of the matrix , in the direction of and respectively, which are necessarily bounded by the eigenvalues of and will generally be some weighted average of those eigenvalues. The timestep-dependent factor looks like a quadratic for small values of its parameter, but saturates to 1 as the parameter becomes large. Importantly, the sign of is now not necessarily positive. can be either positive or negative, and qualitative experimentation indicates that the overall effect over several timesteps is a reasonably good conservation of energy. In particular, because and and because this method explicitly conserves , the energy is bounded from above and below: .

When applied to a cylindrical body, it’s not too hard to see that is a constant, . Because , for cylindrical bodies this looks like an evolution towards , and bodies of this type will slowly align their multiplicity-2 axis with their angular momentum. For oblate (puck-like) bodies and so energy is lost; for prolate (rugby ball-like) bodies so energy is gained. In both cases the energy is bounded by , though.

Through numerical experiments, I noticed that this method in fact seems to cause to approach the median principal inverse inertia, call it . Having seen this I was able to go through some very tedious algebra to find that .

Without loss of generality I assume the ordering , and because is a combination of the three principal values, we also have . Then, is the only factor in the above term that can be either positive or negative. , and are unconditionally positive, meaning that the increment of is a positive multiple of . This is positive for and negative for so is pushed towards in all cases. This has a stabilising effect, meaning energy tends towards a limiting value determined by the median eigenvalue of . For cylindrical bodies, the median eigenvalue is the repeated one, and so a long bar will gradually “lie down” to rotate around its short axes. A flat plate will gradually “stand up” to rotate around its wide axes.

Rotating the Angular Momentum

Looking at the Jolt method, the initial modification of the angular momentum looks a bit like it’s a first-order approximation to rotating by . So, how about doing this:

Once again our angular momentum’s magnitude is conserved, so let’s look straight at the energy. I’ll employ Rodrigues’ rotation formula, with the shorthand and :

Using the following expansions:

I get to:

To lowest order in time, We still have the monotonic growth in energy shown by the explicit method, not the factor we had for the Jolt method (although now that is conserved, at least the maximum energy is bounded). Unlike the Jolt method, which causes to approach the median eigenvalue of , this new method causes it to approach the largest eigenvalue of . For cylindrical bodies, the largest eigenvalue of is for long bars and for flat plates. Therefore a long bar will - contrary to the Jolt method - “stand up” to spin around its long axis. A flat plate will behave similarly to the Jolt method.

This isn’t what we wanted, and implies the Jolt method is actually doing something different to just “low order approximation to rotating around “. It took me a long time and a lot of scribbling to figure out what the difference is, and the key is that the normalisation step, , shrinks all components of isotropically, whereas a true rotation leaves the component of a vector parallel to the axis unchanged. Then I realised that while is indeed a first-order approximation to a rotation around , it’s not a one-to-one correspondence: treated as a linear operator, the cross product with has a zero eigenvalue (with the corresponding eigenvector being itself). That means that for any scalar value , the above expression is a first-order approximation to a rotation around , with the same :

The Jolt Method in Rotation Form (Properly)

It turns out that all we need to do to reproduce the Jolt method is figure out the right value of . Then the Jolt method is approximately a rotation with angular velocity . The key insight here is that if , shrinks all of the components of , but the component parallel to the axis must be unchanged, then that component must be zero!

So we have . Cool! What’s our energy looking like now? First, angular momentum:

Where I’ve used the fact that to simplify. Now the energy:

For the term, I have used the following simplification:

Substituting the value , and therefore that we have:

Whew. That’s what we were shooting for though! This method is good because the quadratic term is not always positive, and as an added bonus the higher-order terms vanish (apart of course from the terms arising due to the sinc and cosine terms, which is a multiplier of ). Using that result from previously to simplify , we can also write this as:

The next question is of course: Can we do any better? Can we nix the quadratic term entirely?

Finding a better

We’ve now established that stepping the Euler equations using a rotation around a modified angular momentum can work well, showing that produces results comparable to the Jolt method. But could a different value of produce even better results?

There’s a few different approaches we could take to this, and they all give the same answer. Let’s think about the time derivatives of the rotational energy. Rather than evaluating derivatives using Euler’s equations, I’ll treat the evolution as a rotation about and we’ll see what happens

This is trivially satisfied given the form we’ve chosen for : . Good start.

The second derivative gives us:

There we go: For this second derivative to vanish, we need , so .

Looking back at the energy conservation expressions from earlier, we now have:

That looks promising, we’re now third-order.

As a further note, I’ll calculate here what looks like for a symmetric top, with eigenvalues :

Notice that, under my proposed scheme, , the finding that means we exactly reproduce the analytic integration of the symmetric top! Looking back at the energy equation to confirm for this case:

As expected, exact conservation for the symmetric top!

Numerical Experiments

I’ve put together a little toy to let me play with these algorithms, embedded below (assuming it works… I’m not a web dev I don’t know what I’m doing).

The way it works is this: The “range” of the principal inverse moments, has a fixed value of 1, because changing it is equivalent to changing the timestep and duration of the simulation by the same factor. You can use the first slider to adjust the “slow” (small) inverse moment between 0.1 and 5, adding a constant value to all of the inverse moments. Changing this value only changes the exact solution in terms of the world-space rotation about the angular momentum; it should not affect the body-space trajectory of the angular momentum vector. How well this symmetry is preserved in practice is a property of the different simulation methods. The “median” inverse moment varies between and , controlled using the second slider. The “energy” slider adjusts the initial rotational energy of a simulated body between the minimum () and maximum () possible values, and you can set the (approximate) number of timesteps per rotation to use. Setting the “Energy” and “Median J” sliders close to each other produces the highly “taco-shaped” trajectories of the Dzhanibekov effect, and setting “Median J” all the way to the left or right produces “symmetric top” behaviour corresponding to a long bar or a flat plate respectively.

A body is simulated rotating with initial angular momentum along the z-axis and of unit magnitude. The graphs show how the simulation progresses. By default the results are shown for four integrators: the basic explicit integrator, the Jolt integrator, the naive rotation algorithm, and the two approaches I propose in the next section. To focus on one or another, you can toggle visibility for the lines from each integrator by clicking its entry in the legend below the graphs.

The first two plots are line graphs: the first showing the “energy factor” and the second showing the magnitude of the angular momentum throughout the simulation. A time-axis slider located above these graphs can be used to zoom in on a smaller region of the simulation time. Both of these line graphs should stay as close as possible to their original values to fulfil physical conservation laws.

The polar plot below the “energy factor” line graph shows the evolution of the transverse (x and y) components of the angular momentum throughout the simulation. This should stay as close to the origin as possible, as the direction of the angular momentum should remain constant in world space.

Finally, the remaining three polar plots show the evolution of the body-space angular momentum throughout the simulation. The bottom-right plot shows the x and z components (aligned with the minimum and maximum principal values of respectively). The plot to its left shares its vertical axis (showing the y and z components of ) and the one above it shares its horizontal axis (showing the x and y components). These three plots should represent a closed loop, because the body-space trajectory of the angular momentum is periodic. If they instead spiral in towards the x-axis, energy is being lost, and if they spiral towards the z-axis, energy is being gained. If instead (as the Jolt method does) the trajectory becomes more irregular over time, then is approaching . These three plots should be insensitive to the value chosen on the “Min J” slider, but this is not the case for the “naive rotation” method.

My recommendation

I have two recommendations for authors of rigid body simulations, depending on their preference.

”Modified Jolt” Method

Continue to use the typical split between (angular) velocity integration and position (orientation) integration:

For the velocity update, use:

Optionally, use the “fast length-preserving rotation” found at the start of this post to implement the angular momentum integration:

The advantage of this approach is that it can slot naturally into a conventional physics engine integrator, replacing the handling of gyroscopic effects that is already implemented. It inherits from that general approach the disadvantage that the direction of angular momentum in world space is only approximately conserved, in contrast to my next suggestion

”Momentum-first” Method

Treat the velocity update stage as a momentum update:

For the position update, perform the relevant rotation and update the angular velocity to reflect the new orientation afterwards.

This treats angular momentum and orientation as the “fundamental” quantities, and angular velocity as something derived from a given momentum and orientation. Unlike the first option, it naturally preserves the direction of the angular momentum, not just its magnitude. It is a bit more of a radical departure from typical design of a rigid body integrator though.