Timeline, Whats happening Under the Hood: with multiple AnimationTracks for same gameobject

Setup:
I have a Timeline with two tracks.

  1. Unity’s AnimationTrack: Walk forward with root motion
  2. Unity’s AnimationTrack: Stand in spot grumpily.
  3. A custom track that should add an additional rotation to the root motion of the animator.

A simplified Setup only using the first two tracks could also be used to answer my problem.

**Problem: The second animation track overrides first track. **
I would like it to walk forward, stop walking, wait then play idle angry.
Unfortunately, having the second animation track completely overrides the first animation track. the character doesn’t walk and just stands still until the angry animation clip begins.

Why? What hidden under the hood function makes it override? Can i optionally remove this function somehow?

**Problem 2: Custom clip doesnt work in Editor when there is a AnimationPlayableAsset track . **
My custom clip works as desired (rotates the animator.rootRotation and transform.rotation) when it is the only track on the timeline. But when i add the AnimationPlayableAsset track to the timeline, the proper rotation values get overwritten with the root rotation from the animation track.

**Limitations: **

  1. I am aware that Timeline Animation Tracks only have “override” and an “additive animation” is a much desired feature but doesn’t exist yet… seant_unity’s answer So I’m trying to be creative.
  2. Please don’t tell me: “put the clips on the same track” as that won’t work for my project where i use a custom clip that is not an animation type.
  3. Please don’t tell me to reorder the tracks, if i put idle on top of walk, then it plays the walk but not the idle. I need both.

Things I have tried for my custom clip to work around this:
My custom clip basically does an “additive Rotation” to rootmotion to create an effect similar to a 3rd person controller that walks straight and rotates over y:

  • transform.rotation = Quaternion.Euler(rotIncrement)*transform.rotation;
  • animator.rootRotation = transform.rotation;
  1. Hardcoded setting transform.rotation = desiredRotation; but if the first track exists, the AnimationPlayableAsset seems to overwrite the value somewhere.
  2. Creating a Monobehaviour script to update rotation in LateUpdate or in OnAnimatorIK, Works in runtime =) doesnt work in editor cause animator doesnt update. I NEED it to work in EditorMode.
  3. Using CustomMixerBahaviour.ProcessFrame to set the desired rotation of “next frame”, and CustomBehaviour.PrepareFrame to set the current animator.rootRotation = nextFrameRotation.

None of the 3 alternatives work in editor when the AnimationPlayableAsset track exists above.

THANK YOU!

Without additive blending, this is quite a challenging problem. Normally root motion is applied as a rotation/translation pair, it’s difficult to separate them.

One solution is to use the OnAnimatoveMove callback to modify the root motion, and using timeline to set that data. Here is a quick example that modifies the rotation and still works in timeline preview.

// These classes should be in separate files

[ExecuteInEditMode]
public class AnimatorMove : MonoBehaviour
{
    public Vector3 addRotation { get; set; }
    public bool active { get; set; }

    void OnAnimatorMove()
    {
        Animator animator = GetComponent<Animator>();
        if (animator)
        {
            animator.ApplyBuiltinRootMotion();
            if (active)
                transform.localRotation *= Quaternion.Euler(addRotation);
        }
        addRotation = Vector3.zero;
        active = false;
    }
}


public class AnimatorMoveClip : PlayableAsset
{
    [Serializable]
    public class MoveBehaviour : PlayableBehaviour
    {
        public Vector3 Rotation;
        public override void ProcessFrame(Playable playable, FrameData info, object playerData)
        {
            var animator = playerData as AnimatorMove;
            if (animator == null)
                return;

            animator.active = true;
            animator.addRotation = Rotation;
        }
    }

    // makes the Rotation editable
    public MoveBehaviour template = new MoveBehaviour();
    public override Playable CreatePlayable(PlayableGraph graph, GameObject owner)
    {
        return ScriptPlayable<MoveBehaviour>.Create(graph, template);
    }
}

[TrackClipType(typeof(AnimatorMoveClip))]
[TrackBindingType(typeof(AnimatorMove))]
public class AnimatorMoveTrack: TrackAsset
{
}