Search code examples
javascriptanimationthree.jsconsole.logrequestanimationframe

Three.js animation mixer doesn't update unless logged in animation loop


Very strange behaviour in JavaScript, a simple AnimationMixer.update(delta) doesn't work unless I console.log it:

// This works
function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
  // Update mixers...
  Object.values(sandbox.models).forEach(x => (x.mixer && console.log(x.mixer.update(clock.getDelta()))));
}

// These don't work
function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
  // Update mixers...
  Object.values(sandbox.models).forEach(x => (x.mixer && (x.mixer.update(clock.getDelta()))));
}

function animate() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
  // Update mixers...
  Object.values(sandbox.models).forEach(x => (x.mixer && void(x.mixer.update(clock.getDelta()))));
}

Then, when playing the animation by AnimationMixer.clipAction(animation).play() does not play unless I do the first one.

This is very strange, why does the mixer only update when logged the return value?

I can't show all the code because it's too long and won't work because I have linked files too.

And as you may know you can't log thousands of times per second, it's stupid in general and will slow down the game.


Solution

  • You should never call Clock.getDelta() more than once in your animation loop. Otherwise the delta values will be near 0 (since you get the elapsed time between the last getDelta() call). So try it like so:

    function animate() {
      requestAnimationFrame(animate);
      const delta = clock.getDelta();
      renderer.render(scene, camera);
      // Update mixers...
      Object.values(sandbox.models).forEach( x => {
        if (x.mixer) x.mixer.update(delta);
      } );
    }
    

    Also avoid the usage of Object.values() per frame since it will return a new array on each invocation which is bad for performance (this just leads to GC overhead).