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:

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