Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Walk/run animation blending #1947

Merged
merged 10 commits into from
Dec 12, 2021
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 109 additions & 26 deletions avatars/avatars.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const localQuaternion2 = new THREE.Quaternion();
const localQuaternion3 = new THREE.Quaternion();
const localQuaternion4 = new THREE.Quaternion();
const localQuaternion5 = new THREE.Quaternion();
const localQuaternion6 = new THREE.Quaternion();
const localEuler = new THREE.Euler();
const localEuler2 = new THREE.Euler();
const localMatrix = new THREE.Matrix4();
Expand Down Expand Up @@ -624,6 +625,9 @@ const animationMappingConfig = [

class Avatar {
constructor(object, options = {}) {

this.speedValue = 0;

if (!object) {
object = {};
}
Expand Down Expand Up @@ -1602,13 +1606,27 @@ class Avatar {
);
return localEuler.y;
}
lerpFloat(value1, value2, amount) {
amount = amount < 0 ? 0 : amount;
amount = amount > 1 ? 1 : amount;
return value1 + (value2 - value1) * amount;
}
update(timeDiff) {
/* const wasDecapitated = this.decapitated;
if (this.springBoneManager && wasDecapitated) {
this.undecapitate();
} */
const {now} = this;
const timeDiffS = timeDiff / 1000;
const currentSpeed = localVector.set(this.velocity.x, 0, this.velocity.z).length();

this.speedValue = this.lerpFloat(this.speedValue,currentSpeed,(timeDiffS * 5.0));

//console.log(currentSpeed.toFixed(2) + " " + this.speedValue.toFixed(2));

//let factor = Math.min(1.2, Math.max(0,this.speedValue - 0.5)) * 1.42;

//console.log(factor.toFixed(2));

const _updatePosition = () => {
const currentPosition = this.inputs.hmd.position;
Expand All @@ -1632,7 +1650,6 @@ class Avatar {

const _applyAnimation = () => {
const runSpeed = 0.75;
const currentSpeed = localVector.set(this.velocity.x, 0, this.velocity.z).length();
const angle = this.getAngle();
const timeSeconds = now/1000;

Expand Down Expand Up @@ -1704,15 +1721,15 @@ class Avatar {
return animationsIdleArrays[key].animation;
}
}; */
const _get5wayBlend = (horizontalAnimationAngles, horizontalAnimationAnglesMirror, idleAnimation, mirrorFactor, angleFactor, speedFactor, k, lerpFn, target) => {
// normal horizontal walk/run blend
const _get7wayBlend = (horizontalWalkAnimationAngles, horizontalWalkAnimationAnglesMirror, horizontalRunAnimationAngles, horizontalRunAnimationAnglesMirror, idleAnimation, mirrorFactor, angleFactor, speedFactor, walkRunFactor, k, lerpFn, target) => {
// normal horizontal walk blend
{
const t1 = timeSeconds % horizontalAnimationAngles[0].animation.duration;
const src1 = horizontalAnimationAngles[0].animation.interpolants[k];
const t1 = timeSeconds % horizontalWalkAnimationAngles[0].animation.duration;
const src1 = horizontalWalkAnimationAngles[0].animation.interpolants[k];
const v1 = src1.evaluate(t1);

const t2 = timeSeconds % horizontalAnimationAngles[1].animation.duration;
const src2 = horizontalAnimationAngles[1].animation.interpolants[k];
const t2 = timeSeconds % horizontalWalkAnimationAngles[1].animation.duration;
const src2 = horizontalWalkAnimationAngles[1].animation.interpolants[k];
const v2 = src2.evaluate(t2);

lerpFn
Expand All @@ -1723,14 +1740,14 @@ class Avatar {
);
}

// mirror horizontal blend (backwards walk/run)
// mirror horizontal blend (backwards walk)
{
const t1 = timeSeconds % horizontalAnimationAnglesMirror[0].animation.duration;
const src1 = horizontalAnimationAnglesMirror[0].animation.interpolants[k];
const t1 = timeSeconds % horizontalWalkAnimationAnglesMirror[0].animation.duration;
const src1 = horizontalWalkAnimationAnglesMirror[0].animation.interpolants[k];
const v1 = src1.evaluate(t1);

const t2 = timeSeconds % horizontalAnimationAnglesMirror[1].animation.duration;
const src2 = horizontalAnimationAnglesMirror[1].animation.interpolants[k];
const t2 = timeSeconds % horizontalWalkAnimationAnglesMirror[1].animation.duration;
const src2 = horizontalWalkAnimationAnglesMirror[1].animation.interpolants[k];
const v2 = src2.evaluate(t2);

lerpFn
Expand All @@ -1744,12 +1761,65 @@ class Avatar {
// blend mirrors together to get a smooth walk
lerpFn
.call(
localQuaternion5.copy(localQuaternion3),
localQuaternion5.copy(localQuaternion3), // Result is in localQuaternion5
localQuaternion4,
mirrorFactor
);

// blend the smooth walk with idle
// Same for run
// normal horizontal run blend
{
const t1 = timeSeconds % horizontalRunAnimationAngles[0].animation.duration;
const src1 = horizontalRunAnimationAngles[0].animation.interpolants[k];
const v1 = src1.evaluate(t1);

const t2 = timeSeconds % horizontalRunAnimationAngles[1].animation.duration;
const src2 = horizontalRunAnimationAngles[1].animation.interpolants[k];
const v2 = src2.evaluate(t2);

lerpFn
.call(
localQuaternion3.fromArray(v2),
localQuaternion4.fromArray(v1),
angleFactor
);
}

// mirror horizontal blend (backwards run)
{
const t1 = timeSeconds % horizontalRunAnimationAnglesMirror[0].animation.duration;
const src1 = horizontalRunAnimationAnglesMirror[0].animation.interpolants[k];
const v1 = src1.evaluate(t1);

const t2 = timeSeconds % horizontalRunAnimationAnglesMirror[1].animation.duration;
const src2 = horizontalRunAnimationAnglesMirror[1].animation.interpolants[k];
const v2 = src2.evaluate(t2);

lerpFn
.call(
localQuaternion4.fromArray(v2),
localQuaternion6.fromArray(v1),
angleFactor
);
}

// blend mirrors together to get a smooth run
lerpFn
.call(
localQuaternion6.copy(localQuaternion3), // Result is in localQuaternion6
localQuaternion4,
mirrorFactor
);

// Blend walk/run
lerpFn
.call(
localQuaternion4.copy(localQuaternion5), // Result is in localQuaternion4
localQuaternion6,
walkRunFactor
);

// blend the smooth walk/run with idle
{
const t3 = timeSeconds % idleAnimation.duration;
const src3 = idleAnimation.interpolants[k];
Expand All @@ -1758,7 +1828,7 @@ class Avatar {
lerpFn
.call(
target.fromArray(v3),
localQuaternion5,
localQuaternion4,
speedFactor
);
}
Expand All @@ -1769,9 +1839,16 @@ class Avatar {
false,
this.velocity,
);
const keyAnimationAngles = _getClosest2AnimationAngles(key);
const keyAnimationAnglesMirror = _getMirrorAnimationAngles(keyAnimationAngles, key);
const idleAnimation = _getIdleAnimation(key);
const keyWalkAnimationAngles = _getClosest2AnimationAngles('walk');
const keyWalkAnimationAnglesMirror = _getMirrorAnimationAngles(keyWalkAnimationAngles, 'walk');

const keyRunAnimationAngles = _getClosest2AnimationAngles('run');
const keyRunAnimationAnglesMirror = _getMirrorAnimationAngles(keyRunAnimationAngles, 'run');

const idleAnimation = _getIdleAnimation('walk');





const soundManager = metaversefile.useSoundManager();
Expand Down Expand Up @@ -1821,16 +1898,16 @@ class Avatar {
true,
this.velocity,
);
const keyAnimationAnglesOther = _getClosest2AnimationAngles(keyOther);
const keyAnimationAnglesOtherMirror = _getMirrorAnimationAngles(keyAnimationAnglesOther, keyOther);
const idleAnimationOther = _getIdleAnimation(keyOther);
const keyAnimationAnglesOther = _getClosest2AnimationAngles('crouch');
const keyAnimationAnglesOtherMirror = _getMirrorAnimationAngles(keyAnimationAnglesOther, 'crouch');
const idleAnimationOther = _getIdleAnimation('crouch');

const angleToClosestAnimation = Math.abs(angleDifference(angle, keyAnimationAnglesMirror[0].angle));
const angleBetweenAnimations = Math.abs(angleDifference(keyAnimationAnglesMirror[0].angle, keyAnimationAnglesMirror[1].angle));
const angleToClosestAnimation = Math.abs(angleDifference(angle, keyWalkAnimationAnglesMirror[0].angle));
const angleBetweenAnimations = Math.abs(angleDifference(keyWalkAnimationAnglesMirror[0].angle, keyWalkAnimationAnglesMirror[1].angle));
const angleFactor = (angleBetweenAnimations - angleToClosestAnimation) / angleBetweenAnimations;
const speedFactor = Math.min(Math.pow(currentSpeed, 0.5) * 2, 1);
const crouchFactor = Math.min(Math.max(1 - (this.crouchTime / crouchMaxTime), 0), 1);
const isBackward = _getAngleToBackwardAnimation(keyAnimationAnglesMirror) < Math.PI*0.4;
const isBackward = _getAngleToBackwardAnimation(keyWalkAnimationAnglesMirror) < Math.PI*0.4;
if (isBackward !== this.lastIsBackward) {
this.backwardAnimationSpec = {
startFactor: this.lastBackwardFactor,
Expand Down Expand Up @@ -1859,15 +1936,21 @@ class Avatar {
this.lastBackwardFactor = mirrorFactor;

const _getHorizontalBlend = (k, lerpFn, target) => {
_get5wayBlend(keyAnimationAngles, keyAnimationAnglesMirror, idleAnimation, mirrorFactor, angleFactor, speedFactor, k, lerpFn, localQuaternion);
_get5wayBlend(keyAnimationAnglesOther, keyAnimationAnglesOtherMirror, idleAnimationOther, mirrorFactor, angleFactor, speedFactor, k, lerpFn, localQuaternion2);

const walkRunFactor = Math.min(1.2, Math.max(0,this.speedValue - 0.5)) * 1.42; // range [0.5,1.2]

_get7wayBlend(keyWalkAnimationAngles, keyWalkAnimationAnglesMirror,keyRunAnimationAngles, keyRunAnimationAnglesMirror, idleAnimation, mirrorFactor, angleFactor, speedFactor, walkRunFactor, k, lerpFn, localQuaternion);
_get7wayBlend(keyAnimationAnglesOther, keyAnimationAnglesOtherMirror,keyAnimationAnglesOther, keyAnimationAnglesOtherMirror, idleAnimationOther, mirrorFactor, angleFactor, speedFactor, walkRunFactor, k, lerpFn, localQuaternion2);

//_get5wayBlend(keyAnimationAnglesOther, keyAnimationAnglesOtherMirror, idleAnimationOther, mirrorFactor, angleFactor, speedFactor, k, lerpFn, localQuaternion2);

lerpFn
.call(
target.copy(localQuaternion),
localQuaternion2,
crouchFactor
);

};
const _getApplyFn = () => {
if (this.jumpState) {
Expand Down