Search Unity

Resolved Can not calculate Mecanim Animator's actual frame

Discussion in 'Animation' started by Makaveliy, Jan 9, 2021.

  1. Makaveliy

    Makaveliy

    Joined:
    Nov 16, 2017
    Posts:
    2
    Hi Guys,

    I'm trying to synchronize different parts of my character, that are animated with different tools. The body of my character is animated on GPU (I use MeshAnimator asset), and other parts (for example hairs in this particular case, glasses, hat, headphones...) are animated with Mecanim Animator (actually meshes are not animated, but attached to the head bone as child object). So the Mecanim Animator doesn't affect the body, its used only to move objects, that I want to change on runtime.

    The task is to get current frame of the Mecanim Animator and pass it to the MeshAnimator (Mecanim Animator is leading).

    The example animation has NO INTERPOLATION between frames (CONSTANT) and has keyframes for each frame (I mean that each frame is sampled before importing to Unity). Frames count = 24, length = 1.0, fps = 24.

    And here's the problem:
    I thought that Mecanim Animator jumps to the next frame only when its normalizedTime becomes greater or equal to the "required normalized time" of the target frame. And in most cases it does.

    So my first script for calculating the frame was like this:

    float normTime = currentAnimatorState.normalizedTime - (float)Math.Truncate(currentAnimatorState.normalizedTime);
    int frame = (int)Math.Floor(normTime * framesCount);


    But sometimes Mecanim jumps to the next frame even when normalizedTime doesn't reach the required value. In result, hairs move 1 frame further than the body. For example 13 / 24 = 0.5416667 is the "required normalized time" for 13-th frame. Current normalizedTime of the Animator = 0.5395675, which is less for 0.002099, but it moves to frame 13 whatever. Other cases were: 0.002358, 0.002071... Sometimes even 0.009...



    So I decided to add some precision offset of 0.0025 to the normalizedTime before calculating the frame:

    float normTime = currentAnimatorState.normalizedTime - (float)Math.Truncate(currentAnimatorState.normalizedTime);
    normTime += 0.0025f;
    int frame = (int)Math.Floor(normTime * framesCount);


    But now I have situations, when Mecanim does NOT move to the next frame even when difference between required value and normalizedTime is pretty low, and in result the body moves 1 frame further than hairs.
    Examples:
    Required value: 12 / 24 = 0.5, normalizedTime = 0.4984703, difference = 0.00153
    Required value: 1 / 24 = 0.041667, normalizedTime = 0.04064846, difference = 0.001018


    I tryed to use (int)Math.Round(normTime * framesCount), but still got the same unpredictable results.

    Now I look towards using legacy animation or Animancer. But I really don't want to.

    If someone knows how to get the actual frame of Animator, please help.
    I've spent a lot of time trying to accomplish this task, but to no avail.

    Thank you.
     
    Last edited: Jan 12, 2021
  2. Makaveliy

    Makaveliy

    Joined:
    Nov 16, 2017
    Posts:
    2
    The problem is resolved.

    Thanks to Kybernetik.

    normalizedTime updates between Update() and LateUpdate() loops, so I was getting irrelevant frame while I tryed to calculate it in Update loop. Now I calculate current frame in LateUpdate() and it works perfect.