Angular Velocity Integration in PhysX
I came across some odd behavior when debugging some of the core physics code in the Unity engine. If we start with a still rigid body, say:
body.rotation: Quaternion(0.671550453, 0.243898988, 0.07047556, 0.696108162)
body.angularVelocity: Vector3(0, 0, 0)
and then directly set the body’s angular velocity to a new value:
body.angularVelocity = new Vector3(-1.21769, -0.8254209, 0.107366793);
The final rotation of the body after one physics step is always slightly less than it should be. If you run the math, the correct rotation after a time step of 1/72
seconds is:
body.rotation: Quaternion(0.6714375, 0.243848488, 0.07051581, 0.696230769) // Mathematically correct, using axis-angle
body.rotation: Quaternion(0.665043, 0.24099271, 0.07277777, 0.7030958) // What Unity returns
In this case, this is only difference of 1.151
degrees, but when the angular velocity is high, say (36, 10, 11)
, the final Unity value can be off by 30 degrees! That’s a very noticeable amount!
But.. why?
I lucked out on this one. I’ve been delving into the dark secrets of quaternions for a totally separate project, and a couple months back I stumbled on an approximation for applying angular velocities to quaternions, mentioned in this StackOverflow post:
As it turns out, this is precisely the approximation used by PhysX for applying a rigid body’s angular velocity. If we run the numbers, we get the results we expect:
body.rotation = Quaternion(0.665043354, 0.240992859, 0.0727777, 0.7030955) // Approximated formula
body.rotation = Quaternion(0.665043, 0.24099271, 0.07277777, 0.7030958) // What Unity returns
Now that’s clean. We’re within a factor of floating point rounding! Much better.
Does this matter? It does in our case. For our object grabbing code, we need to calculate the precise angular velocity to apply to a body, such that it will rotate to the orientation of the hand in the next time step. This inaccuracy made objects feel just slightly bouncy, rather than snapped to the hand (particularly noticeable under strong rotations of the wrist).
I love little micro-discoveries like this. It’s one step closer to truly understanding how your game engine is put together.
-JA