Is there a way to view the Timeline preview without a playable director?

Hello,

I am writing a character controller, intending to use timeline for character states, so that I can author particle effects and the likes in perfect unison with the character’s animation.

I’d like to preview & author those animations and effects, but…
I evaluate and mix the graphs manually, as well as handle the bindings myself, without the playable director.

Is there a way to get past the need for PlayableDirector in order to preview a timeline asset?

The Timeline window absolutely requires a Director in order to preview.

Signals also require a Director. So if you have signals in your Timeline, you’ll need a director to play the Timeline.

But otherwise you can preview the Timeline manually by changing the time of the graph and evaluating.

You could even use the IAnimationWindowPreview interface to preview your Timeline in the Animation Window.

Also keep in mind that properties of objects that are changed may not get reverted after preview if you don’t use the Timeline window.

All in all, it’s possible, but I would instead advise you to build and edit you Timeline in a separate scene, where you use the director and only edit the Timeline, and have your own playback mechanism for the scenes that need to go in your game.

1 Like

Thank you very much for this elaborate response. If using the playable director is inevitable, I have a few followup questions.

The character I use relies on root motion from the animations in order to move the character controller - I mean that I don’t use the built-in root motion, and instead accumulate its given values to a character controller so that I can decide how they’re handled. (using OnAnimatorMove and the deltaPosition, deltaRotation)
The playable director evaluation seems to mess these values up, seemingly making them the full root position and rotation instead of the deltas from the previous evaluation.
Is there any way to, at runtime, disable this behaviour so that I can probably sample the values?

Also, if disabling this behavior is not possible (which I assume it is not, from the limited source code I’ve read), I’d like to make my own ‘play animation’ behavior clips. What would be the best way to make the timeline preview support my custom animation clip behaviors in that case?

The Timeline Animation Track uses a special Playable called AnimationMotionXToDeltaPlayable.
It lets us treat everything as absolute motion (easier for authoring, and necessary to keep the code dealing with offsets manageable), but lets us write that as deltas to root motion, so that we can get the best of both worlds.

But that assumes you play the Timeline from a PlayableDirector, and probably want the first frame to be at a specific position. Sounds like that’s not your case.

Have you tried playing around with the Animation Track options?
If you set the Track Offsets option to Apply Scene Offsets, does that work for you?

Otherwise, there’s nothing preventing you from writing your own Animation Track without the AnimationMotionXToDeltaPlayable.

I don’t think you’ll be able to duplicate the recording features, but for Playback, I don’t see any reason why you couldn’t make it work.

2 Likes

I have tried all the combinations of options, but none have worked out for me.

I also took a look into writing my own playable behaviour, though it seems many things in the timeline package are private, internal, or otherwise inaccessible, so there is an excessive amount of necessary duplicate code involved…
Some examples that come to mind are the hashing of animations, animationClip.hasRootMotion? and the editor draw codes involved (styles, etc)…

Can I have a confirmation on which classes would be absolutely necessary to recreate the animation clips behavior?
I assume everything in Timeline/Runtime/Animation, but what about Timeline/Editor/Animation?
I believe making my own track asset, then making a behaviour for it and a mixer is the bare minimum?
How would I handle resetting the animator to bind pose when stopping the timeline preview?

Thanks for all the help.

If all you want is to play AnimationClips one after the other, you don’t care about offsets, and you will not be recording AnimationClips on that track, then creating your own track that does that should be fairly simple.

What you need is:

  • The code that creates the AnimationMixer and ClipPlayables for your track.
  • Your track PlayableAsset implements IPropertyPreview.GatherProperties so that the scene can be reverted.
  • You use IPropertyCollector.AddFromClip to feed the properties from the AnimationClips to IPropertyPreview.GatherProperties.

That’s assuming all your clips are built the same way they would be to play in an AnimatorController.

If your clips don’t all have the root joint in the same position, then you may have issues without having some mechanism to deal with offsets.

2 Likes

@DavidGeoffroy Apologies for resurrecting this somewhat old thread but I am currently implementing my own Timeline-based system for authoring Abilities which includes many custom tracks and clips driving things like weapon trails, hitboxes, etc.

I have noticed that the default animationtrack has some… odd behavior when you’re trying to play a timeline by connecting it to your own graph at run-time. I believe what I want instead of the built-in AnimationTrack (which includes the AnimationMotionXToDeltaPlayable) is just a raw AnimationMixer for the track’s mixer and a set of animation clips.

I have implemented this and to some extent it is working (the animation plays when the appropriate output from the timeline is plugged into my graph).

However, I am not able to get the Timeline “framework” to create the correct kind of output for my custom track. This only matters when I am trying to preview the Timeline as the output type it is generating (which should be AnimationPlayableOutput is instead a ScriptPlayableOutput).

Any advice here would be greatly appreciated.

[TrackClipType(typeof(AnimationPlayableAsset), false)]
[TrackBindingType(typeof(Animator))]
public class LocalAnimationTrackAsset : TrackAsset {
  public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount) {
    return AnimationMixerPlayable.Create(graph, inputCount);
  }

  public override void GatherProperties(PlayableDirector director, IPropertyCollector driver) {
    var animator = director.GetGenericBinding(this) as Animator;
    if (animator == null)
      return;
    foreach (var clip in m_Clips) {
      var asset = clip.asset as AnimationPlayableAsset;
      if (asset == null)
        continue;
      Debug.Log($"Added props from {asset.clip.name}");
      driver.AddFromClip(asset.clip);
    }
  }
}

EDIT:
For anyone who might find this thread or post in the future here is how you specify the output for a custom AnimationTrack to get the OutputPlayable to be an AnimationPlayableOutput.

[TrackColor(.25f, .25f, .75f)]
[TrackBindingType(typeof(Animator))]
[TrackClipType(typeof(AnimationPlayableAsset), false)]
public class LocalAnimationTrackAsset : TrackAsset {
  public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount) {
    return AnimationMixerPlayable.Create(graph, inputCount);
  }

  public override IEnumerable<PlayableBinding> outputs {
    get {
      yield return AnimationPlayableBinding.Create("Animation Binding", this);
    }
  }

  public override void GatherProperties(PlayableDirector director, IPropertyCollector driver) {
    var animator = director.GetGenericBinding(this) as Animator;
    if (animator == null)
      return;
    foreach (var clip in m_Clips) {
      var asset = clip.asset as AnimationPlayableAsset;
      if (asset == null)
        continue;
      driver.AddFromClip(asset.clip);
    }
  }
}
2 Likes