• Unity
  • Adding new animations to Mecanim Controller

Hi guys,

I'm not sure if my brain has just stopped working but I'm hoping someone can help me. I have a feeling I've solved this myself before, but I can't for the life of me figure out how to do it right now.

So, in Unity, I have a Mecanim Animator Controller containing the basic character animations created in Spine - for example, idle, walk, run - and the transitions to and from each state. But I have now added additional animations in Spine - such as crouch and jump - and re-exported it from Spine. However, I can't figure out how to add the new animations to the existing controller without messing up the existing states and transitions. If I bake a new controller, that works fine, but I'd need to recreate all of the transitions and conditions. Rather than start over with a new controller everytime I create a new animation, I just want to add the new animation to the existing controller.

Seems like such an obvious thing, so I'm sure I'm just having brain issues.

tl;dr - How do I add newly-created Spine animations to an existing Mecanim Animator Controller?

Thanks

Related Discussions
...

I'm not set up to check this right now, but I believe you just need to look at the Controller asset in Project view. It should have a list of clips underneath it that you can drag into the Animator view to assign / create states, and it should automatically update to match new animations, I think.

Hi, clandestine.

Thanks for the reply, but no, it doesn't appear to behave like this. When I re-export from Spine with new animations and then go back to Unity, the relevant Controller isn't automatically updated, regardless of whether it's in the default "Baked" folder or has been moved elsewhere in the project. It seems the only way to get the new anim to appear is to re-bake it, but of course that creates a brand new Controller that doesn't contain any Mecanim transistions, variables or triggers that have already been created - it just lists each of the states in their default, err, state.

Thanks again for the reply, though.

Hi Jamie,

I'm not sure how things work with baked objects, but with the built-in integration with Mecanim, you can simply drag the animations from the project view into the animator window (where all of your existing states/transitions live). I'm not sure if it that is exactly the answer you are looking for, but I think the Mecanim Animator system is generally set up for drag and drop creation of states.

Hope that helps.

Hi blinz,

Yeah, that's what I'm hoping to be able to do, and indeed that was exactly what I did when setting up the original Controller. The problem is is that the new animations don't show up in the project window for the original Controller automatically. Only when I use the bake system does it create a new Controller file with all of the new and existing animations shown as children of it in the project window. The original Controller component just retains the original animations as children.

I think I can technically re-bake it to create a new controller (which has none of the previously set up Mecanim functionality but does have all of the animations), and then drag the new animations from the new Controller file onto the Animator window for the original Controller, but this seems like a recipe for confusion to me. Even when I do this, it still doesn't show the new animations as children of the original Controller file in the project window, even though it is shown in the Animator window... (Yep, I've just tested this and can confirm that's true).

So, I can get it to work in a bit of a hacky way, but it seems counter-intuitive to have to do the followings steps:

1) Export from Spine
2) Re-bake animations
3) Find newly-created Controller
4) Drag new animations one-by-one from there to original Controller Animator window (which does not visually update the children of the original Controller)
5) Edit Animator transitions

I just assumed it would make more sense if it went:

1) Export from Spine
2) New animations shown automatically
3) Add new animations to Controller Animator window in any of the usual ways
4) Edit Animator transitions

Perhaps I'm just missing something about the way that is has to work.

And I realise this is probably quite a difficult problem to visualise without being able to see exactly when I mean - it's definitely a tricky one to try to describe! 🙂

Is there a reason you need to bake your Spine objects? If you need/want to use Mecanim, I know that if you use the Mecanim integration built into the runtime, then it works like I described (animation updates/additions show up in the same controller and can be dragged into the animator window). All you have to do is instantiate a Mecanim instance rather than a SkeletonAnimation instance at the start. I realize you would still probably have to redo your state machine if you did this, but at least it would be more robust if you needed to add animations later on.

To be honest, as a relative novice with Unity, I'm not really sure on the difference between baking and not baking. And when I say "I'm not really sure", I mean I have no idea what it means! 🙂 That's something I plan to research a little later in my learning process.

