Working with animations is easy in Unity, and so is working with physics. However when you combine those two, things can go haywire. I wanted to write a short post about it and how to avoid some of the potential pitfalls.
If TL;DR: scroll down and read the summarum and check out the Unity webplayer demonstration.
Understanding Time in Unity
It’s a fundamental thing to understand how time works in Unity. In one hand you have the regular, variable time step update loop which is governed by the rendering, and on the other hand you have the physics, fixed time step update loop which is governed by the physics engine. Because of their nature, they’re never quite in sync. This means that there are basically two instances of the same universe but in different time!
From regular world to physics world
By default the animations are updated in the regular update loop. This is perfectly fine, and gives us smooth visual results. However, because the time in physics world is different, objects updated in the regular update loop appear to move erratically in the physics world. If you’ve ever animated a collider and placed some physics objects on top of it, you might know what this means. Luckily this can be solved by forcing the animation to be updated in the physics loop – just use the Animate Physics setting in either Animator or Animation component.
The caveat with this is that once you go from the regular update to the physics update, you will start to get small jitter in the motion as the physics is never perfectly in sync with regular update. Again, luckily this can be solved with interpolation modes (see below).
Moving versus Reappearing
Once you set the animation to update in the physics loop, the physics engine sees the collider being updated at regular intervals. At every frame, the collider’s position is updated as dictated by the animation. That’s all we need, right? Unfortunately this doesn’t mean that the physics sees the collider moving. In fact, what the physics engine just sees is a collider without a rigidbody disappearing from somewhere, and appearing at someplace else! In physics perspective, the collider doesn’t have any movement speed, and it’s not moving in any direction. This will cause some issues.
First, because the collider is disappearing and appearing, there’s a great probability that the new position of the collider is actually intersecting with some of the rigidbodies in the world, causing erratic collisions and potential fall-throughs.
Secondly, if the animated collider is moving underneath some rigidbodies, there is no friction at play at all. This means that collider is simply sliding under those rigidbodies on top of it, leaving them be.
So how to fix it? Simple. Just add a rigidbody to the animated collider and you’re set. This ensures that the collider has a proper physical response. Remember to set it to kinematic!
Getting Really Out of Sync!
It’s a noble goal to have your update loop and fixed update loop are running somewhat at the same pace (say, 60Hz) – everything looks smooth and jitter-free. But when your update loop rate is nothing near a multiple of the fixed update loop rate, you start to see sync problems.
Quick example: let’s say your regular update is running about 45 FPS (22.22ms delta time) while you have set the physics to run at 60 Hz (16.66ms delta time). This means that roughly for every 3 regular updates there will be 4 physics updates. And because there can be only integer number of physics updates per frame, this means that two of the frames will have 1 physics update and one will have 2 updates. It gets even worse with 40 FPS regular update rate and 60 Hz physics update rate (why?)
On the other hand, if you lower your physics update rate to something like 10 Hz (which you really should, just to test your game physics), you get opposite effect. There will be frames where physics is not updated at all. If you rely on the fact that FixedUpdate gets called every frame just because your FPS is lower than your physics update rate, don’t! Bugs are known to exists because of that 🙂
Past or future?
While these settings fix the physics side of things, the physics animation is more or less out of sync from the visual representation every frame. For this Unity offers a way to interpolate the position of rigidbody for the regular update. There are two modes: interpolation and extrapolation. (The interpolation mode is not only for animation, it works with any rigidbody)
Interpolation means that the position for the object is calculated by taking the current update time, and moving it backwards one physics update delta time. Now there are at least two physics updates: one behind the chosen time and one ahead. Unity simply interpolates between those two updates to conceive a position which it then uses for the update position. This means that the interpolation is actually lagging behind one physics update! But it’s guaranteed to be rather smooth.
The other option is to use extrapolation. Instead of using those two physics updates and interpolate between them, Unity uses them to predict the future position for the object. While this doesn’t suffer from a lag, it’s unfortunately unable to see in the future correctly, causing a visual jitter when the prediction fails. And it will fail often, especially in sudden changes in motion (like collisions…)
Here are my recipe for solid physics-compatible animation in Unity:
- Add rigidbody to the animated collider for proper physics response and set it kinematic because of the animations (thanks T.M)
- Set the animation to run in the physics update (Animate Physics)
- Use interpolation for smooth visuals if needed
- Aim for same (or integer multiple) regular update and physics update rates where possible (i.e. 60Hz or 30FPS/60Hz etc)
I’ve created a small Unity webplayer demonstration to easy testing how these settings affect the physics stability.
There is a simple setup with a cube, a sphere and an animated platform. With the UI you can setup various things for the platform.
Be sure to test out all the settings and their combinations. Try these:
- No rigidbody, with or without physics animation (default settings). Objects stay in place, platform sliding beneath. When the platform rises, sphere simply goes through it.
- With rigidbody but no physics animation: The cube stays properly on the platform, but jitters noticeably. With 10Hz physics the cube gets really wonky.
- With rigidbody and physics animation: The cube stays on the platform as expected, sphere rolls and falls as expected. Works well even in 10Hz physics rate!
- No rigidbody, fast animation, 10Hz physics rate: Objects simply fall immediately through the platform as it moves into them.
- (Also test out the interpolation modes for the platform)
That’s it. If you have any feedback, leave it here or in twitter (@snlehton).