Loading character with animations to scene and cloning it with animation groups

Hi everyone! I have a similar pickle that the person in this thread: How the heck do you load in your model with animations?

I’m trying to develop a large-ish game with Babylon.js. Currently I have some static models (wall pieces, floor pieces, general assets and objects that are in the map) and now some characters with animations. I currently use the AssetsManager to load all the required stuff, with bit of a different handling on the success -method with static assets and characters.

What I try to do with characters is the following:

  1. Load the character glb file with AssetsManager
  2. Save the result for easy access and future use on my own plain JavaScript object
  3. When needed, fetch the character model and animations and play one of the many animations
  4. Change the animation if needed (running to walk, inspired by https://playground.babylonjs.com/#6I67BL#2)

This requires me to clone the mesh and animations somehow. The animations per clone need to be individual as well. In the other thread there was this solution: https://playground.babylonjs.com/#AJA5J6#76
However, I would prefer to use AssetsManager and store the models/animations to a storage I can kind of take care of my own, if possible. Other reason to use AssetsManager is that the loader for all asset types is the same one.

So the question is can I use the AssetsManager to load somewhat complex characters and clone them with animations somehow? I’ve been trying to figure this out with my own model for hours now, feeling a bit desperate… The model I am currently using is working in sandbox perfectly with multiple animations and it also loads into the scene well (if setEnabled(true)). The only problem is the actual instantiation of the characters to the scene with the animations.

1 Like

Shortly, instances will always play the same animation group; clones are able to play different animation groups.
As for your Assets Manager question, these threads may be helpful
Cloning with AssetsManager
meshTask + clone + animationGroups
PG Example - https://playground.babylonjs.com/#ZQPDEF#18

1 Like

Yeah, it is the cloning I want to achieve! :slight_smile:

The playground example with the planes is kind of what I am looking for, but it still feels a bit “hacky” way to achieve the end goal. It uses the asset container and extends the AbstractAssetTask… I would like to use one or another :slight_smile:

So I made two tests. The first one is with asset containers. Seems to work pretty well, attached it to this playground with my custom model that I am using in my game: https://playground.babylonjs.com/#S7E00P#39

However, I would like to know a bit deeper how everything works and what goes into cloning mesh/animation/skeleton data. I also would still, stubbornly, prefer to use assetManager. I have created a playground for this purpose, but I don’t really understand what magic I am missing:
https://playground.babylonjs.com/#S7E00P#43
I try to clone the root mesh, then the skeleton and animationgroups. When I do this I think I can’t bind the skeleton to the new mesh properly as the scaling seems really of as you can see from the next picture :laughing: … I am also using Mixamo animations, so I wonder if they do something naughty to the model itself? :thinking:

You need to assign the cloned skeleton to the cloned mesh : https://playground.babylonjs.com/#S7E00P#44

2 Likes

Thank you @sebavan ! Looks really good now!

Then, the only thing left is to understand how the animation group cloning works. Currently the animation groups, even though cloned, are somehow linked to the original skeleton/mesh? In the asset container code, the cloning process tries to attach the animation groups to the clone skeleton/mesh, right? Here are the actual lines for it: Babylon.js/assetContainer.ts at master · BabylonJS/Babylon.js · GitHub

So I should pretty much try to have the new cloned skeleton bones saved somewhere and try to attach the cloned animation group TargetedAnimations to it?

2 Likes

Yup I would think so.

1 Like

Tried to do this the similar way asset containers were doing this but still missing a secret sauce I’m afraid… https://playground.babylonjs.com/#S7E00P#45

Can’t get the animations to play different animations when cloned :exploding_head:

I guess you might miss this part : Babylon.js/assetContainer.ts at master · BabylonJS/Babylon.js · GitHub

Mainly this one: Babylon.js/assetContainer.ts at master · BabylonJS/Babylon.js · GitHub

1 Like

Yeap, you are correct! I was suspicious of that part as well, but didn’t have time to test it yet :slight_smile:

Here is the final version, with added animation blending!

So what I gather, here is what needs to be done if you wish to clone a fully rigged and animated character “manually”. I also assume there might be some differences if the glb/gltf formats are not used…

  1. You need to store the root mesh, the skeleton and the animation groups somewhere.
  2. Clone the root mesh using instantiateHierarchy, with the doNotInstantiate -option. You also need to store the links between the original mesh parts with the cloned mesh parts.
  3. Clone the skeleton with the regular clone function.
  4. Set the cloned root mesh as skeletons overrideMesh if skeleton already has this pointing to somewhere (as in the original mesh, so it needs to be replaced).
  5. Fetch all the descendants of the rootMesh with getDescendants (with false as option)
  6. Set the cloned skeleton as the skeleton of all the descendants.
  7. Link all the cloned skeleton bones with the new cloned root mesh. You need to use the stored links created in section 1.
  8. Clone each animation group separately using the clone function. This works a bit differently than normal clone, since you need create a special conversion function to set the animation group to a new target, which is some part of the new cloned root mesh hierarchy. Here you need the stored links as well from section 1.
  9. Done! You can use your cloned animation groups to play animations separately :slight_smile:

Have to say that I really love Babylon community :heart: Thank you all for helping me!

Update:
You can use asset containers to do the same thing easier! Check this playground: https://playground.babylonjs.com/#S7E00P#237

7 Likes

Hi, just want to pass my just acquired knowledge to everyone who will come to this thread searching for help with animating cloned characters with multiple meshes, in this case root + model mesh. You can download model here and preview it in sandbox to see what this “root + model mesh” means.

Working code: https://playground.babylonjs.com/#S7E00P#225

Enhanced TODO list from @Panuchka :

  1. You need to store the root mesh and model mesh, the skeleton and the animation groups somewhere.
  2. Clone the root mesh and model mesh using instantiatehierarchy, with the doNotInstantiate -option. You also need to store the links between the original mesh parts with the cloned mesh parts.
  3. Clone the skeleton with the regular clone function.
  4. Set the cloned skeleton to model mesh
  5. Fetch all the descendants of the Model mesh with getDescendants (with false as option)
  6. Set the cloned skeleton as the skeleton of all the descendants.
  7. Link all the cloned skeleton bones with the new cloned root mesh/model mesh. You need to use the stored links created in section 1.
  8. Clone each animation group separately using the clone function. This works a bit differently than normal clone, since you need create a special conversion function to set the animation group to a new target, which is some part of the new cloned root mesh/model mesh hierarchy. Here you need the stored links as well from section 1.
  9. Done! You can use your cloned animation groups to play animations separately :slight_smile:

As an absolute newcomer to 3D models/Babylon.js I struggled for many hours with this, try-failing many there-and-back changes in the code, so I hope this will ease others journeys :slight_smile:

3 Likes

This is an old thread so it might be worth mentioning that we now have an instantiateModelsToScene function that can duplicate a loaded asset container with a single call.

doc: https://doc.babylonjs.com/divingDeeper/importers/assetContainers#duplicating-the-models

3 Likes

Yeah, could update the playgroynd at some point for the assetContainer method (if you don’t have time to do it) :slight_smile: I think there was some hassle that I didn’t use the assetContainer back in the day :thinking:

Coming back to this, assetContainers feel a bit tough to deal with in my game example. I don’t think there is a specific method in the assetContainer to get a specific model to the scene.

I would like to use asset container as a pool of assets where I can get a specific model instantiated using a specific key. For example, I want to load 20 assets to the asset container, and just instantiate the player model. The instantiateModelsToScene just seems to insert all the models of the asset container to the scene.

I could use the assetContainer so that I only add one model to it, but it still gives me a list of nodes and feels a bit awkward to use. To me kind of feels that assetContainers haven’t been thinked through, or that I am really missing something :thinking:

Using one model per assetContainer seems to work pretty well actually.

I changed the previous final product to show how to implement similar functionality with assetContainers: https://playground.babylonjs.com/#S7E00P#237

7 Likes

I’m about to deep dive into this thread to figure out what magic you guys are doing above. But one thing that’s weird about the examples in this thread. If you go to inspector, open Animation groups - and play/pause the groups individually, the behavior is odd. Sometimes both characters stop. Sometimes they don’t restart on play. Sometimes one plays and the other stops.

Is it just that the inspector isn’t capable of starting/stoping the clones via the Animation Group name, given the way they were cloned?

And second question: is all the data from the animation groups doubled? If i cloned 100 characters, is the animation data replicated? Or some kind of pointer created?

thx!

That’s pretty weird. I have no idea why it does this. @carolhmj Do you have time to check this out?

I scanned the code and it looks like the data is duplicated.

I do!

It’s not, the animation group is cloned: Babylon.js/assetContainer.ts at master · BabylonJS/Babylon.js (github.com), but the actual data is reused: Babylon.js/animationGroup.ts at master · BabylonJS/Babylon.js (github.com), which is what was causing problems on the inspector. I fixed that, and also for some reason when the play button for one group was clicked, it was pausing every other group. PR is here: Fix: Animation Groups not showing the correct current frame value in … by carolhmj · Pull Request #13307 · BabylonJS/Babylon.js (github.com)

7 Likes

Ah, yes, I scanned the code too fast and missed the flag :slight_smile:

2 Likes