But, if I right-click the SkeletonData and Instantiate Mecanim, that doesn't refresh the animations either, I'm afraid. That simply spawns a new player and aims its Animator at the original, non-baked Controller (as in, the one that I'm currently using for the Mecanim transitions). It doesn't refresh the list of child animations shown under the controller, so I still have no way of adding the new animations into Mecanim without creating a baked version first and then dragging the animations from that new Controller back into the original one that was created with right-click > Instantiate Mecanim. I have a feeling that may work if I first deleted my original Controller and I would then be able to see all the new animations, but, as you said, I'm assuming that would still delete all the state machines I have in Mecanim and I'd be back at square one anyway!

So, I still haven't found a great work-around this problem for now. Still having to bake a new controller and drag the individual animations around every time I add new animations. It isn't a terrible problem, but it just seems like there must be a more straight-forward and slightly less confusing way to do it.

Thanks very much for the suggestions though, guys. I really appreciate them.

This might be useless, but have you watched the video about the baking feature? I assume it mentions that somewhere...

The basic idea behind baking objects is that it converts them to native Unity objects. This means after baking, your objects no longer rely on the Spine runtime to function (I believe the video references this).

Being fairly new to Unity and Spine myself, I'm certainly no expert, but I would probably say not to bake your objects unless you really have a reason to do so. There are some cool elements to the Spine runtime (check out the features on this page: viewtopic.php?f=3&t=3318 ... Thanks, Mitch!) that you lose out on when baking. (I'm sure some more experienced Spine/Unity users may disagree with me on this 🙂 )

As far as getting things to work the way I was suggesting, I just tested and confirmed that the animation controller does update correctly. Here are the steps that I used (note that I am using Windows and Unity 5, although I'm pretty sure this worked the same in 4.6):

1) Export your animation from Spine and import into Unity (I usually just do this by dragging the files from Windows Explorer into the project window in Unity).
2) Right click on the SkeletonData.asset file that was generated, and click Spine>Instantiate (Mecanim). The object is added to the scene. Note, also, that an animation controller is added to your project that contains your animations. This animator is also automatically associated with the object in the scene.
3) Make a new animation in Spine and re-export
4) THIS STEP IS IMPORTANT: Open your Unity project folder in Window explorer (right click on any of the Spine data in the project window and select "Show in Explorer"), and in another Explorer window open the location where you exported your Spine data. Copy the atlas, png, and json files FROM the Spine export folder TO the Unity asset folder where your old Spine data exists. This will probably ask if you want to overwrite the files, and say yes for all files. (As a side note, I tried dragging the data directly into Unity, but this simply created a new copy and did not update the data that was already there)

At this point, when you go back to Unity, the data will be refreshed, and the animator controller that was already there should be updated with the new data (including your new animation). Additionally, the state machine (the animations and transitions) should be preserved, and you can simply drag and drop your new animations.

Hopefully that made some amount of sense. Let me know if this process works for you. If not, I'd consider making a video tutorial if that would be useful to you.

Good luck!

Thanks for that, Blinz. It hasn't actually worked, but I think I can see why (and I wouldn't be surprised if this is why it wasn't working for me at all to start with). I followed your steps and it didn't appear to work, but I noticed I'm getting the following error in the Console:

"NullReferenceException: Object reference not set to an instance of an object
SpineEditorUtilities.ResetExistingSkeletonData (System.String skeletonJSONPath) (at Assets/spine-unity/Editor/SpineEditorUtilities.cs:382)"

ResetExistingSkeletonData! That sounds very much like the kind of function I need. I've just looked in the SpineEditorUtilities.cs file and can see the following code:

static void ResetExistingSkeletonData (string skeletonJSONPath) {

  string dir = Path.GetDirectoryName(skeletonJSONPath);
  TextAsset textAsset = (TextAsset)AssetDatabase.LoadAssetAtPath(skeletonJSONPath, typeof(TextAsset));
  DirectoryInfo dirInfo = new DirectoryInfo(dir);

  FileInfo[] files = dirInfo.GetFiles("*.asset");

  foreach (var f in files) {
     string localPath = dir + "/" + f.Name;
     var obj = AssetDatabase.LoadAssetAtPath(localPath, typeof(Object));
     if (obj is SkeletonDataAsset) {
        var skeletonDataAsset = (SkeletonDataAsset)obj;

        if (skeletonDataAsset.skeletonJSON == textAsset) {
           if (Selection.activeObject == skeletonDataAsset)
              Selection.activeObject = null;

           skeletonDataAsset.Reset();
           
           string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(skeletonDataAsset));
           string lastHash = EditorPrefs.GetString(guid + "_hash");

           if (lastHash != skeletonDataAsset.GetSkeletonData(true).Hash) {
              //do any upkeep on synchronized assets
              UpdateMecanimClips(skeletonDataAsset);
           }

           EditorPrefs.SetString(guid + "_hash", skeletonDataAsset.GetSkeletonData(true).Hash);
        }
     }
  }
   }

That all looks fine to me, but I'm no expert, and obviously something has gone wrong. The ".asset" file is in the correct place, so I'm not sure what could be causing this.

Do you think I should start a new thread specifically for this error?

Yep, that is likely your problem. The line that is having that error is the first line below (based on the Git repo: https://github.com/EsotericSoftware/spi ... ilities.cs). That means the "UpdateMechanimClips" method is never getting called.

if (lastHash != skeletonDataAsset.GetSkeletonData(true).Hash) {
    //do any upkeep on synchronized assets
    UpdateMecanimClips(skeletonDataAsset);
 }

One thing that you can try is to change "true" in that line to "false". That parameter specifies if the GetSkeletonData function spits out debugging info. If you set it to false, you can see the debug info and maybe get a better idea of what is going on.

I just tested this with and without baking, and here's the behaviour I get:

  • With baking, animations aren't updated in the controller unless you choose "Bake All Skins" or "Bake [Skin]" from the actual SkeletonData asset. This makes sense, because baking animations into clips is much slower than creating a dummy asset to mirror Mecanim.
  • Without baking, animations are automatically updated in the controller when you export new animations.

My guess here is that your SkeletonData asset is pointing at the wrong / an invalid asset or something. Can you post:

  • Your directory layout (just a screen of the window in Unity)
  • Your Inspector window for the SkeletonData asset.

Yea... I should handle baking better...

Unity 5 solved a lot of problems with not being able to access Controllers through editor code so I was holding off. I'll take another pass at dealing with updating existing clips for Baking as long as they're still in the same folder.

Thanks for your replies.

I've uploaded two images:


unity_project.png


This shows the Project window. You can see the "character_suit_constraints_Controller" file only has 6 animations under it, and never gets updated automatically when I export new animations. At the moment, when I bake the SkeletonData, it goes into the "Baked" folder. That's where the updated Controller with all of the animations lives. When I add a new animations, I re-bake and go find the new Controller in that folder, then drag the new animation up a level into the Animator window for the Controller in the "characters > pc > data" folder.


unity_inspector.png


This is the Inspector for the SkeletonData file. You can see it's linked to the correct controller that's shown in the previous image. You'll also notice that there are 11 animations shown, only 6 of which are shown in the Controller in the previous image.

Okay, I've just done a test to figure out updating baked controllers. It looks like you can edit the controller and bake over it while maintaining transitions, so that's probably what you want to do. You could also use two controllers, but since you're doing baking the SkeletonData asset should not point at any controller. That's only for the Mecanim-connected SkeletonAnimator, which is separate from baking.

You said earlier that baking over the same controller was messing with your states / transitions, right? That's not happening for me - what version of Unity do you have?

I'm using Unity 5 now. If I try rebaking over the existing one, I get an error, but it's fine. I'm giving up on worrying about this for now. I'm sure it's just got something to do with how I originally set up my project, and I imagine I wouldn't encounter the same problems in future if I just make sure I edit the correct Controller in the first place. I can work around it anyway.

And you were right: If I bake a new Controller, edit it, then rebake, it does update the animations and retain the existing transitions.

2 months later

I'm actually experiencing this exact issue.. so there is no way to "Generate Mecanim Controller" and preserve your states and transitions?

I have just started my project so doing it the right way from scratch is no problem, but it seems very confusing what the proper workflow should be 😉

There are a ton of things I'd like to use in the Spine controller like swapping out attachments as sprites for equipping items on a player that I don't think you can do if you bake?

That's right. Baking doesn't support a lot of features. Baking is a workaround in case you don't need/don't want to use or rely on the Spine runtime— which includes publishing stuff to the Unity Asset store (though I heard that this is actually okay).

As for Mecanim controller stuff, I'll send a message to Mitch to let him know you're having problems.

Small bit to add. I just tried exporting after making a new animation and then went into Unity, made sure the SkeletonData had the Animation Controller still hooked up in the inspector and then did Instantiate(Mecanim). This appears to update and if not existing, create a new animation controller which might work great except that it duplicated a ton of clips under my controller and now I can't get them out. Any idea why this would have occured?

Edit: It seems unity auto updates the controller after you build over to unity so not sure what caused all the dupe clips now unfortunately...