code review changes for walk.js 1.25

This commit is contained in:
DaveDubUK 2015-06-24 19:41:54 +07:00
parent 73e59fe07f
commit 0e71583048
6 changed files with 86 additions and 97 deletions

View file

@ -37,11 +37,9 @@
} }
}); });
} }
elArmsFree.addEventListener("change", emitUpdate); elArmsFree.addEventListener("change", emitUpdate);
elFootstepSounds.addEventListener("change", emitUpdate); elFootstepSounds.addEventListener("change", emitUpdate);
elBlenderPreRotations.addEventListener("change", emitUpdate); elBlenderPreRotations.addEventListener("change", emitUpdate);
elPower.addEventListener("click", function() { elPower.addEventListener("click", function() {
EventBridge.emitWebEvent(JSON.stringify({ EventBridge.emitWebEvent(JSON.stringify({
type: "powerToggle" type: "powerToggle"

View file

@ -45,4 +45,4 @@ input[type=button] {
border: 0; border: 0;
color: #fff; color: #fff;
font-weight: bold; font-weight: bold;
} }

View file

@ -2,10 +2,10 @@
// walkApi.js // walkApi.js
// version 1.3 // version 1.3
// //
// Created by David Wooldridge, Autumn 2014 // Created by David Wooldridge, June 2015
// Copyright © 2015 High Fidelity, Inc. // Copyright © 2014 - 2015 High Fidelity, Inc.
// //
// Exposes API for use by walk.js version 1.2+. // Exposes API for use by walk.js version 1.2+.
// //
// Editing tools for animation data files available here: https://github.com/DaveDubUK/walkTools // Editing tools for animation data files available here: https://github.com/DaveDubUK/walkTools
// //
@ -32,7 +32,7 @@ const SAWTOOTH = 1;
const TRIANGLE = 2; const TRIANGLE = 2;
const SQUARE = 4; const SQUARE = 4;
// constants used by walk.js and walkApi.js // constants used by walk.js and walkApi.js
const MAX_WALK_SPEED = 2.9; // peak, by observation const MAX_WALK_SPEED = 2.9; // peak, by observation
const MAX_FT_WHEEL_INCREMENT = 25; // avoid fast walk when landing const MAX_FT_WHEEL_INCREMENT = 25; // avoid fast walk when landing
const TOP_SPEED = 300; const TOP_SPEED = 300;
@ -62,7 +62,7 @@ Avatar = function() {
const HYDRA_TRIGGERS = 2; const HYDRA_TRIGGERS = 2;
const HYDRA_CONTROLLERS_PER_TRIGGER = 2; const HYDRA_CONTROLLERS_PER_TRIGGER = 2;
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers; var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
if (numberOfButtons == HYDRA_BUTTONS && if (numberOfButtons == HYDRA_BUTTONS &&
numberOfTriggers == HYDRA_TRIGGERS && numberOfTriggers == HYDRA_TRIGGERS &&
controllersPerTrigger == HYDRA_CONTROLLERS_PER_TRIGGER) { controllersPerTrigger == HYDRA_CONTROLLERS_PER_TRIGGER) {
print('walk.js info: Razer Hydra detected. Setting arms free (not controlled by script)'); print('walk.js info: Razer Hydra detected. Setting arms free (not controlled by script)');
@ -75,7 +75,7 @@ Avatar = function() {
// settings // settings
this.headFree = true; this.headFree = true;
this.armsFree = this.hydraCheck(); // automatically sets true to enable Hydra support - temporary fix this.armsFree = this.hydraCheck(); // automatically sets true to enable Hydra support - temporary fix
this.makesFootStepSounds = false; this.makesFootStepSounds = false;
this.isBlenderExport = false; // temporary fix this.isBlenderExport = false; // temporary fix
this.animationSet = undefined; // currently just one animation set this.animationSet = undefined; // currently just one animation set
this.setAnimationSet = function(animationSet) { this.setAnimationSet = function(animationSet) {
@ -121,8 +121,8 @@ Avatar = function() {
} }
} }
this.calibration.hipsToFeet = MyAvatar.getJointPosition("Hips").y - MyAvatar.getJointPosition("RightToeBase").y; this.calibration.hipsToFeet = MyAvatar.getJointPosition("Hips").y - MyAvatar.getJointPosition("RightToeBase").y;
// maybe measuring before Blender pre-rotations have been applied? // maybe measuring before Blender pre-rotations have been applied?
if (this.calibration.hipsToFeet < 0 && this.isBlenderExport) { if (this.calibration.hipsToFeet < 0 && this.isBlenderExport) {
this.calibration.hipsToFeet *= -1; this.calibration.hipsToFeet *= -1;
} }
@ -165,7 +165,7 @@ Avatar = function() {
// footsteps // footsteps
this.nextStep = RIGHT; // the first step is right, because the waveforms say so this.nextStep = RIGHT; // the first step is right, because the waveforms say so
this.leftAudioInjector = null; this.leftAudioInjector = null;
this.rightAudioInjector = null; this.rightAudioInjector = null;
this.makeFootStepSound = function() { this.makeFootStepSound = function() {
@ -229,7 +229,7 @@ Motion = function() {
// orientation, locomotion and timing // orientation, locomotion and timing
this.velocity = {x:0, y:0, z:0}; this.velocity = {x:0, y:0, z:0};
this.acceleration = {x:0, y:0, z:0}; this.acceleration = {x:0, y:0, z:0};
this.yaw = Quat.safeEulerAngles(MyAvatar.orientation).y; // MyAvatar.orientation.y; // this.yaw = Quat.safeEulerAngles(MyAvatar.orientation).y;
this.yawDelta = 0; this.yawDelta = 0;
this.yawDeltaAcceleration = 0; this.yawDeltaAcceleration = 0;
this.direction = FORWARDS; this.direction = FORWARDS;
@ -241,12 +241,12 @@ Motion = function() {
this.lastYaw = Quat.safeEulerAngles(MyAvatar.orientation).y; this.lastYaw = Quat.safeEulerAngles(MyAvatar.orientation).y;
this.lastYawDelta = 0; this.lastYawDelta = 0;
this.lastYawDeltaAcceleration = 0; this.lastYawDeltaAcceleration = 0;
// Quat.safeEulerAngles(MyAvatar.orientation).y tends to repeat values between frames, so values are filtered // Quat.safeEulerAngles(MyAvatar.orientation).y tends to repeat values between frames, so values are filtered
var YAW_SMOOTHING = 22; var YAW_SMOOTHING = 22;
this.yawFilter = filter.createAveragingFilter(YAW_SMOOTHING); //createButterworthFilter(); // this.yawFilter = filter.createAveragingFilter(YAW_SMOOTHING);
this.deltaTimeFilter = filter.createAveragingFilter(YAW_SMOOTHING); //createButterworthFilter(); // this.deltaTimeFilter = filter.createAveragingFilter(YAW_SMOOTHING);
this.yawDeltaAccelerationFilter = filter.createAveragingFilter(YAW_SMOOTHING); //createButterworthFilter(); // this.yawDeltaAccelerationFilter = filter.createAveragingFilter(YAW_SMOOTHING);
// assess locomotion state // assess locomotion state
this.assess = function(deltaTime) { this.assess = function(deltaTime) {
@ -350,16 +350,16 @@ Motion = function() {
var surfaceMotion = isOnSurface && this.isMoving; var surfaceMotion = isOnSurface && this.isMoving;
var acceleratingAndAirborne = this.isAccelerating && !isOnSurface; var acceleratingAndAirborne = this.isAccelerating && !isOnSurface;
var goingTooFastToWalk = !this.isDecelerating && this.isFlyingSpeed; var goingTooFastToWalk = !this.isDecelerating && this.isFlyingSpeed;
var movingDirectlyUpOrDown = (this.direction === UP || this.direction === DOWN) // && lateralVelocity < MOVE_THRESHOLD; var movingDirectlyUpOrDown = (this.direction === UP || this.direction === DOWN)
var maybeBouncing = Math.abs(this.acceleration.y > BOUNCE_ACCELERATION_THRESHOLD) ? true : false; var maybeBouncing = Math.abs(this.acceleration.y > BOUNCE_ACCELERATION_THRESHOLD) ? true : false;
// we now have enough information to set the appropriate locomotion mode // we now have enough information to set the appropriate locomotion mode
switch (this.state) { switch (this.state) {
case STATIC: case STATIC:
var staticToAirMotion = this.isMoving && (acceleratingAndAirborne || goingTooFastToWalk || var staticToAirMotion = this.isMoving && (acceleratingAndAirborne || goingTooFastToWalk ||
(movingDirectlyUpOrDown && !isOnSurface)); (movingDirectlyUpOrDown && !isOnSurface));
var staticToSurfaceMotion = surfaceMotion && !motion.isComingToHalt && !movingDirectlyUpOrDown && var staticToSurfaceMotion = surfaceMotion && !motion.isComingToHalt && !movingDirectlyUpOrDown &&
!this.isDecelerating && lateralVelocity > MOVE_THRESHOLD; !this.isDecelerating && lateralVelocity > MOVE_THRESHOLD;
if (staticToAirMotion) { if (staticToAirMotion) {
this.nextState = AIR_MOTION; this.nextState = AIR_MOTION;
} else if (staticToSurfaceMotion) { } else if (staticToSurfaceMotion) {
@ -370,8 +370,8 @@ Motion = function() {
break; break;
case SURFACE_MOTION: case SURFACE_MOTION:
var surfaceMotionToStatic = !this.isMoving || var surfaceMotionToStatic = !this.isMoving ||
(this.isDecelerating && motion.lastDirection !== DOWN && surfaceMotion && (this.isDecelerating && motion.lastDirection !== DOWN && surfaceMotion &&
!maybeBouncing && Vec3.length(this.velocity) < MAX_WALK_SPEED); !maybeBouncing && Vec3.length(this.velocity) < MAX_WALK_SPEED);
var surfaceMotionToAirMotion = (acceleratingAndAirborne || goingTooFastToWalk || movingDirectlyUpOrDown) && var surfaceMotionToAirMotion = (acceleratingAndAirborne || goingTooFastToWalk || movingDirectlyUpOrDown) &&
(!surfaceMotion && isTakingOff) || (!surfaceMotion && isTakingOff) ||
@ -391,8 +391,7 @@ Motion = function() {
case AIR_MOTION: case AIR_MOTION:
var airMotionToSurfaceMotion = (surfaceMotion || aboutToLand) && !movingDirectlyUpOrDown; var airMotionToSurfaceMotion = (surfaceMotion || aboutToLand) && !movingDirectlyUpOrDown;
var airMotionToStatic = !this.isMoving && this.direction === this.lastDirection; //|| var airMotionToStatic = !this.isMoving && this.direction === this.lastDirection;
//this.isDeceleratingFast || isOnSurface;
if (airMotionToSurfaceMotion){ if (airMotionToSurfaceMotion){
this.nextState = SURFACE_MOTION; this.nextState = SURFACE_MOTION;
} else if (airMotionToStatic) { } else if (airMotionToStatic) {
@ -484,7 +483,7 @@ animationOperations = (function() {
} else { } else {
jointTranslations.z = joint.thrust * Math.sin jointTranslations.z = joint.thrust * Math.sin
(filter.degToRad(modifiers.thrustFrequencyMultiplier * ft + joint.thrustPhase)) + joint.thrustOffset; (filter.degToRad(modifiers.thrustFrequencyMultiplier * ft + joint.thrustPhase)) + joint.thrustOffset;
} }
return jointTranslations; return jointTranslations;
}, },
@ -780,7 +779,7 @@ Transition = function(nextAnimation, lastAnimation, lastTransition, playTransiti
if (this.lastTransition !== nullTransition) { if (this.lastTransition !== nullTransition) {
this.lastTransition.incrementRecursion(); this.lastTransition.incrementRecursion();
} }
// end of transition initialisation. begin Transition public methods // end of transition initialisation. begin Transition public methods
// keep up the pace for the frequency time wheel for the last animation // keep up the pace for the frequency time wheel for the last animation
@ -788,7 +787,7 @@ Transition = function(nextAnimation, lastAnimation, lastTransition, playTransiti
var wheelAdvance = undefined; var wheelAdvance = undefined;
if (this.lastAnimation === avatar.selectedWalkBlend && if (this.lastAnimation === avatar.selectedWalkBlend &&
this.nextAnimation === avatar.selectedIdle) { this.nextAnimation === avatar.selectedIdle) {
if (this.degreesRemaining <= 0) { if (this.degreesRemaining <= 0) {
// stop continued motion // stop continued motion
wheelAdvance = 0; wheelAdvance = 0;
@ -855,7 +854,6 @@ Transition = function(nextAnimation, lastAnimation, lastTransition, playTransiti
// update transition progress // update transition progress
this.filteredProgress = filter.bezier(this.progress, this.parameters.easingLower, this.parameters.easingUpper); this.filteredProgress = filter.bezier(this.progress, this.parameters.easingLower, this.parameters.easingUpper);
//if (this.progress >= 1) walkTools.toLog(this.lastAnimation.name + ' to '+ this.nextAnimation.name + ': done');
return this.progress >= 1 ? TRANSITION_COMPLETE : false; return this.progress >= 1 ? TRANSITION_COMPLETE : false;
}; };

View file

@ -3,7 +3,7 @@
// version 1.1 // version 1.1
// //
// Created by David Wooldridge, Autumn 2014 // Created by David Wooldridge, Autumn 2014
// Copyright © 2015 High Fidelity, Inc. // Copyright © 2014 - 2015 High Fidelity, Inc.
// //
// Provides a variety of filters for use by the walk.js script v1.2+ // Provides a variety of filters for use by the walk.js script v1.2+
// //
@ -131,9 +131,9 @@ HarmonicsFilter = function(magnitudes, phaseAngles) {
// the main filter object literal // the main filter object literal
filter = (function() { filter = (function() {
const HALF_CYCLE = 180; const HALF_CYCLE = 180;
// Bezier private variables // Bezier private variables
var _C1 = {x:0, y:0}; var _C1 = {x:0, y:0};
var _C4 = {x:1, y:1}; var _C4 = {x:1, y:1};
@ -158,7 +158,7 @@ filter = (function() {
}, },
// these filters need instantiating, as they hold arrays of previous values // these filters need instantiating, as they hold arrays of previous values
// simple averaging (LP) filter for damping / smoothing // simple averaging (LP) filter for damping / smoothing
createAveragingFilter: function(length) { createAveragingFilter: function(length) {
var newAveragingFilter = new AveragingFilter(length); var newAveragingFilter = new AveragingFilter(length);
@ -184,7 +184,7 @@ filter = (function() {
}, },
// the following filters do not need separate instances, as they hold no previous values // the following filters do not need separate instances, as they hold no previous values
// Bezier response curve shaping for more natural transitions // Bezier response curve shaping for more natural transitions
bezier: function(input, C2, C3) { bezier: function(input, C2, C3) {
// based on script by Dan Pupius (www.pupius.net) http://13thparallel.com/archive/bezier-curves/ // based on script by Dan Pupius (www.pupius.net) http://13thparallel.com/archive/bezier-curves/

View file

@ -2,8 +2,8 @@
// walkSettings.js // walkSettings.js
// version 0.1 // version 0.1
// //
// Created by David Wooldridge, Summer 2015 // Created by David Wooldridge, June 2015
// Copyright © 2015 High Fidelity, Inc. // Copyright © 2014 - 2015 High Fidelity, Inc.
// //
// Presents settings for walk.js // Presents settings for walk.js
// //
@ -20,14 +20,14 @@ WalkSettings = function() {
const MARGIN_TOP = 145; const MARGIN_TOP = 145;
const ICON_SIZE = 50; const ICON_SIZE = 50;
const ICON_ALPHA = 0.9; const ICON_ALPHA = 0.9;
var minimisedTab = Overlays.addOverlay("image", { var minimisedTab = Overlays.addOverlay("image", {
x: _innerWidth - MARGIN_RIGHT, y: Window.innerHeight - MARGIN_TOP, x: _innerWidth - MARGIN_RIGHT, y: Window.innerHeight - MARGIN_TOP,
width: ICON_SIZE, height: ICON_SIZE, width: ICON_SIZE, height: ICON_SIZE,
imageURL: pathToAssets + 'overlay-images/ddpa-minimised-ddpa-tab.png', imageURL: pathToAssets + 'overlay-images/ddpa-minimised-ddpa-tab.png',
visible: true, alpha: ICON_ALPHA visible: true, alpha: ICON_ALPHA
}); });
function mousePressEvent(event) { function mousePressEvent(event) {
if (Overlays.getOverlayAtPoint(event) === minimisedTab) { if (Overlays.getOverlayAtPoint(event) === minimisedTab) {
_visible = !_visible; _visible = !_visible;
@ -35,43 +35,36 @@ WalkSettings = function() {
} }
} }
Controller.mousePressEvent.connect(mousePressEvent); Controller.mousePressEvent.connect(mousePressEvent);
Script.update.connect(function(deltaTime) { Script.update.connect(function(deltaTime) {
if (window.innerWidth !== _innerWidth) { if (window.innerWidth !== _innerWidth) {
_innerWidth = window.innerWidth; _innerWidth = window.innerWidth;
Overlays.EditOverlay(minimisedTab, {x: _innerWidth - MARGIN_RIGHT}); Overlays.EditOverlay(minimisedTab, {x: _innerWidth - MARGIN_RIGHT});
} }
}); });
function cleanup() { function cleanup() {
Overlays.deleteOverlay(minimisedTab); Overlays.deleteOverlay(minimisedTab);
} }
Script.scriptEnding.connect(cleanup); Script.scriptEnding.connect(cleanup);
var _control = false;
var _shift = false; var _shift = false;
function keyPressEvent(event) { function keyPressEvent(event) {
if (event.text === "CONTROL") {
_control = true;
}
if (event.text === "SHIFT") { if (event.text === "SHIFT") {
_shift = true; _shift = true;
} }
if (_shift && (event.text === 'o' || event.text === 'O')) { if (_shift && (event.text === 'o' || event.text === 'O')) {
_visible = !_visible; _visible = !_visible;
_webView.setVisible(_visible); _webView.setVisible(_visible);
} }
} }
function keyReleaseEvent(event) { function keyReleaseEvent(event) {
if (event.text === "CONTROL") {
_control = false;
}
if (event.text === "SHIFT") { if (event.text === "SHIFT") {
_shift = false; _shift = false;
} }
} }
Controller.keyPressEvent.connect(keyPressEvent); Controller.keyPressEvent.connect(keyPressEvent);
Controller.keyReleaseEvent.connect(keyReleaseEvent); Controller.keyReleaseEvent.connect(keyReleaseEvent);
// web window // web window
var _url = Script.resolvePath('html/walkSettings.html'); var _url = Script.resolvePath('html/walkSettings.html');
@ -84,7 +77,7 @@ WalkSettings = function() {
data = JSON.parse(data); data = JSON.parse(data);
if (data.type == "init") { if (data.type == "init") {
// send the current settings to the dialog // send the current settings to the window
_webView.eventBridge.emitScriptEvent(JSON.stringify({ _webView.eventBridge.emitScriptEvent(JSON.stringify({
type: "update", type: "update",
armsFree: avatar.armsFree, armsFree: avatar.armsFree,
@ -94,7 +87,7 @@ WalkSettings = function() {
} else if (data.type == "powerToggle") { } else if (data.type == "powerToggle") {
motion.isLive = !motion.isLive; motion.isLive = !motion.isLive;
} else if (data.type == "update") { } else if (data.type == "update") {
// receive settings from the dialog // receive settings from the window
avatar.armsFree = data.armsFree; avatar.armsFree = data.armsFree;
avatar.makesFootStepSounds = data.footstepSounds; avatar.makesFootStepSounds = data.footstepSounds;
avatar.isBlenderExport = data.blenderPreRotations; avatar.isBlenderExport = data.blenderPreRotations;

View file

@ -2,11 +2,11 @@
// walk.js // walk.js
// version 1.25 // version 1.25
// //
// Created by David Wooldridge, May 2015 // Created by David Wooldridge, June 2015
// Copyright © 2015 High Fidelity, Inc. // Copyright © 2014 - 2015 High Fidelity, Inc.
// //
// Animates an avatar using procedural animation techniques. // Animates an avatar using procedural animation techniques.
// //
// Editing tools for animation data files available here: https://github.com/DaveDubUK/walkTools // Editing tools for animation data files available here: https://github.com/DaveDubUK/walkTools
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
@ -49,7 +49,7 @@ Script.include([
pathToAssets + "walkAssets.js" pathToAssets + "walkAssets.js"
]); ]);
// construct Avatar and Motion // construct Avatar and Motion
var avatar = new Avatar(); var avatar = new Avatar();
var motion = new Motion(); var motion = new Motion();
@ -73,7 +73,7 @@ var flyBackwardFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING);
Script.update.connect(function(deltaTime) { Script.update.connect(function(deltaTime) {
if (motion.isLive) { if (motion.isLive) {
// assess current locomotion state // assess current locomotion state
motion.assess(deltaTime); motion.assess(deltaTime);
@ -90,7 +90,7 @@ Script.update.connect(function(deltaTime) {
renderMotion(); renderMotion();
// record this frame's parameters // record this frame's parameters
motion.saveHistory(); motion.saveHistory();
} }
}); });
@ -98,29 +98,29 @@ Script.update.connect(function(deltaTime) {
function setTransition(nextAnimation, playTransitionReachPoses) { function setTransition(nextAnimation, playTransitionReachPoses) {
var lastTransition = motion.currentTransition; var lastTransition = motion.currentTransition;
var lastAnimation = avatar.currentAnimation; var lastAnimation = avatar.currentAnimation;
// if already transitioning from a blended walk need to maintain the previous walk's direction // if already transitioning from a blended walk need to maintain the previous walk's direction
if (lastAnimation.lastDirection) { if (lastAnimation.lastDirection) {
switch(lastAnimation.lastDirection) { switch(lastAnimation.lastDirection) {
case FORWARDS: case FORWARDS:
lastAnimation = avatar.selectedWalk; lastAnimation = avatar.selectedWalk;
break; break;
case BACKWARDS: case BACKWARDS:
lastAnimation = avatar.selectedWalkBackwards; lastAnimation = avatar.selectedWalkBackwards;
break; break;
case LEFT: case LEFT:
lastAnimation = avatar.selectedSideStepLeft; lastAnimation = avatar.selectedSideStepLeft;
break; break;
case RIGHT: case RIGHT:
lastAnimation = avatar.selectedSideStepRight; lastAnimation = avatar.selectedSideStepRight;
break; break;
} }
} }
motion.currentTransition = new Transition(nextAnimation, lastAnimation, lastTransition, playTransitionReachPoses); motion.currentTransition = new Transition(nextAnimation, lastAnimation, lastTransition, playTransitionReachPoses);
avatar.currentAnimation = nextAnimation; avatar.currentAnimation = nextAnimation;
@ -137,10 +137,10 @@ function selectAnimation() {
// select appropriate animation. create transitions where appropriate // select appropriate animation. create transitions where appropriate
switch (motion.nextState) { switch (motion.nextState) {
case STATIC: { case STATIC: {
if (avatar.distanceFromSurface < ON_SURFACE_THRESHOLD && if (avatar.distanceFromSurface < ON_SURFACE_THRESHOLD &&
avatar.currentAnimation !== avatar.selectedIdle) { avatar.currentAnimation !== avatar.selectedIdle) {
setTransition(avatar.selectedIdle, playTransitionReachPoses); setTransition(avatar.selectedIdle, playTransitionReachPoses);
} else if (!(avatar.distanceFromSurface < ON_SURFACE_THRESHOLD) && } else if (!(avatar.distanceFromSurface < ON_SURFACE_THRESHOLD) &&
avatar.currentAnimation !== avatar.selectedHover) { avatar.currentAnimation !== avatar.selectedHover) {
setTransition(avatar.selectedHover, playTransitionReachPoses); setTransition(avatar.selectedHover, playTransitionReachPoses);
} }
@ -151,13 +151,13 @@ function selectAnimation() {
case SURFACE_MOTION: { case SURFACE_MOTION: {
// walk transition reach poses are currently only specified for starting to walk forwards // walk transition reach poses are currently only specified for starting to walk forwards
playTransitionReachPoses = (motion.direction === FORWARDS); playTransitionReachPoses = (motion.direction === FORWARDS);
var isAlreadyWalking = (avatar.currentAnimation === avatar.selectedWalkBlend); var isAlreadyWalking = (avatar.currentAnimation === avatar.selectedWalkBlend);
switch (motion.direction) { switch (motion.direction) {
case FORWARDS: case FORWARDS:
if (avatar.selectedWalkBlend.lastDirection !== FORWARDS) { if (avatar.selectedWalkBlend.lastDirection !== FORWARDS) {
animationOperations.deepCopy(avatar.selectedWalk, avatar.selectedWalkBlend); animationOperations.deepCopy(avatar.selectedWalk, avatar.selectedWalkBlend);
avatar.calibration.strideLength = avatar.selectedWalk.calibration.strideLength; avatar.calibration.strideLength = avatar.selectedWalk.calibration.strideLength;
} }
avatar.selectedWalkBlend.lastDirection = FORWARDS; avatar.selectedWalkBlend.lastDirection = FORWARDS;
@ -165,7 +165,7 @@ function selectAnimation() {
case BACKWARDS: case BACKWARDS:
if (avatar.selectedWalkBlend.lastDirection !== BACKWARDS) { if (avatar.selectedWalkBlend.lastDirection !== BACKWARDS) {
animationOperations.deepCopy(avatar.selectedWalkBackwards, avatar.selectedWalkBlend); animationOperations.deepCopy(avatar.selectedWalkBackwards, avatar.selectedWalkBlend);
avatar.calibration.strideLength = avatar.selectedWalkBackwards.calibration.strideLength; avatar.calibration.strideLength = avatar.selectedWalkBackwards.calibration.strideLength;
} }
avatar.selectedWalkBlend.lastDirection = BACKWARDS; avatar.selectedWalkBlend.lastDirection = BACKWARDS;
@ -182,7 +182,7 @@ function selectAnimation() {
avatar.selectedWalkBlend.lastDirection = RIGHT; avatar.selectedWalkBlend.lastDirection = RIGHT;
avatar.calibration.strideLength = avatar.selectedSideStepRight.calibration.strideLength; avatar.calibration.strideLength = avatar.selectedSideStepRight.calibration.strideLength;
break; break;
default: default:
// condition occurs when the avi goes through the floor due to collision hull errors // condition occurs when the avi goes through the floor due to collision hull errors
animationOperations.deepCopy(avatar.selectedWalk, avatar.selectedWalkBlend); animationOperations.deepCopy(avatar.selectedWalk, avatar.selectedWalkBlend);
@ -190,7 +190,7 @@ function selectAnimation() {
avatar.calibration.strideLength = avatar.selectedWalk.calibration.strideLength; avatar.calibration.strideLength = avatar.selectedWalk.calibration.strideLength;
break; break;
} }
if (!isAlreadyWalking && !motion.isComingToHalt) { if (!isAlreadyWalking && !motion.isComingToHalt) {
setTransition(avatar.selectedWalkBlend, playTransitionReachPoses); setTransition(avatar.selectedWalkBlend, playTransitionReachPoses);
} }
@ -206,18 +206,18 @@ function selectAnimation() {
var velocityMagnitude = Vec3.length(motion.velocity); var velocityMagnitude = Vec3.length(motion.velocity);
var verticalProportion = motion.velocity.y / velocityMagnitude; var verticalProportion = motion.velocity.y / velocityMagnitude;
var thrustProportion = motion.velocity.z / velocityMagnitude / 2; var thrustProportion = motion.velocity.z / velocityMagnitude / 2;
// directional components // directional components
var upComponent = motion.velocity.y > 0 ? verticalProportion : 0; var upComponent = motion.velocity.y > 0 ? verticalProportion : 0;
var downComponent = motion.velocity.y < 0 ? -verticalProportion : 0; var downComponent = motion.velocity.y < 0 ? -verticalProportion : 0;
var forwardComponent = motion.velocity.z < 0 ? -thrustProportion : 0; var forwardComponent = motion.velocity.z < 0 ? -thrustProportion : 0;
var backwardComponent = motion.velocity.z > 0 ? thrustProportion : 0; var backwardComponent = motion.velocity.z > 0 ? thrustProportion : 0;
// smooth / damp directional components to add visual 'weight' // smooth / damp directional components to add visual 'weight'
upComponent = flyUpFilter.process(upComponent); upComponent = flyUpFilter.process(upComponent);
downComponent = flyDownFilter.process(downComponent); downComponent = flyDownFilter.process(downComponent);
forwardComponent = flyForwardFilter.process(forwardComponent); forwardComponent = flyForwardFilter.process(forwardComponent);
backwardComponent = flyBackwardFilter.process(backwardComponent); backwardComponent = flyBackwardFilter.process(backwardComponent);
// normalise directional components // normalise directional components
var normaliser = upComponent + downComponent + forwardComponent + backwardComponent; var normaliser = upComponent + downComponent + forwardComponent + backwardComponent;
@ -225,7 +225,7 @@ function selectAnimation() {
downComponent = downComponent / normaliser; downComponent = downComponent / normaliser;
forwardComponent = forwardComponent / normaliser; forwardComponent = forwardComponent / normaliser;
backwardComponent = backwardComponent / normaliser; backwardComponent = backwardComponent / normaliser;
// blend animations proportionally // blend animations proportionally
if (upComponent > 0) { if (upComponent > 0) {
animationOperations.blendAnimation(avatar.selectedFlyUp, animationOperations.blendAnimation(avatar.selectedFlyUp,
@ -274,7 +274,7 @@ function determineStride() {
wheelAdvance = filter.radToDeg(motion.deltaTime * ftWheelAngularVelocity); wheelAdvance = filter.radToDeg(motion.deltaTime * ftWheelAngularVelocity);
} else { } else {
// turn the frequency time wheel by the amount specified for this animation // turn the frequency time wheel by the amount specified for this animation
wheelAdvance = filter.radToDeg(avatar.currentAnimation.calibration.frequency * motion.deltaTime); wheelAdvance = filter.radToDeg(avatar.currentAnimation.calibration.frequency * motion.deltaTime);
} }
if (motion.currentTransition !== nullTransition) { if (motion.currentTransition !== nullTransition) {
@ -291,20 +291,20 @@ function determineStride() {
} }
motion.currentTransition.advancePreviousFrequencyTimeWheel(motion.deltaTime); motion.currentTransition.advancePreviousFrequencyTimeWheel(motion.deltaTime);
} }
// avoid unnaturally fast walking when landing at speed - simulates skimming / skidding // avoid unnaturally fast walking when landing at speed - simulates skimming / skidding
if (Math.abs(wheelAdvance) > MAX_FT_WHEEL_INCREMENT) { if (Math.abs(wheelAdvance) > MAX_FT_WHEEL_INCREMENT) {
wheelAdvance = 0; wheelAdvance = 0;
} }
// advance the walk wheel the appropriate amount // advance the walk wheel the appropriate amount
motion.advanceFrequencyTimeWheel(wheelAdvance); motion.advanceFrequencyTimeWheel(wheelAdvance);
// walking? then see if it's a good time to measure the stride length (needs to be at least 97% of max walking speed) // walking? then see if it's a good time to measure the stride length (needs to be at least 97% of max walking speed)
const ALMOST_ONE = 0.97; const ALMOST_ONE = 0.97;
if (avatar.currentAnimation === avatar.selectedWalkBlend && if (avatar.currentAnimation === avatar.selectedWalkBlend &&
(Vec3.length(motion.velocity) / MAX_WALK_SPEED > ALMOST_ONE)) { (Vec3.length(motion.velocity) / MAX_WALK_SPEED > ALMOST_ONE)) {
var strideMaxAt = avatar.currentAnimation.calibration.strideMaxAt; var strideMaxAt = avatar.currentAnimation.calibration.strideMaxAt;
const TOLERANCE = 1.0; const TOLERANCE = 1.0;
@ -348,7 +348,7 @@ function updateTransitions() {
// helper function for renderMotion(). calculate the amount to lean forwards (or backwards) based on the avi's velocity // helper function for renderMotion(). calculate the amount to lean forwards (or backwards) based on the avi's velocity
function getLeanPitch() { function getLeanPitch() {
var leanProgress = 0; var leanProgress = 0;
if (motion.direction === DOWN || if (motion.direction === DOWN ||
motion.direction === FORWARDS || motion.direction === FORWARDS ||
motion.direction === BACKWARDS) { motion.direction === BACKWARDS) {
@ -364,7 +364,7 @@ function getLeanRoll() {
var leanRollProgress = 0; var leanRollProgress = 0;
var linearContribution = 0; var linearContribution = 0;
const LOG_SCALER = 8; const LOG_SCALER = 8;
if (Vec3.length(motion.velocity) > 0) { if (Vec3.length(motion.velocity) > 0) {
linearContribution = (Math.log(Vec3.length(motion.velocity) / TOP_SPEED) + LOG_SCALER) / LOG_SCALER; linearContribution = (Math.log(Vec3.length(motion.velocity) / TOP_SPEED) + LOG_SCALER) / LOG_SCALER;
} }
@ -375,7 +375,7 @@ function getLeanRoll() {
leanRollProgress = filter.bezier(leanRollProgress, {x: 1, y: 0}, {x: 1, y: 0}); leanRollProgress = filter.bezier(leanRollProgress, {x: 1, y: 0}, {x: 1, y: 0});
// which way to lean? // which way to lean?
var turnSign = (motion.yawDelta >= 0) ? 1 : -1; var turnSign = (motion.yawDelta >= 0) ? 1 : -1;
if (motion.direction === BACKWARDS || if (motion.direction === BACKWARDS ||
motion.direction === LEFT) { motion.direction === LEFT) {
turnSign *= -1; turnSign *= -1;
@ -409,7 +409,7 @@ function renderMotion() {
// factor any leaning into the hips offset // factor any leaning into the hips offset
hipsTranslations.z += avatar.calibration.hipsToFeet * Math.sin(filter.degToRad(leanPitch)); hipsTranslations.z += avatar.calibration.hipsToFeet * Math.sin(filter.degToRad(leanPitch));
hipsTranslations.x += avatar.calibration.hipsToFeet * Math.sin(filter.degToRad(leanRoll)); hipsTranslations.x += avatar.calibration.hipsToFeet * Math.sin(filter.degToRad(leanRoll));
// ensure skeleton offsets are within the 1m limit // ensure skeleton offsets are within the 1m limit
hipsTranslations.x = hipsTranslations.x > 1 ? 1 : hipsTranslations.x; hipsTranslations.x = hipsTranslations.x > 1 ? 1 : hipsTranslations.x;
hipsTranslations.x = hipsTranslations.x < -1 ? -1 : hipsTranslations.x; hipsTranslations.x = hipsTranslations.x < -1 ? -1 : hipsTranslations.x;
@ -422,7 +422,7 @@ function renderMotion() {
// play footfall sound? // play footfall sound?
var producingFootstepSounds = (avatar.currentAnimation === avatar.selectedWalkBlend) && avatar.makesFootStepSounds; var producingFootstepSounds = (avatar.currentAnimation === avatar.selectedWalkBlend) && avatar.makesFootStepSounds;
if (motion.currentTransition !== nullTransition && avatar.makesFootStepSounds) { if (motion.currentTransition !== nullTransition && avatar.makesFootStepSounds) {
if (motion.currentTransition.nextAnimation === avatar.selectedWalkBlend || if (motion.currentTransition.nextAnimation === avatar.selectedWalkBlend ||
motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) { motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) {
@ -433,8 +433,8 @@ function renderMotion() {
const QUARTER_CYCLE = 90; const QUARTER_CYCLE = 90;
const THREE_QUARTER_CYCLE = 270; const THREE_QUARTER_CYCLE = 270;
var ftWheelPosition = motion.frequencyTimeWheelPos; var ftWheelPosition = motion.frequencyTimeWheelPos;
if (motion.currentTransition !== nullTransition && if (motion.currentTransition !== nullTransition &&
motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) { motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) {
ftWheelPosition = motion.currentTransition.lastFrequencyTimeWheelPos; ftWheelPosition = motion.currentTransition.lastFrequencyTimeWheelPos;
} }
@ -453,7 +453,7 @@ function renderMotion() {
// ignore arms / head rotations if options are selected in the settings // ignore arms / head rotations if options are selected in the settings
if (avatar.armsFree && (joint.IKChain === "LeftArm" || joint.IKChain === "RightArm")) { if (avatar.armsFree && (joint.IKChain === "LeftArm" || joint.IKChain === "RightArm")) {
continue; continue;
} }
if (avatar.headFree && joint.IKChain === "Head") { if (avatar.headFree && joint.IKChain === "Head") {
continue; continue;
} }
@ -469,13 +469,13 @@ function renderMotion() {
motion.frequencyTimeWheelPos, motion.frequencyTimeWheelPos,
motion.direction); motion.direction);
} }
// apply angular velocity and speed induced leaning // apply angular velocity and speed induced leaning
if (jointName === "Hips") { if (jointName === "Hips") {
jointRotations.x += leanPitch; jointRotations.x += leanPitch;
jointRotations.z += leanRoll; jointRotations.z += leanRoll;
} }
// apply rotations // apply rotations
MyAvatar.setJointData(jointName, Quat.fromVec3Degrees(jointRotations)); MyAvatar.setJointData(jointName, Quat.fromVec3Degrees(jointRotations));
} }