- Home /
Timeline, Whats happening Under the Hood: with multiple AnimationTracks for same gameobject
Setup:
I have a Timeline with two tracks.
Unity's AnimationTrack: Walk forward with root motion
Unity's AnimationTrack: Stand in spot grumpily.
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:
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.
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.
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;
Hardcoded setting transform.rotation = desiredRotation; but if the first track exists, the AnimationPlayableAsset seems to overwrite the value somewhere.
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.
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!
Answer by seant_unity · Sep 24, 2020 at 12:47 PM
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
{
}
Thank you very much for your fast response!! The code you gave is similar to what i was already doing, but i was missing the animator.ApplyBuiltinRoot$$anonymous$$otion();
Additionally, i need therotation change to persist when the clip is finished. So Im having to adapt it quite a bit, practically creating my own root motion accumulated rotation. But you gave me a good starting ground to work off of.
Thank you very much! I'll comment back when I get it working the way i want it!
Your answer
Follow this Question
Related Questions
How to create animations that can be edited with scripts in runtime? 1 Answer
Is there a way to get exact root motion to be applied by animation? 0 Answers
Root motion accuracy issue 0 Answers
Animator animates feet in an animation without foot animation 1 Answer
What are the best practices for reusing an animation controller? 0 Answers