1
\$\begingroup\$

I'm new to Unity in general, and particularly to animations, but what I'm trying to do should be fairly basic so I'm probably doing something simple wrong.

I've broken this down into a very simple demo case: I need to spin a cube smoothly.

Here's what I've done:

  • Created a TestCube.
  • Using the Timeline window, created a Director component with a Playable.
  • Added an Animation Track to the timeline linked to TestCube (which automatically added the Animator component to the cube).

I then recorded a very simple animation with two keyframes, where I rotate TestCube 180 degrees.

Animation curve

The result looks okay at first glance, but in reality it is actually quite jittery and uneven. I created a simple script to log how much the cube rotates each frame. In my real application, I'm mainly working in FixedUpdate, but I'm interested in both, so I logged both.

using UnityEngine;

public class Test : MonoBehaviour
{
    private Quaternion previousUpdateRotation;
    private Quaternion previousFixedUpdateRotation;

    private void Awake()
    {
        previousUpdateRotation = transform.rotation;
        previousFixedUpdateRotation = transform.rotation;
    }

    private void Update()
    {
        Debug.Log($"Update|{Quaternion.Angle(previousUpdateRotation, transform.rotation)}");
        previousUpdateRotation = transform.rotation;
    }

    private void FixedUpdate()
    {
        Debug.Log($"FixedUpdate|{Quaternion.Angle(previousFixedUpdateRotation, transform.rotation)}");
        previousFixedUpdateRotation = transform.rotation;
    }
}

I then graphed the output:

Angle Delta - Update - Normal Angle Delta - FixedUpdate - Normal

As you can see, the rotation of the cube is very much not smooth. My first thought way maybe the Animator.UpdateMode parameter could help me. I set it to Animate Physics and ran the test again, hoping to get a better result on FixedUpdate. But I got similar results.

Angle Delta - Update - Animate Physics Angle Delta - FixedUpdate - Animate Physics

Can anyone tell me what I'm doing wrong? How can I get a smooth response to match the smoothness of the animation curve?

\$\endgroup\$
2
  • \$\begingroup\$ What version of the Editor are you using? What framerate are you getting in the Editor while the game is running? Does the giant spike in the graph reflect where the animation loops? Ignoring the jitter in your graph, does the animation look smooth (other than the moment when it loops back to the beginning)? \$\endgroup\$
    – Kevin
    Oct 3, 2023 at 0:55
  • \$\begingroup\$ There is no looping in the animation. The graphs go from 0 to 180 degrees of rotation. There is a visible lag during that spike- probably due to other things I have going on in the scene, I'm not sure, but nothing else should be effecting that cube, and I need the animations to be internally smooth even if the game lags, because I'll be doing calculations in FixedUpdate based on movements. \$\endgroup\$ Oct 3, 2023 at 1:27

1 Answer 1

4
\$\begingroup\$

I tried this on my end and found that I got jitter that looked similar when graphed, when playing the animation on a Timeline through a Playable Director. The delta graph looks much smoother when played directly from the Animator component without a Playable Director (i.e. using an Animator Controller).

Note that the Playable Director has its own Update Mode settings and these do not include any option to update the timeline from the fixed time step. You could set the mode to "manual" and update it from FixedUpdate() with your own code; otherwise, there's no point to measuring deltas in FixedUpdate() because they are out of sync with Update().

What's more important than the Update() deltas is how smooth the animation is over time. The interval between frames won't be entirely consistent, even if you have specified a target framerate (via Application.targetFramerate), so some jitter in the deltas is expected. If you graph the actual euler angle over time (not over frames), that graph should look pretty smooth, even when played from a Playable Director.

Here's a way to graph it in the Editor:

public class Test : MonoBehaviour {

    public AnimationCurve animationCurve;
    public AnimationCurve deltaCurve;
    private Quaternion previousUpdateRotation;

    private void Awake() {
        previousUpdateRotation = transform.rotation;
    }

    private void Update() {
        animationCurve.AddKey(Time.time, transform.eulerAngles.y);
        deltaCurve.AddKey(Time.time, Quaternion.Angle(previousUpdateRotation, transform.rotation));
        previousUpdateRotation = transform.rotation;
    }

}

The above code records the values each frame into AnimationCurves, which can then be viewed from the inspector. Note that since I'm not bothering to smooth the bezier handles, the curve from point to point in the graph won't look exactly right. Just focus on the actual points, not the interpolated curve between them.

Deltas over time Graph of euler angle deltas

Euler angle over time Graph of euler angle y-axis over time

Notice that despite some nasty-looking jitter in our deltas, the actual curve of the euler angle over time is very smooth. This suggests that the delta time between frames is relatively inconsistent but the engine is correctly accounting for this when performing the animation.

If you want to remove inconsistent frame intervals from the equation, use Time.captureFramerate = 60 (or whatever framerate you want to use). This will force the engine to use a consistent delta time for each frame. This setting is intended for use when recording gameplay videos, hence the name, and normally shouldn't be used for actual gameplay (unless you want the game to go into apparent slow motion if the player's hardware can't keep up with the desired framerate).

TLDR

  • Don't use delta between frames to try to measure how smooth an animation is
  • If you want a graph to show you how smooth an animation is, graph the value that you're animating over time (not over frames)
  • You may see more inconsistent frame timing when playing an animation through a Timeline rather than through an Animator Controller. This doesn't necessarily mean the animation will look any less smooth to the player.
\$\endgroup\$
2
  • \$\begingroup\$ Thank you for this info, particularly on Playable Director having its own timing separate from the Animator. I was using the timeline to coordinate a series of timed actions across a few different object, but I'm considering just dropping it and using a custom coded script at this point. \$\endgroup\$ Oct 3, 2023 at 2:11
  • \$\begingroup\$ @KeithStein You're welcome! If this answers your question, please don't forget to mark it as the answer. \$\endgroup\$
    – Kevin
    Oct 3, 2023 at 17:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .