Hello all,
I’m having a tough time with this method, AnimationClip.CreateFromMorphTargetSequence…
I loaded a GLB with some animations. I want two of them to loop only once and stop at last frame.
However, as talked here, the loader copy the first frame of the animations on the last, to make loops look smoother. Someone came up with a solution here, but I cannot use it the right way apparently…
I’m supposed to make a new AnimationClip from the old one (the one with the last frame I don’t want), with AnimationClip.CreateFromMorphTargetSequence, with “noLoop” parameter set to true. I tried but it doesn’t work.
I made a live exemple, with some anotations in the code
<!DOCTYPE html>
<html>
<head>
<title>Live exemple of my problem</title>
<meta charset="utf-8">
<style>
#world {
position: fixed;
margin:0;
top:0;
left:0;
width: 100vw;
height: 100vh;
overflow: hidden;
}
#menu {
position: fixed;
margin: 0;
padding: 15px;
top: 25vh;
width: 30vw;
height: 50vh;
background-color: #ffcce6;
text-align: center;
z-index: 1;
}
#menu>button {
margin: 10px;
}
</style>
</head>
<body>
<div id="world"></div>
<div id="menu">
<p>Click on this button to play the three animationAction.</p>
<button onclick="onButtonClick()">open the cap</button>
<p>Two of them (keyRise and capRise,) are supposed to loop only once
and stop at the last frame. For each of them, I set the clampWhenFinished
property to true, but to no apparent effect.</p>
<p>I found an Issue <a href="https://github.com/mrdoob/three.js/issues/8446">here</a>
about my problem</p>
<p>Apparently the loader is at fault, because it copy the first fram as the last
to make loops look smoother. So in my case I'm supposed to use
<a href="https://github.com/mrdoob/three.js/pull/8637/commits/9d223623114a5473af120a7f6a90d74e01d63205">CreateFromMorphTargetSequence</a>
, but I'm not sure how.</p>
<p>You will find more information about this in my code in the GLTFloader</p>
</div>
<script src="Three.js"></script>
<script src="GLTFLoader.js"></script>
<script src="stats.min.js"></script>
<script src="OrbitControls.js"></script>
<script>
window.addEventListener("load", function() {
main();
}, false);
var scene, camera, renderer, stats, clock, loader;
var loader, keyMixer, capMixer, keyRotation, keyRise, capRise;
function onButtonClick() {
keyRotation.play();
keyRise.play();
capRise.play();
keyRise.clampWhenFinished = true;
capRise.clampWhenFinished = true;
keyRise.loop = THREE.LoopOnce;
capRise.loop = THREE.LoopOnce;
};
function main() {
scene = new THREE.Scene();
scene.background = new THREE.Color(0x39ac73);
camera = new THREE.PerspectiveCamera(35, window.innerWidth/window.innerHeight, 0.5, 100);
camera.position.set(0, 0.3, 1.5);
camera.lookAt(0, 0.3, 0);
renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById("world").appendChild(renderer.domElement);
stats = new Stats();
document.body.appendChild(stats.dom);
addShadowedLight( -10, 6, -10, 0xffffff, 0.5);
addShadowedLight( 1, 1, 1, 0xffffff, 0.5 );
addShadowedLight( 0.5, 1, -1, 0xffaa00, 0.1 );
clock = new THREE.Clock();
clock.start();
// GLB importation //
loader = new THREE.GLTFLoader();
loader.load("PineappleAndKey.glb", function(glb) {
var animations = glb.animations;
var pot = glb.scene.getObjectByName("pot");
var cap = glb.scene.getObjectByName("couvercle");
var key = glb.scene.getObjectByName("clef");
var group = new THREE.Group();
group.add(pot, cap, key);
scene.add(group);
group.position.z += 0.8;
capMixer = new THREE.AnimationMixer(cap);
keyMixer = new THREE.AnimationMixer(key);
keyRotation = keyMixer.clipAction(
THREE.AnimationClip.findByName( animations, 'rotationClef' ));
keyRise = keyMixer.clipAction(
THREE.AnimationClip.findByName( animations, 'elevationClef' ));
capRise = capMixer.clipAction(
THREE.AnimationClip.findByName( animations, 'ouverturePot' ));
// Here is what I should write if I follow the process described in the
// pull request whose link I give in the text (here is the link again :
// https://github.com/mrdoob/three.js/pull/8637/commits/9d223623114a5473af120a7f6a90d74e01d63205).
// To try it, use the following code and remove
// the last capRise declaration just above.
// var clipCapRise = THREE.AnimationClip.findByName( animations, 'ouverturePot');
// var clipCapRiseNoLoop = THREE.AnimationClip.CreateFromMorphTargetSequence(
// 'ouverturePot', clipCapRise.tracks[0], 60, true);
// capRise = capMixer.clipAction(clipCapRiseNoLoop);
// When I try this, the animation does not work at all.
// I'm sure there is something wrong with my use of CreateFromMorphTargetSequence
},
function ( xhr ) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
function ( error ) {
console.log( 'An error happened' );
}
);
/////////////////////
loop();
function loop() {
requestAnimationFrame(loop);
stats.update();
if (keyMixer && clock) {
var t = clock.getDelta();
keyMixer.update(t);
capMixer.update(t);
};
renderer.render(scene, camera);
};
function addShadowedLight( x, y, z, color, intensity ) {
var directionalLight = new THREE.DirectionalLight( color, intensity );
directionalLight.position.set( x, y, z );
directionalLight.castShadow = true;
var d = 1;
directionalLight.shadow.camera.left = -d;
directionalLight.shadow.camera.right = d;
directionalLight.shadow.camera.top = d;
directionalLight.shadow.camera.bottom = -d;
directionalLight.shadow.camera.near = 0.1;
directionalLight.shadow.camera.far = 30;
directionalLight.shadow.mapSize.width = 1048;
directionalLight.shadow.mapSize.height = 1048;
directionalLight.shadow.bias = -0;
scene.add( directionalLight );
};
};
</script>
</body>
</html>
The GLB file is here :
PineappleAndKey.glb (67.6 KB)
I would be so glad if you helped me wrap my head around this method…