Search Unity

Can't create Animation Clip and set keys with code "No animation clip assigned"

Discussion in 'Timeline' started by ghtx1138, Feb 18, 2019.

  1. ghtx1138

    ghtx1138

    Joined:
    Dec 11, 2017
    Posts:
    114
    I'm trying to create animation clips and set keys with c#. @seant_unity helped me out here to set curves on a custom clip but the same approach doesn't work for animation clips. I'm using 2018.3.0f2

    In the image below you can see the "My Animation Clip" has been created in the timeline. I recorded a clip "Recorded" and you can see the Position.y keys

    NoClipAssigned0.png

    However when I open My Animation Clip the position x,y,z keys are not available in the track header even though the y keys I created via c# are in the clip/not a clip. :eek:

    NoClipAssigned1b.png

    I feel it may have something to do with the Animation Playable Asset but I've not been able to find much info on this.

    NoClipAssigned2.png

    Here is my code:

    Code (CSharp):
    1.             var playableDirectors = FindObjectsOfType<PlayableDirector>();
    2.             foreach (var director in playableDirectors)
    3.             {
    4.                 var timelineAsset = director.playableAsset as TimelineAsset;
    5.                 if (timelineAsset != null)
    6.                 {
    7.                     foreach (var track in timelineAsset.GetOutputTracks())
    8.                     {
    9.                         if (track.name == "Sprite Test Track")
    10.                         {
    11.                             var newCustomClip = track.CreateClip<SpriteTestClip>();
    12.                             newCustomClip.displayName = "My New Clip";
    13.                             newCustomClip.duration = 10;
    14.                         }
    15.  
    16.                         if (track.name == "Animation Track")
    17.                         {
    18.                             var newCustomClip = track.CreateDefaultClip();
    19.                             newCustomClip.displayName = "My Animation Clip";
    20.                             newCustomClip.duration = 10;
    21.  
    22.                             Keyframe[] keys;
    23.                             keys = new Keyframe[3];
    24.                             keys[0] = new Keyframe(0.0f, 0.0f);
    25.                             keys[1] = new Keyframe(1.1f, 1.5f);
    26.                             keys[2] = new Keyframe(2.0f, 0.0f);
    27.                             curve = new AnimationCurve(keys);
    28.                             Debug.Log(curve.keys[1].time);
    29.  
    30.                             typeof(TimelineClip).GetMethod("AllocateAnimatedParameterCurves", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(newCustomClip, new object[] { });
    31.                             newCustomClip.curves.SetCurve("", typeof(AnimationClip), "Position.y", curve);
    32.  
    33.                             AssetDatabase.SaveAssets();
    34.  
    35.                             // This is just me thowing mud at a wall - I have no idea what I am doing
    36.                             AnimationPlayableAsset animationPlayableAsset = newCustomClip.asset as AnimationPlayableAsset;
    37.                             animationPlayableAsset.clip = newCustomClip.animationClip;
    38.  
    39.                         }
    40.  
    41.                     }
    42.                 }
    43.             }
    Any advice would be greatly appreciated. Cheers
     
  2. ghtx1138

    ghtx1138

    Joined:
    Dec 11, 2017
    Posts:
    114
    Update: The transform issue was solved - I was stupidly not using Transform localPosition when setting the curve

    Code (CSharp):
    1.                             typeof(TimelineClip).GetMethod("AllocateAnimatedParameterCurves", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(newCustomClip, new object[] { });
    2.                             newCustomClip.curves.SetCurve("", typeof(Transform), "localPosition.y", curve);
    NoClipAssigned3.png
     
  3. ghtx1138

    ghtx1138

    Joined:
    Dec 11, 2017
    Posts:
    114
    Update: So it appears I am creating the clip but it is not saving. I can see that the Recorded clip is a child asset of the timeline - but My Animation Clip - even though it is on the timeline is not yet a child asset

    NoClipAssigned4.png

    I'm guessing it will be related to something like this

    Code (CSharp):
    1. AnimationClip animclip = newCustomClip.animationClip;
    2. AnimationPlayableAsset animationPlayableAsset = newCustomClip.asset as AnimationPlayableAsset;
    3. animationPlayableAsset.clip = animclip;
    I tried generating an UnityEngine.AnimationClip and while that worked I can't edit the curves in the Timeline - so I need to get a UnityTimeline.AnimationClip.

    Cheers
     
  4. ghtx1138

    ghtx1138

    Joined:
    Dec 11, 2017
    Posts:
    114
    Update: I'm also seeing this error but I'm not sure if it is related.

    Code (CSharp):
    1. TreeView root item is null. Ensure that your TreeViewDataSource sets up at least a root item.
    2. UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)
     
  5. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    For animation tracks clips, you can use CreateRecordableClip(). It will create blank animation clips ready for timeline to record with...or you can modify it yourself. The clip will be available via animationPlayableAsset.clip (like in your example).

    That method will add it to the asset database (make sure your timeline is in the asset database first) and set the clip to be recordable - which makes it show up in the curve editor.
     
  6. ghtx1138

    ghtx1138

    Joined:
    Dec 11, 2017
    Posts:
    114
    @seant_unity thanks very much.

    Is there a way to make the new clip start at the end of the previous clip (if any). When CreateDefaultClip() is used it adds the new clip to the end of the previous clip (if any). I see that with CreateRecordableClip() I must specify the start time.

    Please know that, in my mind at least, you are a living legend.

    Cheers


    Code (CSharp):
    1. theAnimationTrack = timelineAsset.GetOutputTrack(0) as AnimationTrack;
    2. theAnimationClip = theAnimationTrack.CreateRecordableClip("MyRecordableClip");
    3. theAnimationClip.duration = 10;
    4.  
    5. theAnimationClip.start = 10;
    6.  
    7. AnimationPlayableAsset animationPlayableAsset = theAnimationClip.asset as AnimationPlayableAsset;
    8.  
    9. Keyframe[] keys;
    10. keys = new Keyframe[3];
    11. keys[0] = new Keyframe(0.0f, 0.0f);
    12. keys[1] = new Keyframe(1.1f, 1.5f);
    13. keys[2] = new Keyframe(2.0f, 0.0f);
    14. curve = new AnimationCurve(keys);
    15.  
    16. typeof(TimelineClip).GetMethod("AllocateAnimatedParameterCurves", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(theAnimationClip, new object[] { });
    17. animationPlayableAsset.clip.SetCurve("", typeof(Transform), "localPosition.y", curve);
    18.  
    19. AssetDatabase.SaveAssets();
    20. AssetDatabase.Refresh();
     
  7. seant_unity

    seant_unity

    Unity Technologies

    Joined:
    Aug 25, 2015
    Posts:
    1,516
    Ah, thanks for pointing that out - we didn't realize the behavior was different.

    I think the simplest workaround is assign the duration of the track.
    var d = track.duration;
    var c = track.CreateRecordableClip(...);
    c.start = d;

    And thanks for the kind words, over the top as they might be. They are another gentle reminder that Unity has such a positive and amazing community :)