Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We’re making changes to the Unity Runtime Fee pricing policy that we announced on September 12th. Access our latest thread for more information!
    Dismiss Notice
  3. Dismiss Notice

How can I add curve keys and recording to a custom track?

Discussion in 'Timeline' started by LazloBonin, Nov 25, 2020.

  1. LazloBonin


    Mar 6, 2015
    I'm stumped trying to add keys and recording to a custom track.

    I'm creating an object that needs to record its properties over time in a custom track.

    I don't want to give it an AnimatorController and an Animation track, because it doesn't require an AnimatorController.

    I also don't want to use an Animation track because I want custom blending -- in my case, I'm blending a camera view override.

    So far I found these questions that indicate recording and keying on custom tracks was removed in 2019.3:

    Now I was able to gather that CreateCurves could be used to bring back curves.

    A few questions:
    • Should I call TrackAsset.CreateCurves or TimelineClip.CreateCurves? Why?
    • Why do I have to call SetCurve after to get the curves button to appear after CreateCurves is called on a clip? What if I don't know what curves I want in advance?
    • When should I call any of those methods?
    • How do I get the record button to show up?
    • In spite of the record button showing up, I can still hit Record in the Animation Window when I double click my curved clips, but nothing gets recorded -- why?
    • Do I need to implement GatherProperties on the TrackAsset or on IPropertyPreview to get this to work?

    @seant_unity said in one of the linked threads:
    Which menu? Which left side panel? How are "fields that can be animated" automatically chosen?
  2. seant_unity


    Unity Technologies

    Aug 25, 2015
    You shouldn't need to use the API to use animated parameters on tracks and clips. It is completely dependent on how the custom tracks and clips are structured.

    However, animated parameters on clips and tracks are animating values on the Track/PlayableAsset, not on the target component like AnimationTracks do.

    Here's an example:
    Code (CSharp):
    1.     [Serializable]
    2.     public class TextPlayableBehaviour : PlayableBehaviour
    3.     {
    4.         public Color color = Color.white; // automatically animated
    5.         public int fontSize = 14;        
    6.         public string text = "";
    8.         // ProcessFrame would copy these value to the Text object bound to the track...
    9.     }
    12.     // Represents the serialized data for a clip on the TextTrack
    13.     [Serializable]
    14.     public class TextPlayableAsset : PlayableAsset
    15.     {
    16.         public TextPlayableBehaviour template = new TextPlayableBehaviour();
    18.         public override Playable CreatePlayable(PlayableGraph graph, GameObject owner)
    19.         {
    20.             // Using a template will clone the serialized values
    21.             return ScriptPlayable<TextPlayableBehaviour>.Create(graph, template);
    22.         }
    23.     }
    This works for either a track or a clip. Timeline will automatically detect that a template is being used inside the playable asset, and manage curves on the playable behaviour in the inline curve editor. The button to expand the curve editor is on the track header, like the animation track.

    The curve editor will show only animatable properties. If it's not currently animated, a constant curve is shown. Keys can be added (recorded) using the context menu in the inspector, or by editing the curve directly.

    When you modify the curves in editor, those parameters are automatically updated before PrepareFrame or ProcessFrame calls are run on your PlayableBehaviour.

    v1.4.5 fixes a bunch of bugs with these types of curves in the editor, so I'd recommend using that version if possible.

    If you are copying the behaviour values to a Component, then you need to specify which Component values you are modifying in GatherProperties so when previewing is disabled, their scene values are properly restored. But you do not need to specify anything for PlayableBehaviour values.

    If you want to set values in the API, then CreateCurves can be used to initialize the animation clip for the animated properties.

    After creating the curve, values can be set via API using animation apis:
    AnimationUtility.SetEditorCurve(clip.curves, typeof(TextPlayableAsset), "color.r", AnimationCurve.Linear(0,0,1,1));

    Note - the type is the type of PlayableAsset (or track asset), but the "template". prefix for the color parameter isn't required.

    I hope that helps.
  3. LazloBonin


    Mar 6, 2015
    Hi Sean, thanks for the quick reply.

    After multiple iterations on extending the timeline, I stopped using a template that I copy to the Behaviour on CreateInstance, and keep my data inside the PlayableAsset itself. As such, I don't have a "template" field.

    How exactly is the structural analysis done?
    • Is it by the field name "template"?
    • Is it by any PlayableBehaviour typed field on the PlayableAsset?
    • Is it inferred from the result of CreatePlayable?
    • Is it documented anywhere?
    Can I gain access to this animation feature without a template field?
  4. DavidGeoffroy


    Unity Technologies

    Sep 9, 2014
    The answers to your four questions:
    • No, You don't need to name it "template".
    • Yes*
    • No, but only fields that exist on the type returned by CreatePlayable will be animated.
    • I'll have to check.
    * Only fields serialized on a PlayableAsset as part of a PlayableBehaviour can be animated.

    You can put as many PlayableBehaviours as you want in your PlayableAsset, but only the fields that exist on the PlayableBehaviour that you pass to
    ScriptPlayable<PlayableBehaviourT>.Create(graph, template);
    will be animated at Runtime.

    You don't need to pass in the template to
    , although you should, but you will need to serialize the type of PlayableBehaviour that you instantiate in
    in your PlayableAsset in order to get access to this animation feature.
  5. jonagill


    Oct 5, 2019
    Resurrecting this thread to leave some advice for future travelers:

    If you are looking to add curves to your Tracks, rather than your Clips, your code should be a little different to the example posted above. Tracks use `CreateTrackMixer()` instead of `CreatePlayable()`, so your serialized fields should be inside your mixer type. Any serialized type that inherits from `PlayableBehaviour()` will draw keys in the Timeline editor, but you'll only actually be able to query for animated values if you put them in your Mixer behaviour. (At least, that's the only way I was able to!)

    Your code should be something like:

    Code (CSharp):
    2.     public class MyTrack : TrackAsset
    3.     {
    4.         [SerializeField] public MyMixer mixerTemplate;
    6.         public sealed override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
    7.         {
    8.             return ScriptPlayable<MyMixer>.Create(graph, mixerTemplate, inputCount);
    9.         }
    10.     }
    12.     public class MyMixer : PlayableBehaviour
    13.     {
    14.         [SerializeField] public float myAnimatableValue;
    16.         // NOTE: This function is called at runtime and edit time.
    17.         // Keep that in mind when setting the values of properties.
    18.         public override void ProcessFrame(Playable playable, FrameData info, object playerData)
    19.         {
    20.             Debug.Log( myAnimatableValue );
    21.         }
    22.     }
    Edit: it seems to be important that your mixer is public. Changing it to a private serialized field seems to cause it to not render properly in the Timeline.
    Last edited: Feb 7, 2023