Pattern to use for multiple animations on different GLTF models

three.js r150, GLTFLoader, AnimationMixer

My application consists of 20 “primary” GLTF models, each with a skeleton and an animation. I load them all into the scene and create animation mixer and animation group. Then, when the user selects one, they are given the option to select from a number of “secondary” GLTF models to display along side. When a secondary is selected, I apply the skeleton from the primary, add the secondary to the animation group and play the animation.

It all works well for a simple one-off test but I need to support clearing and rebuilding the animation machinery each time the user changes primary models.

I’ve had some success but plenty of errors too so I thought asking here about the correct pattern to use would be a good idea before I dig deeper. A single AnimationMixer or one for each primary and update an array of them in my animation render loop? A separate AnimationObjectGroup for each primary then add/remove secondaries to/from it?

I would normally create a CodePen or JS Fiddle to illustrate my question but that’s not possible in this instance.

Thank you.

Animation affects the skeleton / bones of the character. If you are certain that the skeletons of all possible characters are identical — names of bones, default orientation and size, inverse bind matrices, everything — then you could reuse a single mixer and animations all with that same skeleton, and just swap out the SkinnedMesh that uses the skeleton.

If you aren’t certain about that, I think it’d probably be safest to have an AnimationMixer per character model. Store your AnimationClip objects for reuse, but each time the character model changes you’ll use the new AnimationMixer to create new clip actions.

Understood and thank you.

I found a solution that works and I think it’s essentially the latter suggestion you made.

When each GLTF is loaded, I save the animation in the object userData (since I don’t have access to it once I run the loaded model throughSkeletonUtils.clone and add it to the scene.

Then, when a primary and set of secondaries are selected, I create an AnimationGroupObject and use that to create an AnimationMixer. Then along with the animation I saved in the scene, I construct the animation machinery and play it. Seems to work nicely.

One thing I added that makes a big difference visually is to record the time offset from the current animation and then use setTime on the new one to jump to the same spot - feels a lot smoother.

I tried lots of things that didn’t work and for most of them, I wasn’t sure why.

For example, I thought I might be able to save an AnimationMixer and AnimationGroupObject for each primary and then when I process the secondaries, just remove existing ones from the existing AnimationGroupObject and add the new ones. I couldn’t find support in the API to do that though. No AnimationGroupObject::clear() for example

I also tried creating an AnimationMixer and AnimationGroupObject for each primary and adding all the secondaries to it at load time. My assumption was that the ones marked invisible in the scene (~300) would have little impact compared to the visible ones (~5). That didn’t work either.

In any case, I have something that works well now - my only concern is generating a new AnimationObjectGroup and AnimationMixer each time the selection changes - I don’t know enough about JS determine if the old one will be discarded automatically or not.

Oh, and BTW - one issue I’ve been putting off is finding a way to more quickly load the several hundred GLBs - I installed gltf-transform and it’s magnificent. With just a single pass (draco) I was able to reduce the file size by 45% which helped with load time immensely. I did try a pass with optimize but I think it was too aggressive - the resulting models looked noticeably less smooth and some of the objects in the model that my code relies on seemed to have been optimized away. Plenty of options to play with though - thank you for making and sharing such a great tool.