Skip to content

Animation doesn't play correctly if child name if not unique #31371

@floriandotorg

Description

@floriandotorg

Description

Hey, THREE.js team,

First, thank you for your amazing work!

I've encountered the following bug, if you have the following hierarchy:
A > Test
B > Test

And you create animation tracks like this:
A/Test.position
B/Test.position

The animations are not played correctly. If you change the child names, e.g.
A > TestA
B > TestB

It works as intended.

Reproduction steps

  1. Create a hierarchy like
    A/Test.position
    B/Test.position
  2. Create animation tracks for both like:
    A/Test.position
    B/Test.position
  3. Play animation

Code

In the example both cubes should be moving:

import * as THREE from 'three'

let scene, camera, renderer, mixer;
let groupA, groupB, meshA, meshB;
let animationA, animationB;

const TESTA_NAME = 'test'
const TESTB_NAME = 'test'

function init() {
  // Scene setup
  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(800, 500);
  renderer.setClearColor(0x1a1a1a);
  document.getElementById('container').appendChild(renderer.domElement);

  // Create hierarchy as described in the bug report
  groupA = new THREE.Group();
  groupA.name = 'A';
  groupA.position.set(-2, 0, 0);

  groupB = new THREE.Group();
  groupB.name = 'B';
  groupB.position.set(2, 0, 0);

  // Create meshes with same name in different groups
  const geometryA = new THREE.BoxGeometry(1, 1, 1);
  const materialA = new THREE.MeshBasicMaterial({ color: 0xff0000 });
  meshA = new THREE.Mesh(geometryA, materialA);
  meshA.name = TESTA_NAME;

  const geometryB = new THREE.BoxGeometry(1, 1, 1);
  const materialB = new THREE.MeshBasicMaterial({ color: 0x0000ff });
  meshB = new THREE.Mesh(geometryB, materialB);
  meshB.name = TESTB_NAME;

  // Add meshes to their respective groups
  groupA.add(meshA);
  groupB.add(meshB);

  // Add groups to scene
  scene.add(groupA);
  scene.add(groupB);

  // Add some lighting
  const ambientLight = new THREE.AmbientLight(0x404040, 0.6);
  scene.add(ambientLight);
  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
  directionalLight.position.set(1, 1, 1);
  scene.add(directionalLight);

  // Position camera
  camera.position.set(0, 0, 8);
  camera.lookAt(0, 0, 0);

  // Create animation mixer
  mixer = new THREE.AnimationMixer(scene);

  // Create animation tracks for both meshes
  createAnimationTracks();

  animate();
}

function createAnimationTracks() {
  // Animation for A/test - should only affect red cube
  const timesA = [0, 1, 2];
  const valuesA = [
    0, 0, 0,      // start position
    0, 2, 0,      // middle position (up)
    0, 0, 0       // end position
  ];

  const trackA = new THREE.VectorKeyframeTrack(`A/${TESTA_NAME}.position`, timesA, valuesA);
  const clipA = new THREE.AnimationClip('animationA', 2, [trackA]);
  animationA = mixer.clipAction(clipA);
  animationA.setLoop(THREE.LoopRepeat);

  // Animation for B/test - should only affect blue cube
  const timesB = [0, 1, 2];
  const valuesB = [
    0, 0, 0,      // start position
    0, -2, 0,     // middle position (down)
    0, 0, 0       // end position
  ];

  const trackB = new THREE.VectorKeyframeTrack(`B/${TESTB_NAME}.position`, timesB, valuesB);
  const clipB = new THREE.AnimationClip('animationB', 2, [trackB]);
  animationB = mixer.clipAction(clipB);
  animationB.setLoop(THREE.LoopRepeat);
}

function startBothAnimations() {
  animationA.reset();
  animationB.reset();
  animationA.play();
  animationB.play();
}

function animate() {
  requestAnimationFrame(animate);

  const delta = 0.016; // ~60fps
  if (mixer) {
    mixer.update(delta);
  }

  renderer.render(scene, camera);
}

// Handle window resize
window.addEventListener('resize', () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});

// Initialize the scene
init();
startBothAnimations()

Live example

In the example both cubes should be moving:
https://jsfiddle.net/5cxyumjr/

You can change TESTA_NAME to something like testb and it works.

Screenshots

No response

Version

r178

Device

Desktop

Browser

Chrome

OS

MacOS

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions