hey everyone,
whats the simplest way to play the animations of an imported GLTF file? The file contains a mesh, its skeleton and two animation clips (“jump”, “wink”). I test it, the file works fine (tested in two GLTF Viewers) but when i try to play the animations:
scene.getObjectByName(“Suzanne”).geometry.animation[0].play()
i get an error, that there is no property like this…
1 Like
Do it like so:
const loader = new THREE.GLTFLoader();
loader.load( 'model.glb', function ( gltf ) {
mixer = new THREE.AnimationMixer( gltf.scene );
var action = mixer.clipAction( gltf.animations[ 0 ] );
action.play();
scene.add( gltf.scene );
} );
This code is deprecated. Animations are not stored in the geometry object. Besides, do not forget to update the mixer in your animation loop.
1 Like
thanks for your help.
is there a seperate loop fot the bone animation?
1 Like
No it’s your normal animation loop, see
1 Like
that works, thank you. Its also possible to manipulate the playback speed, very interesting
My glb file has more than one animation clip but in the loader only one got addet to the mixer object
var action = mixer.clipAction( gltf.animations[ 0 ] );
so i tried to add another clip in the loader callback
let cube
const loader = new THREE.GLTFLoader()
loader.load( ‘assets/cube_bone.glb’, (gltf) => {
mixer = new THREE.AnimationMixer( gltf.scene );
let action = mixer.clipAction( gltf.animations[ 1 ] )
mixer.clipAction( gltf.animations[ 0 ] )
action.play();
scene.add( gltf.scene )
} );
so, the mixer objects now contains two action, but i couldnt start the second clip while my app was running
mixer._actions[1].play()
1 Like
Yes, for example by modulating AnimationAction.timeScale.
If you want to playback more than one animation clip, I suggest you study how webgl_animation_skinning_blending works. The example creates the animation actions like so:
mixer = new THREE.AnimationMixer( model );
idleAction = mixer.clipAction( animations[ 0 ] );
walkAction = mixer.clipAction( animations[ 3 ] );
runAction = mixer.clipAction( animations[ 1 ] );
At a later point, it depends on your requirements how you want to playback these action (e.g. with or without fading).
1 Like
thanks again. I think i now better understand how the animation system is working
here’s my working example if some else is searching for it…
let camera, scene, renderer, dt, lastframe = Date.now(), mixer
let idleAction, jumpAction
init();
update();
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 500 );
camera.position.z = 9
camera.position.y = 4
scene = new THREE.Scene()
let ambilight = new THREE.AmbientLight( 0xcccffc, 3.4 );
ambilight.name = "ambilight"
scene.add( ambilight );
let dirlight = new THREE.DirectionalLight( 0xffcffc, 5.4 );
dirlight.name = "dirlight"
dirlight.position.set(0,0,0)
scene.add( dirlight );
const loader = new THREE.GLTFLoader()
loader.load( 'assets/cube_bone.glb', (gltf) => {
mixer = new THREE.AnimationMixer( gltf.scene );
idleAction = mixer.clipAction( gltf.animations[ 1 ] )
jumpAction = mixer.clipAction( gltf.animations[ 0 ] )
scene.add( gltf.scene )
// starts idle animation
idleAction.play()
} );
renderer = new THREE.WebGLRenderer( { antialias: true } )
renderer.setClearColor("#434")
renderer.physicallyCorrectLights = true;
renderer.setSize( window.innerWidth, window.innerHeight )
window.addEventListener("resize", e => {
renderer.setSize( window.innerWidth, window.innerHeight )
camera.aspect = window.innerWidth/ window.innerHeight
camera.updateProjectionMatrix()
})
document.body.appendChild( renderer.domElement );
}
function update() {
dt = (Date.now()-lastframe)/1000
if(mixer){
mixer.update(dt)
}
renderer.render( scene, camera );
lastframe=Date.now()
requestAnimationFrame( update );
}
2 Likes
This guide might be helpful: three.js docs
2 Likes