Reusing animations across different models

Hi all,

I’m trying my hand at animation, have run into a problem and could do with some advice.

My approach is to load character models separately from their animations, thereby avoiding the need for the animations and models to be tightly coupled (and the associated admin overhead!).

In my latest attempt I managed to:

  • Load a single glb from an exported scene in blender, which includes 2 rigged character models
  • Load an fbx file which includes a single animation, create an animation clip from it
  • Find character models in loaded scene, create its own mixer, get the anim clip to create an action with the mixer
  • Play the action

The animation works on the first model, but not the second. Reason being, threejs is renaming each bone in the second model to ‘boneName_1’ which voids the clip because the tracks are trying to find ‘boneName’. In blender, the bones for both models have duplicate names so I’m assuming threejs is doing the renaming.

At this point, I thought I’d reach out and check if this approach (separate anim clips to models) is simply not going to work. I’d rather not have to export the animations as part of the models individually, as that’s just work (esp when you want to add/remove animations). Similarly, I’d rather not start renaming bones on load as that’s verbose and error-prone.

So is my approach valid or daft? Cast your vote!

If it helps, you can go here and check the console for error and object logs.

For full code, see repo here this or I’ve pasted pertinent logic below.

      // In animLoader:
      private loadAnims() {
      const loader = new FBXLoader(this.loadingManager);

      const url = new URL("/anims/sitting.fbx", import.meta.url).href;
      loader.load(url, (group) => {
        // Should only be one animation present
        if (group.animations.length) {
          const clip = group.animations[0];
          this.anims.set("sitting", clip);
          }
      });
    }

    // I'm loading in a glb file similarly, assigning gltf.scene to a map which I get here
    const mainScene = this.gameLoader.modelLoader.get("my-scene-model-name");

    // Create animated character objects
    const { animLoader } = this.gameLoader;
    const chars: AnimatedCharacter[] = [];
    ["bandit1", "thug1"].forEach((name) => {
      // Find the character model within the main scene object
      const object = mainScene.getObjectByName(name);
      if (object) {
        // Create its own animation mixer
        const mixer = new THREE.AnimationMixer(object);

        // Get the animation clips for this character
        const clips = animLoader.getClips(["sitting"]);

        // Create animation actions for this character from clips
        const actions: THREE.AnimationAction[] = [];
        clips.forEach((clip) => {
          // Create a character animation action for this clip
          actions.push(mixer.clipAction(clip));
        });

        // Add the object
        chars.push({
          object,
          mixer,
          actions,
        });
      }
    });

Thanks for reading!

I usually fix these by just repairing the bone names. It’s generally helpful to have some standard.

scene.traverse(b=>(b.isBone)&&(b.name = b.name.replace('_1',''))

Yeah I could start doing string replacements for n models, but it just feels like a hack to address an issue somewhere in my asset prep pipeline!

I’m beginning to think this is an issue caused by exporting the rigged models together with the scene as a single glb…

I’m going to put a pin in this - I don’t think there’s an easy answer to my problem, though I do think the general approach is sound (reuse anims between similarly rigged models)