From 53a343ec45c73bf947c30500f4059533bb91fcd6 Mon Sep 17 00:00:00 2001 From: Kevin Date: Thu, 25 Nov 2021 06:52:47 +0800 Subject: [PATCH 1/3] smooth speed based mount animations --- type_templates/glb.js | 100 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 94 insertions(+), 6 deletions(-) diff --git a/type_templates/glb.js b/type_templates/glb.js index a905363..517dc36 100644 --- a/type_templates/glb.js +++ b/type_templates/glb.js @@ -1,7 +1,7 @@ import * as THREE from 'three'; import metaversefile from 'metaversefile'; -const {useApp, useFrame, useCleanup, useLocalPlayer, usePhysics, useLoaders, useActivate, useAvatarInternal, useInternals} = metaversefile; +const {useApp, useFrame, useCleanup, useLocalPlayer, usePhysics, useLoaders, useActivate, useAvatarInternal, useInternals, getSpeed} = metaversefile; const wearableScale = 1; @@ -55,6 +55,9 @@ export default e => { // sit state let sitSpec = null; + let rideAction = null; + let mountMixer = null; + let mountActions = []; const petComponent = app.getComponent('pet'); const _makePetMixer = () => { @@ -81,6 +84,23 @@ export default e => { idleAction, }; }; + + const sitComponent = app.getComponent('sit'); + const _makeMountMixer = () => { + let mountMixer; + + let firstMesh = null; + glb.scene.traverse(o => { + if (firstMesh === null && o.isMesh) { + firstMesh = o; + } + }); + mountMixer = new THREE.AnimationMixer(firstMesh); + + return { + mountMixer, + }; + }; let activateCb = null; e.waitUntil((async () => { @@ -122,9 +142,22 @@ export default e => { let clip = idleAnimation || animations[animationMixers.length]; if (clip) { const mixer = new THREE.AnimationMixer(o); - const action = mixer.clipAction(clip); - action.play(); + + if(sitComponent) { + const disableLoop = sitComponent.disableLoop ? sitComponent.disableLoop : false; + const clamp = sitComponent.clampAnimation ? sitComponent.clampAnimation : false; + + if(disableLoop) { + action.loop = THREE.LoopOnce; // Only plays once + } + + if(clamp) { + action.clampWhenFinished = true; + } + } + //action.play(); + mountActions.push(action); /* let lastTimestamp = Date.now(); const update = now => { @@ -138,6 +171,9 @@ export default e => { update(deltaSeconds) { mixer.update(deltaSeconds); }, + clear() { + mixer.stopAllAction(); + } }); } } @@ -337,11 +373,16 @@ export default e => { } }); - if (petComponent) { + if (petComponent) { const m = _makePetMixer(); petMixer = m.petMixer; idleAction = m.idleAction; } + + if (sitComponent) { + const m = _makeMountMixer(); + mountMixer = m.mountMixer; + } activateCb = () => { if ( @@ -375,6 +416,10 @@ export default e => { const sitAction = localPlayer.getAction('sit'); if (sitAction) { localPlayer.removeAction('sit'); + sitSpec = null; + for (const mixer of animationMixers) { + mixer.clear(); + } } } }; @@ -529,6 +574,7 @@ export default e => { const localPlayer = useLocalPlayer(); const rideBone = sitSpec.sitBone ? rideMesh.skeleton.bones.find(bone => bone.name === sitSpec.sitBone) : null; + const sitAction = { type: 'sit', time: 0, @@ -620,14 +666,56 @@ export default e => { const deltaSeconds = timeDiff / 1000; petMixer.update(deltaSeconds); } - } else { + } /*else { const deltaSeconds = timeDiff / 1000; for (const mixer of animationMixers) { mixer.update(deltaSeconds); } - } + }*/ }; _updatePet(); + + const _isMoving = (v) => { + const threshold = 1; + return Math.abs(v.x) > threshold || Math.abs(v.z) > threshold ? true : false; // Excluding velocity.y + } + + const _updateRide = () => { + if (!!app.getComponent('sit')) { + if (sitSpec) { + const localPlayer = useLocalPlayer(); + const sitAction = localPlayer.getAction('sit'); + if(sitAction) { + const velocity = localPlayer.characterPhysics.velocity.clone(); + const speed = getSpeed(); // 0.1, ~0.3, 2 Getting speed from game.js + const smooth = sitSpec.damping ? sitSpec.damping : 0.5; // smoothing animation end/start + + if(_isMoving(velocity)) { + + for (const action of mountActions) { + if(!action.isRunning()) { + action.play(); + } + if(action.weight < 1) { + action.weight += (1 - Math.pow(smooth, speed)) / 2; + } + } + } else { + for (const action of mountActions) { + if(action.weight > 0) { + action.weight *= Math.pow(smooth, speed); + } + } + } + } + } + } + const deltaSeconds = timeDiff / 1000; + for (const mixer of animationMixers) { + mixer.update(deltaSeconds); + } + }; + _updateRide(); const _updateLook = () => { const lookComponent = app.getComponent('look'); From c0ca646a23b54c31959c884999454ab108c52d93 Mon Sep 17 00:00:00 2001 From: Kevin Date: Thu, 25 Nov 2021 22:53:05 +0800 Subject: [PATCH 2/3] simplified code --- type_templates/glb.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/type_templates/glb.js b/type_templates/glb.js index 517dc36..2906b35 100644 --- a/type_templates/glb.js +++ b/type_templates/glb.js @@ -146,7 +146,7 @@ export default e => { if(sitComponent) { const disableLoop = sitComponent.disableLoop ? sitComponent.disableLoop : false; - const clamp = sitComponent.clampAnimation ? sitComponent.clampAnimation : false; + const clamp = sitComponent.clampAnimationWhenFinished ? sitComponent.clampAnimationWhenFinished : false; if(disableLoop) { action.loop = THREE.LoopOnce; // Only plays once @@ -680,30 +680,34 @@ export default e => { return Math.abs(v.x) > threshold || Math.abs(v.z) > threshold ? true : false; // Excluding velocity.y } + const _applyDamping = (dampingAmount, timeDiff) => { + return Math.pow(dampingAmount, timeDiff / 60); + } + const _updateRide = () => { if (!!app.getComponent('sit')) { if (sitSpec) { const localPlayer = useLocalPlayer(); const sitAction = localPlayer.getAction('sit'); if(sitAction) { - const velocity = localPlayer.characterPhysics.velocity.clone(); + const velocity = localPlayer.characterPhysics.velocity; const speed = getSpeed(); // 0.1, ~0.3, 2 Getting speed from game.js const smooth = sitSpec.damping ? sitSpec.damping : 0.5; // smoothing animation end/start + const factor = _applyDamping(smooth, timeDiff); - if(_isMoving(velocity)) { - + if(_isMoving(velocity)) { // If is moving, gradually add to weight, else gradually decrease weight for (const action of mountActions) { if(!action.isRunning()) { - action.play(); + action.play(); // If clampWhenFinished is true and is clamped, play action again } if(action.weight < 1) { - action.weight += (1 - Math.pow(smooth, speed)) / 2; + action.weight += speed * factor; } } } else { for (const action of mountActions) { if(action.weight > 0) { - action.weight *= Math.pow(smooth, speed); + action.weight -= speed * factor; } } } From 12310b2ba5286ea4bf43f79c4b47aed86573cbcf Mon Sep 17 00:00:00 2001 From: Kevin Date: Fri, 26 Nov 2021 19:38:15 +0800 Subject: [PATCH 3/3] autoplay defaults --- type_templates/glb.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/type_templates/glb.js b/type_templates/glb.js index 2906b35..8781d6a 100644 --- a/type_templates/glb.js +++ b/type_templates/glb.js @@ -151,13 +151,14 @@ export default e => { if(disableLoop) { action.loop = THREE.LoopOnce; // Only plays once } - if(clamp) { action.clampWhenFinished = true; } + mountActions.push(action); + } + else { + action.play(); // If not sitComponent, auto-play actions } - //action.play(); - mountActions.push(action); /* let lastTimestamp = Date.now(); const update = now => { @@ -602,6 +603,15 @@ export default e => { const _isFar = distance => (distance - minDistance) > 0.01; useFrame(({timestamp, timeDiff}) => { // components + + const _updateDefaults = () => { + const deltaSeconds = timeDiff / 1000; + for (const mixer of animationMixers) { + mixer.update(deltaSeconds); + } + }; + _updateDefaults(); + const _updatePet = () => { if (!!app.getComponent('pet')) { if (rootBone) { @@ -714,10 +724,6 @@ export default e => { } } } - const deltaSeconds = timeDiff / 1000; - for (const mixer of animationMixers) { - mixer.update(deltaSeconds); - } }; _updateRide();