Playing an animation changes behaviour of next animation

Hi,
I am trying to animate the stories of a house. It should be possible to animate the house to the first story and after that to the second story. Like this:
Bildschirmfoto 2020-03-19 um 16.19.55

The animations look fine in the gltf viewer. When I play the animation to the first story (“Stock 1”), it works perfectly, but when playing the animation to the second story (“Stock2”), the cube does not get animated to the full extend of the story. Calling the animations separately also works. It seems like that the first animation somehow influences the following animation.

This is how I play the animation clips:

  this.action = this.mixer.clipAction(clip)
  this.action.reset()
  this.action.timeScale = 1
  this.action.setLoop(THREE.LoopOnce)
  this.action.clampWhenFinished = true
  this.action.play()

The gltf file: house-stories (241.7 KB)

Thank you for your help!

Try to remove this line since setting AnimationAction.clampWhenFinished to true will only pause the animation on its last frame meaning it still influences the model.

How am I able to stop the animation on the last keyframe then? When I play the animation without clampWhenFinished the animation plays once and jumps to the starting position (like in the gltf viewer).

Okay, I see not what you mean. Maybe you can try to achieve the intended effect by using a brand-new feature called additive animations. The influence of each animation won’t be weighted/normalized but added together. The following example demonstrates this feature:

https://threejs.org/examples/webgl_animation_skinning_additive_blending

You can make your animation clips additive by this call and then use them as usual:

THREE.AnimationUtils.makeClipAdditive( clip );
1 Like

Thank you for your help @Mugen87! Unfortunately this does not work. What I want to achieve is to move an object from one position to another using animations. The end state of the first animation is the starting point for the second animation. How can I achieve this without clamping?

You could set the AnimationAction.weight to 0 when you do not want it to have some influence on the object. And than starts another animation that impacts the same object. I dont know if it is the best practice but i used it once and worked. (Still using the AnimationAction.clampWhenFinished to true).

For triggering the animation maybe you can use the ‘finished’ event.

(yeah, a little late answer)

Thank you for your answer! If anyone is interested, the solution I came up with was to keep a reference to the previous action and set it’s influence to 0 before starting the next action. This makes it possible to use the end state of the first animation as the starting point for the second animation. My function to play an animation with a given name looks something like this:

play(name) {
  return new Promise(resolve => {
    const clip = THREE.AnimationClip.findByName(this.animations, name)

    this.action = this.mixer.clipAction(clip)
    this.action.reset()
    this.action.timeScale = 1
    this.action.setLoop(THREE.LoopOnce)
    this.action.clampWhenFinished = true

    if (this.prevAction) {
      this.prevAction.fadeOut(0) // Set the influence of the previous action to 0
    }
    this.action.play() // Play the animation

    // The animation finished playing
    this.mixer.addEventListener('finished', () => {
      this.prevAction = this.action // Save a reference to the previous action
      resolve()
    })
  })
}
3 Likes