Search Unity

AnimationClip problems

Discussion in 'Animation' started by Malhavok, Dec 17, 2013.

  1. Malhavok

    Malhavok

    Joined:
    Jul 23, 2012
    Posts:
    4
    Hello

    I'm porting Spriter animations to Unity, did it already once via external tool and everything works fine. Now i'm trying to make it work again, but this time plugging it into Unity import system. While everything seems to work (more or less) fine, there are some big bumps on my way.

    Problem 1 - missing animation type
    What I do:
    - create AnimationClip instance in the code
    - create AnimationCurve instances (a lot of them, for every bone and sprite)
    - save it using AssetDatabase.CreateAsset (path created via Path.Combine, filename ending with '.anim')

    What i get:
    - animation created this way is of type "1" (it seems to be Generic, but there is no way of telling that for sure)
    - when i try to add this animation to AnimatorController, i get the following error:
    "Animation clip 'name' is not retargetable. Animation clips used within the Animator Controller need to have Muscle Definition set up in the Asset Importer Inspector”
    - animations created via “Animation / Create New Clip” are of type “2” (which seems to be Legacy). These animations have no problems and work fine.
    - so, i want to change animation type for AnimationClip’s that i’m creating, but it’s not that easy
    - adding (assetImporter as ModelImporter).animationType = ModelImporterAnimationType.Legacy and then reimporting animations via AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate) doesn’t help
    - trying to use reflection and just set some values doesn’t help either. typeof(AnimationClip).GetProperties(BindingFlags.N onPublic) returns 0 elements.

    My only idea now is to mem-map resulting .anim file (in text mode), find line with “m_animationType: 1” and change this one byte to “2”.
    Any better solutions? It has to be a pure code, no inspector clicking (i know about debug mode in inspector, but it doesn’t suit my needs)

    Problem 2 - assigning Sprites to animations
    (note: i won’t be doing exactly this in the final version of the importer, but i still wonder how to do it from script)
    What I want to do:
    - assign a Sprite to an animation at a given time

    How it’s done internally:
    - assignment to “m_PPtrCurves” in text mode

    What are the options:
    - Keyframes are out at start - only assigning floating point value
    - AnimationUtility.SetAnimationEvents seems to be much better hit, the only question is then: what function to call? Checking via reflection i can tell there are no set_Sprite methods, so i’d assume it is a field and not a property.

    Probably the answer is simple - instead of function it is enough to call it for a field and Unity messaging system assumes then a call to an assignment operator, but i’d like a confirmation on this (maybe i just didn't rtfm enough yet).
     
  2. Fenrisul

    Fenrisul

    Joined:
    Jan 2, 2010
    Posts:
    618
    I just ran face first into this issue today myself... definitely interested in any progress.

    Also interested in Spriter support :)
     
  3. Malhavok

    Malhavok

    Joined:
    Jul 23, 2012
    Posts:
    4
    Well, my current solution for AnimationType is:

    Code (csharp):
    1.  
    2. var baseString : String = "m_AnimationType: ";
    3. var testStringToFind : String = baseString + "1";
    4.        
    5. var binData : byte[] = File.ReadAllBytes(outPath);
    6. var data : String = Encoding.UTF8.GetString(binData);
    7.        
    8. if (data.IndexOf(testStringToFind) != -1)
    9. {
    10.     // input file is in text mode
    11. //  Debug.Log("Found marker - text mode assumed");
    12.     data = data.Replace(testStringToFind, baseString + "2");
    13.     File.WriteAllText(outPath, data);
    14. }
    15. else
    16. {
    17.     // input must be in binary mode.
    18.     Debug.Log("Marker for fixing not found. Assets are serialized in binary mode. Change mode to text and reimport again.");
    19.  
    20.     // a fix for binary files can be added here
    21.  
    22. //  File.WriteAllBytes(outPath, binData);
    23. }
    24.  
    It's fugly, terrible and shouldn't even exist. Moreover, it may require restarting Unity, as it sometimes fails to notice change in the file, even thou refresh/reimport is clicked on them. Going "force binary" -> "force text" breaks animation (that is animation mode is set on them to 1 again) so it suggests that all of these assets are internally cached.

    Anyone from the Unity team cares to give us some hints? Or a solution?
     
  4. AaronDeChamplain

    AaronDeChamplain

    Joined:
    May 14, 2014
    Posts:
    3
    I came up with a solution that is potentially a little bit safer, and doesn't require that you serialize all of your assets in text. If you create an AnimationClip asset in your project's Resources folder using the editor, it will have an Animation Type of 2. Then in code:

    Code (CSharp):
    1.  
    2. AnimationClip newAnimClip = Instantiate(Resources.Load<AnimationClip>("TemplateAnimationClip")) as AnimationClip;
    3. //Set your curves
    4. newAnimClip.SetCurve("", typeof(ObjectType), "variableName", curveObject);
    5. string pathName = animPath + Path.GetFileNameWithoutExtension(localPath) + "_" + anim.name + ".anim";
    6. AssetDatabase.CreateAsset(newAnimClip, pathName);
    7. AssetDatabase.ImportAsset(pathName);
    8.  
    If you create an instance of the template object you put in your resources folder, and use that to create a new asset, the new AnimationClip will also be of type 2.
     
  5. Mecanim-Dev

    Mecanim-Dev

    Joined:
    Nov 26, 2012
    Posts:
    1,675
    You can also use SerializeObject and SerializeProperty to edit any value that are not exposed throught they api

    Code (CSharp):
    1. class ChangeAnimationClipType
    2. {
    3.     enum AnimationType {Legacy = 1, Generic = 2, Humanoid = 3}
    4.  
    5.     [MenuItem("Mecanim/Change Animation Clip Type")]
    6.     static void DoChangeAnimationClipType()
    7.     {
    8.         AnimationClip clip = Selection.activeObject as AnimationClip;
    9.         if (clip != null)
    10.         {
    11.             SerializedObject serializedClip = new SerializedObject(clip);
    12.             SerializedProperty animationType = serializedClip.FindProperty("m_AnimationType");
    13.             if(animationType == null)
    14.             {
    15.                 Debug.Log("SerializedProperty m_AnimationType not found");
    16.                 return;
    17.             }
    18.  
    19.             animationType.intValue = (int)AnimationType.Legacy;
    20.             serializedClip.ApplyModifiedProperties();
    21.         }
    22.     }
    23. }
     
  6. mhtraylor

    mhtraylor

    Joined:
    Jan 13, 2013
    Posts:
    33
    There is also AnimationUtility.SetAnimationType(). It doesn't seem to be documented as of yet, but it works.
     
  7. AaronDeChamplain

    AaronDeChamplain

    Joined:
    May 14, 2014
    Posts:
    3
    Well, that's a much better solution. Thanks!