diff --git a/examples/html/walkSettings.html b/examples/html/walkSettings.html
index 7c9b7fbbf7..7e65277977 100644
--- a/examples/html/walkSettings.html
+++ b/examples/html/walkSettings.html
@@ -2,16 +2,16 @@
@@ -62,7 +62,7 @@
-
+
diff --git a/examples/libraries/walkApi.js b/examples/libraries/walkApi.js
index 94357b97dc..ab9f5071b1 100644
--- a/examples/libraries/walkApi.js
+++ b/examples/libraries/walkApi.js
@@ -3,7 +3,7 @@
// version 1.3
//
// Created by David Wooldridge, June 2015
-// Copyright © 2014 - 2015 High Fidelity, Inc.
+// Copyright © 2014 - 2015 High Fidelity, Inc.
//
// Exposes API for use by walk.js version 1.2+.
//
@@ -13,46 +13,11 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
-// locomotion states
-const STATIC = 1;
-const SURFACE_MOTION = 2;
-const AIR_MOTION = 4;
-
-// directions
-const UP = 1;
-const DOWN = 2;
-const LEFT = 4;
-const RIGHT = 8;
-const FORWARDS = 16;
-const BACKWARDS = 32;
-const NONE = 64;
-
-// waveshapes
-const SAWTOOTH = 1;
-const TRIANGLE = 2;
-const SQUARE = 4;
-
-// constants used by walk.js and walkApi.js
-const MAX_WALK_SPEED = 2.9; // peak, by observation
-const MAX_FT_WHEEL_INCREMENT = 25; // avoid fast walk when landing
-const TOP_SPEED = 300;
-const ON_SURFACE_THRESHOLD = 0.1; // height above surface to be considered as on the surface
-const TRANSITION_COMPLETE = 1000;
-const HIFI_PUBLIC_BUCKET = "https://hifi-public.s3.amazonaws.com/";
-
-// constants used by walkApi.js
-const MOVE_THRESHOLD = 0.075;
-const ACCELERATION_THRESHOLD = 0.2; // detect stop to walking
-const DECELERATION_THRESHOLD = -6; // detect walking to stop
-const FAST_DECELERATION_THRESHOLD = -150; // detect flying to stop
-const BOUNCE_ACCELERATION_THRESHOLD = 25; // used to ignore gravity influence fluctuations after landing
-const GRAVITY_THRESHOLD = 3.0; // height above surface where gravity is in effect
-const OVERCOME_GRAVITY_SPEED = 0.5; // reaction sensitivity to jumping under gravity
-const LANDING_THRESHOLD = 0.35; // metres from a surface below which need to prepare for impact
-const MAX_TRANSITION_RECURSION = 10; // how many nested transitions are permitted
+// included here to ensure walkApi.js can be used as an API, separate from walk.js
+Script.include("./libraries/walkConstants.js");
Avatar = function() {
- // if Hydras are connected, the only way to enable use is by never setting any rotations on the arm joints
+ // if Hydras are connected, the only way to enable use is to never set any arm joint rotation
this.hydraCheck = function() {
// function courtesy of Thijs Wenker (frisbee.js)
var numberOfButtons = Controller.getNumberOfButtons();
@@ -75,8 +40,8 @@ Avatar = function() {
// settings
this.headFree = true;
this.armsFree = this.hydraCheck(); // automatically sets true to enable Hydra support - temporary fix
- this.makesFootStepSounds = false;
- this.isBlenderExport = false; // temporary fix
+ this.makesFootStepSounds = true;
+ this.blenderPreRotations = false; // temporary fix
this.animationSet = undefined; // currently just one animation set
this.setAnimationSet = function(animationSet) {
this.animationSet = animationSet;
@@ -123,7 +88,7 @@ Avatar = function() {
this.calibration.hipsToFeet = MyAvatar.getJointPosition("Hips").y - MyAvatar.getJointPosition("RightToeBase").y;
// maybe measuring before Blender pre-rotations have been applied?
- if (this.calibration.hipsToFeet < 0 && this.isBlenderExport) {
+ if (this.calibration.hipsToFeet < 0 && this.blenderPreRotations) {
this.calibration.hipsToFeet *= -1;
}
@@ -165,7 +130,6 @@ Avatar = function() {
// footsteps
this.nextStep = RIGHT; // the first step is right, because the waveforms say so
-
this.leftAudioInjector = null;
this.rightAudioInjector = null;
this.makeFootStepSound = function() {
@@ -173,16 +137,18 @@ Avatar = function() {
const SPEED_THRESHOLD = 0.4;
const VOLUME_ATTENUATION = 0.8;
const MIN_VOLUME = 0.5;
+ var volume = Vec3.length(motion.velocity) > SPEED_THRESHOLD ?
+ VOLUME_ATTENUATION * Vec3.length(motion.velocity) / MAX_WALK_SPEED : MIN_VOLUME;
+ volume = volume > 1 ? 1 : volume; // occurs when landing at speed - can walk faster than max walking speed
var options = {
position: Vec3.sum(MyAvatar.position, {x:0, y: -this.calibration.hipsToFeet, z:0}),
- volume: Vec3.length(motion.velocity) > SPEED_THRESHOLD ?
- VOLUME_ATTENUATION * Vec3.length(motion.velocity) / MAX_WALK_SPEED : MIN_VOLUME
+ volume: volume
};
if (this.nextStep === RIGHT) {
if (this.rightAudioInjector === null) {
this.rightAudioInjector = Audio.playSound(walkAssets.footsteps[0], options);
} else {
- //this.rightAudioInjector.setOptions(options);
+ this.rightAudioInjector.setOptions(options);
this.rightAudioInjector.restart();
}
this.nextStep = LEFT;
@@ -190,7 +156,7 @@ Avatar = function() {
if (this.leftAudioInjector === null) {
this.leftAudioInjector = Audio.playSound(walkAssets.footsteps[1], options);
} else {
- //this.leftAudioInjector.setOptions(options);
+ this.leftAudioInjector.setOptions(options);
this.leftAudioInjector.restart();
}
this.nextStep = RIGHT;
@@ -200,6 +166,7 @@ Avatar = function() {
// constructor for the Motion object
Motion = function() {
+ this.isLive = true;
// locomotion status
this.state = STATIC;
this.nextState = STATIC;
@@ -212,14 +179,6 @@ Motion = function() {
this.isComingToHalt = false;
this.directedAcceleration = 0;
- // settings
- this.isLive = true;
- this.calibration = {
- PITCH_MAX: 60,
- ROLL_MAX: 80,
- DELTA_YAW_MAX: 1.7
- }
-
// used to make sure at least one step has been taken when transitioning from a walk cycle
this.elapsedFTDegrees = 0;
@@ -360,6 +319,7 @@ Motion = function() {
(movingDirectlyUpOrDown && !isOnSurface));
var staticToSurfaceMotion = surfaceMotion && !motion.isComingToHalt && !movingDirectlyUpOrDown &&
!this.isDecelerating && lateralVelocity > MOVE_THRESHOLD;
+
if (staticToAirMotion) {
this.nextState = AIR_MOTION;
} else if (staticToSurfaceMotion) {
@@ -376,6 +336,7 @@ Motion = function() {
var surfaceMotionToAirMotion = (acceleratingAndAirborne || goingTooFastToWalk || movingDirectlyUpOrDown) &&
(!surfaceMotion && isTakingOff) ||
(!surfaceMotion && this.isMoving && !isComingInToLand);
+
if (surfaceMotionToStatic) {
// working on the assumption that stopping is now inevitable
if (!motion.isComingToHalt && isOnSurface) {
@@ -392,6 +353,7 @@ Motion = function() {
case AIR_MOTION:
var airMotionToSurfaceMotion = (surfaceMotion || aboutToLand) && !movingDirectlyUpOrDown;
var airMotionToStatic = !this.isMoving && this.direction === this.lastDirection;
+
if (airMotionToSurfaceMotion){
this.nextState = SURFACE_MOTION;
} else if (airMotionToStatic) {
@@ -492,7 +454,7 @@ animationOperations = (function() {
var joint = animation.joints[jointName];
var jointRotations = {x:0, y:0, z:0};
- if (avatar.isBlenderExport) {
+ if (avatar.blenderPreRotations) {
jointRotations = Vec3.sum(jointRotations, walkAssets.blenderPreRotations.joints[jointName]);
}
@@ -670,7 +632,7 @@ TransitionParameters = function() {
this.duration = 0.5;
this.easingLower = {x:0.25, y:0.75};
this.easingUpper = {x:0.75, y:0.25};
- this.reachPoseNames = [];
+ this.reachPoses = [];
}
const QUARTER_CYCLE = 90;
@@ -710,8 +672,8 @@ Transition = function(nextAnimation, lastAnimation, lastTransition, playTransiti
walkAssets.getTransitionParameters(lastAnimation, nextAnimation, this.parameters);
// fire up any reach poses for this transition
if (playTransitionReachPoses) {
- for (poseName in this.parameters.reachPoseNames) {
- this.liveReachPoses.push(new ReachPose(this.parameters.reachPoseNames[poseName]));
+ for (poseName in this.parameters.reachPoses) {
+ this.liveReachPoses.push(new ReachPose(this.parameters.reachPoses[poseName]));
}
}
}
diff --git a/examples/libraries/walkConstants.js b/examples/libraries/walkConstants.js
new file mode 100644
index 0000000000..abc9a4bc5f
--- /dev/null
+++ b/examples/libraries/walkConstants.js
@@ -0,0 +1,54 @@
+//
+// walkConstants.js
+// version 1.0
+//
+// Created by David Wooldridge, June 2015
+// Copyright © 2015 High Fidelity, Inc.
+//
+// Provides constants necessary for the operation of the walk.js script and the walkApi.js script
+//
+// Editing tools for animation data files available here: https://github.com/DaveDubUK/walkTools
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+// locomotion states
+STATIC = 1;
+SURFACE_MOTION = 2;
+AIR_MOTION = 4;
+
+// directions
+UP = 1;
+DOWN = 2;
+LEFT = 4;
+RIGHT = 8;
+FORWARDS = 16;
+BACKWARDS = 32;
+NONE = 64;
+
+// waveshapes
+SAWTOOTH = 1;
+TRIANGLE = 2;
+SQUARE = 4;
+
+// used by walk.js and walkApi.js
+MAX_WALK_SPEED = 2.9; // peak, by observation
+MAX_FT_WHEEL_INCREMENT = 25; // avoid fast walk when landing
+TOP_SPEED = 300;
+ON_SURFACE_THRESHOLD = 0.1; // height above surface to be considered as on the surface
+TRANSITION_COMPLETE = 1000;
+PITCH_MAX = 60; // maximum speed induced pitch
+ROLL_MAX = 80; // maximum speed induced leaning / banking
+DELTA_YAW_MAX = 1.7; // maximum change in yaw in rad/s
+
+// used by walkApi.js only
+MOVE_THRESHOLD = 0.075; // movement dead zone
+ACCELERATION_THRESHOLD = 0.2; // detect stop to walking
+DECELERATION_THRESHOLD = -6; // detect walking to stop
+FAST_DECELERATION_THRESHOLD = -150; // detect flying to stop
+BOUNCE_ACCELERATION_THRESHOLD = 25; // used to ignore gravity influence fluctuations after landing
+GRAVITY_THRESHOLD = 3.0; // height above surface where gravity is in effect
+OVERCOME_GRAVITY_SPEED = 0.5; // reaction sensitivity to jumping under gravity
+LANDING_THRESHOLD = 0.35; // metres from a surface below which need to prepare for impact
+MAX_TRANSITION_RECURSION = 10; // how many nested transitions are permitted
\ No newline at end of file
diff --git a/examples/libraries/walkFilters.js b/examples/libraries/walkFilters.js
index 9f8c947b1f..1f8077d9eb 100644
--- a/examples/libraries/walkFilters.js
+++ b/examples/libraries/walkFilters.js
@@ -2,8 +2,8 @@
// walkFilters.js
// version 1.1
//
-// Created by David Wooldridge, Autumn 2014
-// Copyright © 2014 - 2015 High Fidelity, Inc.
+// Created by David Wooldridge, June 2015
+// Copyright © 2014 - 2015 High Fidelity, Inc.
//
// Provides a variety of filters for use by the walk.js script v1.2+
//
diff --git a/examples/libraries/walkSettings.js b/examples/libraries/walkSettings.js
index 2657eca605..e997e4f29e 100644
--- a/examples/libraries/walkSettings.js
+++ b/examples/libraries/walkSettings.js
@@ -3,7 +3,7 @@
// version 0.1
//
// Created by David Wooldridge, June 2015
-// Copyright © 2014 - 2015 High Fidelity, Inc.
+// Copyright © 2015 High Fidelity, Inc.
//
// Presents settings for walk.js
//
@@ -31,7 +31,7 @@ WalkSettings = function() {
function mousePressEvent(event) {
if (Overlays.getOverlayAtPoint(event) === minimisedTab) {
_visible = !_visible;
- _webView.setVisible(_visible);
+ _webWindow.setVisible(_visible);
}
}
Controller.mousePressEvent.connect(mousePressEvent);
@@ -55,7 +55,7 @@ WalkSettings = function() {
}
if (_shift && (event.text === 'o' || event.text === 'O')) {
_visible = !_visible;
- _webView.setVisible(_visible);
+ _webWindow.setVisible(_visible);
}
}
function keyReleaseEvent(event) {
@@ -67,30 +67,29 @@ WalkSettings = function() {
Controller.keyReleaseEvent.connect(keyReleaseEvent);
// web window
- var _url = Script.resolvePath('html/walkSettings.html');
const PANEL_WIDTH = 200;
const PANEL_HEIGHT = 180;
- var _webView = new WebWindow('Walk Settings', _url, PANEL_WIDTH, PANEL_HEIGHT, false);
- _webView.setVisible(false);
-
- _webView.eventBridge.webEventReceived.connect(function(data) {
+ var _url = Script.resolvePath('html/walkSettings.html');
+ var _webWindow = new WebWindow('Walk Settings', _url, PANEL_WIDTH, PANEL_HEIGHT, false);
+ _webWindow.setVisible(false);
+ _webWindow.eventBridge.webEventReceived.connect(function(data) {
data = JSON.parse(data);
if (data.type == "init") {
// send the current settings to the window
- _webView.eventBridge.emitScriptEvent(JSON.stringify({
+ _webWindow.eventBridge.emitScriptEvent(JSON.stringify({
type: "update",
armsFree: avatar.armsFree,
- footstepSounds: avatar.makesFootStepSounds,
- blenderPreRotations: avatar.isBlenderExport
+ makesFootStepSounds: avatar.makesFootStepSounds,
+ blenderPreRotations: avatar.blenderPreRotations
}));
} else if (data.type == "powerToggle") {
motion.isLive = !motion.isLive;
} else if (data.type == "update") {
// receive settings from the window
avatar.armsFree = data.armsFree;
- avatar.makesFootStepSounds = data.footstepSounds;
- avatar.isBlenderExport = data.blenderPreRotations;
+ avatar.makesFootStepSounds = data.makesFootStepSounds;
+ avatar.blenderPreRotations = data.blenderPreRotations;
}
});
};
diff --git a/examples/walk.js b/examples/walk.js
index 0c2e978eea..8d54fecc92 100644
--- a/examples/walk.js
+++ b/examples/walk.js
@@ -3,7 +3,7 @@
// version 1.25
//
// Created by David Wooldridge, June 2015
-// Copyright © 2014 - 2015 High Fidelity, Inc.
+// Copyright © 2014 - 2015 High Fidelity, Inc.
//
// Animates an avatar using procedural animation techniques.
//
@@ -13,61 +13,25 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
-// locomotion states
-var STATIC = 1;
-var SURFACE_MOTION = 2;
-var AIR_MOTION = 4;
-
-// directions
-var UP = 1;
-var DOWN = 2;
-var LEFT = 4;
-var RIGHT = 8;
-var FORWARDS = 16;
-var BACKWARDS = 32;
-var NONE = 64;
-
-// waveshapes
-var SAWTOOTH = 1;
-var TRIANGLE = 2;
-var SQUARE = 4;
-
-// constants
-const MAX_WALK_SPEED = 2.9; // peak, by observation
-const MAX_FT_WHEEL_INCREMENT = 25; // avoid fast walk when landing
-const TOP_SPEED = 300;
-const ON_SURFACE_THRESHOLD = 0.1; // height above surface to be considered as on the surface
-const TRANSITION_COMPLETE = 1000;
+// animations, reach poses, reach pose parameters, transitions, transition parameters, sounds, image/s and reference files
const HIFI_PUBLIC_BUCKET = "https://hifi-public.s3.amazonaws.com/";
-
-// path to animations, reach-poses, reachPoses, transitions, overlay images and reference files
var pathToAssets = HIFI_PUBLIC_BUCKET + "procedural-animator/assets/";
Script.include([
+ "./libraries/walkConstants.js",
"./libraries/walkFilters.js",
"./libraries/walkApi.js",
pathToAssets + "walkAssets.js"
]);
-// construct Avatar and Motion
+// construct Avatar, Motion and (null) Transition
var avatar = new Avatar();
var motion = new Motion();
-
-// create settings dialog
-Script.include("./libraries/walkSettings.js");
-
-// create and initialise Transition
var nullTransition = new Transition();
motion.currentTransition = nullTransition;
-// motion smoothing / damping filters
-var FLY_BLEND_DAMPING = 50;
-var leanPitchSmoothingFilter = filter.createButterworthFilter();
-var leanRollSmoothingFilter = filter.createButterworthFilter();
-var flyUpFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING);
-var flyDownFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING);
-var flyForwardFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING);
-var flyBackwardFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING);
+// create settings (gets initial values from avatar)
+Script.include("./libraries/walkSettings.js");
// Main loop
Script.update.connect(function(deltaTime) {
@@ -80,8 +44,8 @@ Script.update.connect(function(deltaTime) {
// decide which animation should be playing
selectAnimation();
- // turn the frequency time wheels and determine stride length
- determineStride();
+ // advance the animation cycle/s by the correct amount/s
+ advanceAnimations();
// update the progress of any live transitions
updateTransitions();
@@ -89,7 +53,7 @@ Script.update.connect(function(deltaTime) {
// apply translation and rotations
renderMotion();
- // record this frame's parameters
+ // save this frame's parameters
motion.saveHistory();
}
});
@@ -130,6 +94,13 @@ function setTransition(nextAnimation, playTransitionReachPoses) {
}
}
+// fly animation blending: smoothing / damping filters
+const FLY_BLEND_DAMPING = 50;
+var flyUpFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING);
+var flyDownFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING);
+var flyForwardFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING);
+var flyBackwardFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING);
+
// select / blend the appropriate animation for the current state of motion
function selectAnimation() {
var playTransitionReachPoses = true;
@@ -259,7 +230,7 @@ function selectAnimation() {
}
// determine the length of stride. advance the frequency time wheels. advance frequency time wheels for any live transitions
-function determineStride() {
+function advanceAnimations() {
var wheelAdvance = 0;
// turn the frequency time wheel
@@ -338,7 +309,6 @@ function updateTransitions() {
}
}
}
- // update the Transition progress
if (motion.currentTransition.updateProgress() === TRANSITION_COMPLETE) {
motion.currentTransition = nullTransition;
}
@@ -346,6 +316,7 @@ function updateTransitions() {
}
// helper function for renderMotion(). calculate the amount to lean forwards (or backwards) based on the avi's velocity
+var leanPitchSmoothingFilter = filter.createButterworthFilter();
function getLeanPitch() {
var leanProgress = 0;
@@ -356,10 +327,11 @@ function getLeanPitch() {
}
// use filters to shape the walking acceleration response
leanProgress = leanPitchSmoothingFilter.process(leanProgress);
- return motion.calibration.PITCH_MAX * leanProgress;
+ return PITCH_MAX * leanProgress;
}
// helper function for renderMotion(). calculate the angle at which to bank into corners whilst turning
+var leanRollSmoothingFilter = filter.createButterworthFilter();
function getLeanRoll() {
var leanRollProgress = 0;
var linearContribution = 0;
@@ -368,7 +340,7 @@ function getLeanRoll() {
if (Vec3.length(motion.velocity) > 0) {
linearContribution = (Math.log(Vec3.length(motion.velocity) / TOP_SPEED) + LOG_SCALER) / LOG_SCALER;
}
- var angularContribution = Math.abs(motion.yawDelta) / motion.calibration.DELTA_YAW_MAX;
+ var angularContribution = Math.abs(motion.yawDelta) / DELTA_YAW_MAX;
leanRollProgress = linearContribution;
leanRollProgress *= angularContribution;
// shape the response curve
@@ -382,7 +354,7 @@ function getLeanRoll() {
}
// filter progress
leanRollProgress = leanRollSmoothingFilter.process(turnSign * leanRollProgress);
- return motion.calibration.ROLL_MAX * leanRollProgress;
+ return ROLL_MAX * leanRollProgress;
}
// animate the avatar using sine waves, geometric waveforms and harmonic generators