Search Unity

Reading keyframe/curve data from Animator?

Discussion in 'Scripting' started by Steven-Walker, Apr 24, 2014.

  1. Steven-Walker

    Steven-Walker

    Joined:
    Oct 27, 2010
    Posts:
    38
    I am working on tools for the Unity editor which work with animations and have run into an impasse accessing vital information from Animator. The main issue is that I cannot find a way to access animation clip data. With the legacy Animation component I was able to access clips easily, as well as extract curve data.

    Below is a utility method I wrote that attempts to extract clip information, however it doesn't work. The main issue is that I cannot find a way in the API to get an AnimationClip object from an Animator state (even though one is clearly assigned in the editor). The closest thing I have found is the Motion object, which isn't even documented. This at least gives me the name of the clip, so then I am attempting to look it up using the AnimationUtility. However, the AnimationUtility only works with the Animation component, so in this context returns null. This is where I am stuck.

    My end goal is to jump to key points in an animation in the editor. My tactic is to get AnimationClipCurveData from an AnimationClip, though if there is another way to go about it I am all ears!

    Does anyone know how I can make this work?

    Code (csharp):
    1. static public AnimationClip GetAnimationClip(GameObject obj, string track) {
    2.     AnimationClip clip = null;
    3.     string name = null;
    4.    
    5.     if(obj  StringUtil.IsNotNull(track)) {
    6.         Animator anim = obj.GetComponent<Animator>();
    7.         if(anim != null) {
    8.             bool found = false;
    9.             for(int x = 0; x < anim.layerCount; x++) {
    10.                 UnityEditorInternal.AnimatorController ac = anim.runtimeAnimatorController as UnityEditorInternal.AnimatorController;
    11.                 UnityEditorInternal.StateMachine sm = ac.GetLayer(x).stateMachine;
    12.                
    13.                 for(int i = 0; i < sm.stateCount; i++) {
    14.                     UnityEditorInternal.State state = sm.GetState(i);
    15.                    
    16.                     if(state.uniqueName == track) {
    17.                         Motion m = state.GetMotion();
    18.                         if(m != null) {
    19.                             Debug.Log("Motion:"+m.name);
    20.                             name = m.name;
    21.                             found = true;
    22.                             break;
    23.                         }
    24.                     }
    25.                 }
    26.                 if(found) break;
    27.             }
    28.         }
    29.        
    30.         AnimationClip[] clips = GetAnimationClips(obj);
    31.         if(clips == null) {
    32.             Debug.Log("GetAnimationClip: "+obj.name+": no animation clips");
    33.         }
    34.         else {
    35.             foreach(AnimationClip c in clips) {
    36.                 if(clip.name == name) {
    37.                     clip = c;
    38.                     break;
    39.                 }
    40.             }
    41.         }
    42.     }
    43.     Debug.Log("GetAnimationClip: "+obj.name+":"+name);
    44.     return clip;
    45. }
    46.  
    On a side note, I want to voice a bit of frustration that scripting Animator is a pain! While it's awesome that Unity has incorporated these powerful new animation tools, the API is really lacking to fully utilize it. And what is there is poorly documented. Much of the code I've written to overcome these obstacles is using undocumented internal procedures, which is quite ugly and worrisome, but I have found no alternatives. I truly hope the Unity developers realize this shortcoming and expose more of the system for developers.

    Thanks in advance for any help!
     
  2. Steven-Walker

    Steven-Walker

    Joined:
    Oct 27, 2010
    Posts:
    38
    I found a solution finally. It turns out that the undocumented Motion type is a derivative of AnimationClip, so I can just perform a cast to get the clip reference. Reading the curve data from the clip appears to work in the same way as with legacy Animation clips.

    Since the UnityEditorInternal object cannot be used in runtime code outside of the editor, the clip is still unreachable through runtime code. Presently in the current API (Unity 4.3.4), it is impossible (insofar as I have found) to get basic information such as the duration of a clip/state. To overcome this, I created a new MonoBehaviour class which gathers the clip and information for each Animator state, storing it in a serializable list, which I can then look up at runtime.

    Here is the core function that gather's animation data. I had to put hooks into my editor classes to ensure the information gets updated:

    Code (csharp):
    1.  
    2. Data = new List<AnimatorInfoData>();
    3.  
    4. #if UNITY_EDITOR
    5. Animator anim = GetComponent<Animator>();
    6. if(anim != null) {
    7.     UnityEditorInternal.AnimatorController ac = anim.runtimeAnimatorController as UnityEditorInternal.AnimatorController;
    8.    
    9.     for(int x = 0; x < anim.layerCount; x++) {
    10.         UnityEditorInternal.StateMachine sm = ac.GetLayer(x).stateMachine;
    11.         if(x == 0) {
    12.             DefaultStateName = sm.defaultState.uniqueName;
    13.             DefaultStateHash = sm.defaultState.uniqueNameHash;
    14.            
    15.             if(DebugEnabled) Debug.Log("AnimatorInfo["+name+"].Gather: DefaultStateName:"+DefaultStateName);
    16.         }
    17.        
    18.         for(int i = 0; i < sm.stateCount; i++) {
    19.             UnityEditorInternal.State state = sm.GetState(i);
    20.             Motion m = state.GetMotion();
    21.             if(m != null) {
    22.                 AnimationClip clip = m as AnimationClip;
    23.                 Data.Add(new AnimatorInfoData(state.uniqueName, state.uniqueNameHash, clip));
    24.             }
    25.             else {
    26.                 Data.Add(new AnimatorInfoData(state.uniqueName, state.uniqueNameHash, null));
    27.             }
    28.         }
    29.     }
    30. }
    31. #endif
     
    jellevda and Alistar like this.
  3. Rama-Al-Maliki

    Rama-Al-Maliki

    Joined:
    Oct 9, 2017
    Posts:
    1
    I can Get it! in my visual studio
     
  4. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,521
    Please don't bump four year old threads that are clearly dead, especially with pointless replies.
     
  5. QuebecDev

    QuebecDev

    Joined:
    May 9, 2020
    Posts:
    37
    Lol
     
    Vincent454 likes this.
  6. QuebecDev

    QuebecDev

    Joined:
    May 9, 2020
    Posts:
    37
    Oups
     
    Vincent454 likes this.