mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 09:48:44 +02:00
code review changes for walk.js 1.25
This commit is contained in:
parent
796d76004c
commit
c2287e9953
5 changed files with 289 additions and 201 deletions
|
@ -1,6 +1,6 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<link rel="stylesheet" type="text/css" href="style.css">
|
<link rel="stylesheet" type="text/css" href="walkStyle.css">
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
function emitUpdate() {
|
function emitUpdate() {
|
||||||
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
function loaded() {
|
function loaded() {
|
||||||
// assign form elements to vars
|
// assign form elements to vars
|
||||||
|
var powerOn = true;
|
||||||
elPower = document.getElementById("power");
|
elPower = document.getElementById("power");
|
||||||
elArmsFree = document.getElementById("arms-free");
|
elArmsFree = document.getElementById("arms-free");
|
||||||
elFootstepSounds = document.getElementById("footstep-sounds");
|
elFootstepSounds = document.getElementById("footstep-sounds");
|
||||||
|
@ -25,13 +26,13 @@
|
||||||
|
|
||||||
if (data.type == "update") {
|
if (data.type == "update") {
|
||||||
if (data.armsFree !== undefined) {
|
if (data.armsFree !== undefined) {
|
||||||
elArmsFree.checked = data.armsFree == true;
|
elArmsFree.checked = data.armsFree;
|
||||||
}
|
}
|
||||||
if (data.footstepSounds !== undefined) {
|
if (data.footstepSounds !== undefined) {
|
||||||
elFootstepSounds.checked = data.footstepSounds == true;
|
elFootstepSounds.checked = data.footstepSounds;
|
||||||
}
|
}
|
||||||
if (data.blenderPreRotations !== undefined) {
|
if (data.blenderPreRotations !== undefined) {
|
||||||
elBlenderPreRotations.checked = data.blenderPreRotations == true;
|
elBlenderPreRotations.checked = data.blenderPreRotations;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -45,6 +46,12 @@
|
||||||
EventBridge.emitWebEvent(JSON.stringify({
|
EventBridge.emitWebEvent(JSON.stringify({
|
||||||
type: "powerToggle"
|
type: "powerToggle"
|
||||||
}));
|
}));
|
||||||
|
powerOn = !powerOn;
|
||||||
|
if (powerOn) {
|
||||||
|
elPower.value = "Turn Animation Off";
|
||||||
|
} else {
|
||||||
|
elPower.value = "Turn Animation On";
|
||||||
|
}
|
||||||
});
|
});
|
||||||
// request initial values
|
// request initial values
|
||||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'init' }));
|
EventBridge.emitWebEvent(JSON.stringify({ type: 'init' }));
|
||||||
|
@ -52,27 +59,27 @@
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body onload='loaded();'>
|
<body onload='loaded();'>
|
||||||
<div class="grid-section">
|
<div>
|
||||||
|
|
||||||
<div id="entity-list-header">
|
<div id="walk-settings-header">
|
||||||
<input type="button" id="power" value="Power" style="margin-left:68px; margin-top:10px"></button>
|
<input type="button" id="power" value="Turn Animation Off" style="margin-left:30px; margin-top:10px"></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="property-section">
|
<div class="settings-section">
|
||||||
<label>Arms free</label>
|
<label>Arms free</label>
|
||||||
<span>
|
<span>
|
||||||
<input type='checkbox' id="arms-free">
|
<input type='checkbox' id="arms-free">
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="property-section">
|
<div class="settings-section">
|
||||||
<label>Footstep sounds</label>
|
<label>Footstep sounds</label>
|
||||||
<span>
|
<span>
|
||||||
<input type='checkbox' id="footstep-sounds">
|
<input type='checkbox' id="footstep-sounds">
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="property-section">
|
<div class="settings-section">
|
||||||
<label>Blender pre-rotations</label>
|
<label>Blender pre-rotations</label>
|
||||||
<span>
|
<span>
|
||||||
<input type='checkbox' id="bender-pre-rotations">
|
<input type='checkbox' id="bender-pre-rotations">
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
// walkApi.js
|
// walkApi.js
|
||||||
// version 1.3
|
// version 1.3
|
||||||
//
|
//
|
||||||
// Created by David Wooldridge, June 2015
|
// Created by David Wooldridge, Autumn 2014
|
||||||
// Copyright © 2014 - 2015 High Fidelity, Inc.
|
// Copyright © 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
|
||||||
//
|
//
|
||||||
|
@ -13,6 +13,44 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// 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
|
||||||
|
|
||||||
Avatar = function() {
|
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 by never setting any rotations on the arm joints
|
||||||
this.hydraCheck = function() {
|
this.hydraCheck = function() {
|
||||||
|
@ -20,8 +58,13 @@ Avatar = function() {
|
||||||
var numberOfButtons = Controller.getNumberOfButtons();
|
var numberOfButtons = Controller.getNumberOfButtons();
|
||||||
var numberOfTriggers = Controller.getNumberOfTriggers();
|
var numberOfTriggers = Controller.getNumberOfTriggers();
|
||||||
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
|
var numberOfSpatialControls = Controller.getNumberOfSpatialControls();
|
||||||
|
const HYDRA_BUTTONS = 12;
|
||||||
|
const HYDRA_TRIGGERS = 2;
|
||||||
|
const HYDRA_CONTROLLERS_PER_TRIGGER = 2;
|
||||||
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
|
var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers;
|
||||||
if (numberOfButtons == 12 && numberOfTriggers == 2 && controllersPerTrigger == 2) {
|
if (numberOfButtons == HYDRA_BUTTONS &&
|
||||||
|
numberOfTriggers == HYDRA_TRIGGERS &&
|
||||||
|
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)');
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -32,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; // true ? still inexplicably glitchy : fine
|
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) {
|
||||||
|
@ -45,8 +88,6 @@ Avatar = function() {
|
||||||
this.selectedSideStepLeft = walkAssets.getAnimationDataFile("MaleSideStepLeft");
|
this.selectedSideStepLeft = walkAssets.getAnimationDataFile("MaleSideStepLeft");
|
||||||
this.selectedSideStepRight = walkAssets.getAnimationDataFile("MaleSideStepRight");
|
this.selectedSideStepRight = walkAssets.getAnimationDataFile("MaleSideStepRight");
|
||||||
this.selectedWalkBlend = walkAssets.getAnimationDataFile("WalkBlend");
|
this.selectedWalkBlend = walkAssets.getAnimationDataFile("WalkBlend");
|
||||||
this.selectedTurnLeft = walkAssets.getAnimationDataFile("MaleTurnLeft");
|
|
||||||
this.selectedTurnRight = walkAssets.getAnimationDataFile("MaleTurnRight");
|
|
||||||
this.selectedHover = walkAssets.getAnimationDataFile("MaleHover");
|
this.selectedHover = walkAssets.getAnimationDataFile("MaleHover");
|
||||||
this.selectedFly = walkAssets.getAnimationDataFile("MaleFly");
|
this.selectedFly = walkAssets.getAnimationDataFile("MaleFly");
|
||||||
this.selectedFlyBackwards = walkAssets.getAnimationDataFile("MaleFlyBackwards");
|
this.selectedFlyBackwards = walkAssets.getAnimationDataFile("MaleFlyBackwards");
|
||||||
|
@ -59,17 +100,16 @@ Avatar = function() {
|
||||||
}
|
}
|
||||||
this.setAnimationSet('standardMale');
|
this.setAnimationSet('standardMale');
|
||||||
|
|
||||||
this.startTime = new Date().getTime();
|
|
||||||
|
|
||||||
// calibration
|
// calibration
|
||||||
this.calibration = {
|
this.calibration = {
|
||||||
hipsToFeet: 1.011,
|
hipsToFeet: 1,
|
||||||
strideLength: this.selectedWalk.calibration.strideLength
|
strideLength: this.selectedWalk.calibration.strideLength
|
||||||
}
|
}
|
||||||
this.distanceFromSurface = 0;
|
this.distanceFromSurface = 0;
|
||||||
this.calibrate = function() {
|
this.calibrate = function() {
|
||||||
// Triple check: measurements are taken three times to ensure accuracy - the first result is often too large
|
// Triple check: measurements are taken three times to ensure accuracy - the first result is often too large
|
||||||
var attempts = 3;
|
const MAX_ATTEMPTS = 3;
|
||||||
|
var attempts = MAX_ATTEMPTS;
|
||||||
var extraAttempts = 0;
|
var extraAttempts = 0;
|
||||||
do {
|
do {
|
||||||
for (joint in walkAssets.animationReference.joints) {
|
for (joint in walkAssets.animationReference.joints) {
|
||||||
|
@ -81,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;
|
||||||
}
|
}
|
||||||
|
@ -95,7 +135,7 @@ Avatar = function() {
|
||||||
|
|
||||||
// just in case
|
// just in case
|
||||||
if (this.calibration.hipsToFeet <= 0 || isNaN(this.calibration.hipsToFeet)) {
|
if (this.calibration.hipsToFeet <= 0 || isNaN(this.calibration.hipsToFeet)) {
|
||||||
this.calibration.hipsToFeet = 1.0;
|
this.calibration.hipsToFeet = 1;
|
||||||
print('walk.js error: Unable to get a non-zero measurement for the avatar hips to feet measure. Hips to feet set to default value ('+
|
print('walk.js error: Unable to get a non-zero measurement for the avatar hips to feet measure. Hips to feet set to default value ('+
|
||||||
this.calibration.hipsToFeet.toFixed(3)+'m). This will cause some foot sliding. If your avatar has only just appeared, it is recommended that you re-load the walk script.');
|
this.calibration.hipsToFeet.toFixed(3)+'m). This will cause some foot sliding. If your avatar has only just appeared, it is recommended that you re-load the walk script.');
|
||||||
} else {
|
} else {
|
||||||
|
@ -125,22 +165,34 @@ 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.rightAudioInjector = null;
|
||||||
this.makeFootStepSound = function() {
|
this.makeFootStepSound = function() {
|
||||||
// correlate footstep volume with avatar speed. place the audio source at the feet, not the hips
|
// correlate footstep volume with avatar speed. place the audio source at the feet, not the hips
|
||||||
var SPEED_THRESHOLD = 0.4;
|
const SPEED_THRESHOLD = 0.4;
|
||||||
var VOLUME_ATTENUATION = 0.8;
|
const VOLUME_ATTENUATION = 0.8;
|
||||||
var MIN_VOLUME = 0.5;
|
const MIN_VOLUME = 0.5;
|
||||||
var options = {
|
var options = {
|
||||||
position: Vec3.sum(MyAvatar.position, {x:0, y: -this.calibration.hipsToFeet, z:0}),
|
position: Vec3.sum(MyAvatar.position, {x:0, y: -this.calibration.hipsToFeet, z:0}),
|
||||||
volume: Vec3.length(motion.velocity) > SPEED_THRESHOLD ?
|
volume: Vec3.length(motion.velocity) > SPEED_THRESHOLD ?
|
||||||
VOLUME_ATTENUATION * Vec3.length(motion.velocity) / MAX_WALK_SPEED : MIN_VOLUME
|
VOLUME_ATTENUATION * Vec3.length(motion.velocity) / MAX_WALK_SPEED : MIN_VOLUME
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.nextStep === RIGHT) {
|
if (this.nextStep === RIGHT) {
|
||||||
Audio.playSound(walkAssets.footsteps[0], options);
|
if (this.rightAudioInjector === null) {
|
||||||
|
this.rightAudioInjector = Audio.playSound(walkAssets.footsteps[0], options);
|
||||||
|
} else {
|
||||||
|
//this.rightAudioInjector.setOptions(options);
|
||||||
|
this.rightAudioInjector.restart();
|
||||||
|
}
|
||||||
this.nextStep = LEFT;
|
this.nextStep = LEFT;
|
||||||
} else if (this.nextStep === LEFT) {
|
} else if (this.nextStep === LEFT) {
|
||||||
Audio.playSound(walkAssets.footsteps[1], options);
|
if (this.leftAudioInjector === null) {
|
||||||
|
this.leftAudioInjector = Audio.playSound(walkAssets.footsteps[1], options);
|
||||||
|
} else {
|
||||||
|
//this.leftAudioInjector.setOptions(options);
|
||||||
|
this.leftAudioInjector.restart();
|
||||||
|
}
|
||||||
this.nextStep = RIGHT;
|
this.nextStep = RIGHT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,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);
|
this.yawFilter = filter.createAveragingFilter(YAW_SMOOTHING); //createButterworthFilter(); //
|
||||||
this.deltaTimeFilter = filter.createAveragingFilter(YAW_SMOOTHING);
|
this.deltaTimeFilter = filter.createAveragingFilter(YAW_SMOOTHING); //createButterworthFilter(); //
|
||||||
this.yawDeltaAccelerationFilter = filter.createAveragingFilter(YAW_SMOOTHING);
|
this.yawDeltaAccelerationFilter = filter.createAveragingFilter(YAW_SMOOTHING); //createButterworthFilter(); //
|
||||||
|
|
||||||
// assess locomotion state
|
// assess locomotion state
|
||||||
this.assess = function(deltaTime) {
|
this.assess = function(deltaTime) {
|
||||||
|
@ -298,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)
|
var movingDirectlyUpOrDown = (this.direction === UP || this.direction === DOWN) // && lateralVelocity < MOVE_THRESHOLD;
|
||||||
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) {
|
||||||
|
@ -318,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) ||
|
||||||
|
@ -339,7 +391,8 @@ 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) {
|
||||||
|
@ -352,10 +405,12 @@ Motion = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// frequency time wheel (foot / ground speed matching)
|
// frequency time wheel (foot / ground speed matching)
|
||||||
|
const DEFAULT_HIPS_TO_FEET = 1;
|
||||||
this.frequencyTimeWheelPos = 0;
|
this.frequencyTimeWheelPos = 0;
|
||||||
this.frequencyTimeWheelRadius = 0.5;
|
this.frequencyTimeWheelRadius = DEFAULT_HIPS_TO_FEET / 2;
|
||||||
this.recentFrequencyTimeIncrements = [];
|
this.recentFrequencyTimeIncrements = [];
|
||||||
for (var i = 0; i < 8; i++) {
|
const FT_WHEEL_HISTORY_LENGTH = 8;
|
||||||
|
for (var i = 0; i < FT_WHEEL_HISTORY_LENGTH; i++) {
|
||||||
this.recentFrequencyTimeIncrements.push(0);
|
this.recentFrequencyTimeIncrements.push(0);
|
||||||
}
|
}
|
||||||
this.averageFrequencyTimeIncrement = 0;
|
this.averageFrequencyTimeIncrement = 0;
|
||||||
|
@ -370,8 +425,9 @@ Motion = function() {
|
||||||
}
|
}
|
||||||
this.averageFrequencyTimeIncrement /= this.recentFrequencyTimeIncrements.length;
|
this.averageFrequencyTimeIncrement /= this.recentFrequencyTimeIncrements.length;
|
||||||
this.frequencyTimeWheelPos += angle;
|
this.frequencyTimeWheelPos += angle;
|
||||||
if (this.frequencyTimeWheelPos >= 360) {
|
const FULL_CIRCLE = 360;
|
||||||
this.frequencyTimeWheelPos = this.frequencyTimeWheelPos % 360;
|
if (this.frequencyTimeWheelPos >= FULL_CIRCLE) {
|
||||||
|
this.frequencyTimeWheelPos = this.frequencyTimeWheelPos % FULL_CIRCLE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,7 +484,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;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -516,7 +572,7 @@ animationOperations = (function() {
|
||||||
|
|
||||||
// harmonics
|
// harmonics
|
||||||
targetAnimation.harmonics = {};
|
targetAnimation.harmonics = {};
|
||||||
if (isDefined(sourceAnimation.harmonics)) {
|
if (sourceAnimation.harmonics) {
|
||||||
targetAnimation.harmonics = JSON.parse(JSON.stringify(sourceAnimation.harmonics));
|
targetAnimation.harmonics = JSON.parse(JSON.stringify(sourceAnimation.harmonics));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -524,26 +580,26 @@ animationOperations = (function() {
|
||||||
targetAnimation.filters = {};
|
targetAnimation.filters = {};
|
||||||
for (i in sourceAnimation.filters) {
|
for (i in sourceAnimation.filters) {
|
||||||
// are any filters specified for this joint?
|
// are any filters specified for this joint?
|
||||||
if (isDefined(sourceAnimation.filters[i])) {
|
if (sourceAnimation.filters[i]) {
|
||||||
targetAnimation.filters[i] = sourceAnimation.filters[i];
|
targetAnimation.filters[i] = sourceAnimation.filters[i];
|
||||||
// wave shapers
|
// wave shapers
|
||||||
if (isDefined(sourceAnimation.filters[i].pitchFilter)) {
|
if (sourceAnimation.filters[i].pitchFilter) {
|
||||||
targetAnimation.filters[i].pitchFilter = sourceAnimation.filters[i].pitchFilter;
|
targetAnimation.filters[i].pitchFilter = sourceAnimation.filters[i].pitchFilter;
|
||||||
}
|
}
|
||||||
if (isDefined(sourceAnimation.filters[i].yawFilter)) {
|
if (sourceAnimation.filters[i].yawFilter) {
|
||||||
targetAnimation.filters[i].yawFilter = sourceAnimation.filters[i].yawFilter;
|
targetAnimation.filters[i].yawFilter = sourceAnimation.filters[i].yawFilter;
|
||||||
}
|
}
|
||||||
if (isDefined(sourceAnimation.filters[i].rollFilter)) {
|
if (sourceAnimation.filters[i].rollFilter) {
|
||||||
targetAnimation.filters[i].rollFilter = sourceAnimation.filters[i].rollFilter;
|
targetAnimation.filters[i].rollFilter = sourceAnimation.filters[i].rollFilter;
|
||||||
}
|
}
|
||||||
// LP filters
|
// LP filters
|
||||||
if (isDefined(sourceAnimation.filters[i].swayLPFilter)) {
|
if (sourceAnimation.filters[i].swayLPFilter) {
|
||||||
targetAnimation.filters[i].swayLPFilter = sourceAnimation.filters[i].swayLPFilter;
|
targetAnimation.filters[i].swayLPFilter = sourceAnimation.filters[i].swayLPFilter;
|
||||||
}
|
}
|
||||||
if (isDefined(sourceAnimation.filters[i].bobLPFilter)) {
|
if (sourceAnimation.filters[i].bobLPFilter) {
|
||||||
targetAnimation.filters[i].bobLPFilter = sourceAnimation.filters[i].bobLPFilter;
|
targetAnimation.filters[i].bobLPFilter = sourceAnimation.filters[i].bobLPFilter;
|
||||||
}
|
}
|
||||||
if (isDefined(sourceAnimation.filters[i].thrustLPFilter)) {
|
if (sourceAnimation.filters[i].thrustLPFilter) {
|
||||||
targetAnimation.filters[i].thrustLPFilter = sourceAnimation.filters[i].thrustLPFilter;
|
targetAnimation.filters[i].thrustLPFilter = sourceAnimation.filters[i].thrustLPFilter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -618,6 +674,11 @@ TransitionParameters = function() {
|
||||||
this.reachPoseNames = [];
|
this.reachPoseNames = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QUARTER_CYCLE = 90;
|
||||||
|
const HALF_CYCLE = 180;
|
||||||
|
const THREE_QUARTER_CYCLE = 270;
|
||||||
|
const FULL_CYCLE = 360;
|
||||||
|
|
||||||
// constructor for animation Transition
|
// constructor for animation Transition
|
||||||
Transition = function(nextAnimation, lastAnimation, lastTransition, playTransitionReachPoses) {
|
Transition = function(nextAnimation, lastAnimation, lastTransition, playTransitionReachPoses) {
|
||||||
|
|
||||||
|
@ -645,7 +706,7 @@ Transition = function(nextAnimation, lastAnimation, lastTransition, playTransiti
|
||||||
// set parameters for the transition
|
// set parameters for the transition
|
||||||
this.parameters = new TransitionParameters();
|
this.parameters = new TransitionParameters();
|
||||||
this.liveReachPoses = [];
|
this.liveReachPoses = [];
|
||||||
if (walkAssets && isDefined(lastAnimation) && isDefined(nextAnimation)) {
|
if (walkAssets && lastAnimation && nextAnimation) {
|
||||||
// overwrite this.parameters with any transition parameters specified for this particular transition
|
// overwrite this.parameters with any transition parameters specified for this particular transition
|
||||||
walkAssets.getTransitionParameters(lastAnimation, nextAnimation, this.parameters);
|
walkAssets.getTransitionParameters(lastAnimation, nextAnimation, this.parameters);
|
||||||
// fire up any reach poses for this transition
|
// fire up any reach poses for this transition
|
||||||
|
@ -661,11 +722,10 @@ Transition = function(nextAnimation, lastAnimation, lastTransition, playTransiti
|
||||||
|
|
||||||
// coming to a halt whilst walking? if so, will need a clean stopping point defined
|
// coming to a halt whilst walking? if so, will need a clean stopping point defined
|
||||||
if (motion.isComingToHalt) {
|
if (motion.isComingToHalt) {
|
||||||
var FULL_CYCLE = 360;
|
|
||||||
var FULL_CYCLE_THRESHOLD = 320;
|
const FULL_CYCLE_THRESHOLD = 320;
|
||||||
var HALF_CYCLE = 180;
|
const HALF_CYCLE_THRESHOLD = 140;
|
||||||
var HALF_CYCLE_THRESHOLD = 140;
|
const CYCLE_COMMIT_THRESHOLD = 5;
|
||||||
var CYCLE_COMMIT_THRESHOLD = 5;
|
|
||||||
|
|
||||||
// how many degrees do we need to turn the walk wheel to finish walking with both feet on the ground?
|
// how many degrees do we need to turn the walk wheel to finish walking with both feet on the ground?
|
||||||
if (this.lastElapsedFTDegrees < CYCLE_COMMIT_THRESHOLD) {
|
if (this.lastElapsedFTDegrees < CYCLE_COMMIT_THRESHOLD) {
|
||||||
|
@ -691,7 +751,8 @@ Transition = function(nextAnimation, lastAnimation, lastTransition, playTransiti
|
||||||
// transition length in this case should be directly proportional to the remaining degrees to turn
|
// transition length in this case should be directly proportional to the remaining degrees to turn
|
||||||
var MIN_FT_INCREMENT = 5.0; // degrees per frame
|
var MIN_FT_INCREMENT = 5.0; // degrees per frame
|
||||||
var MIN_TRANSITION_DURATION = 0.4;
|
var MIN_TRANSITION_DURATION = 0.4;
|
||||||
this.lastFrequencyTimeIncrement *= 0.66; // help ease the transition
|
const TWO_THIRDS = 0.6667;
|
||||||
|
this.lastFrequencyTimeIncrement *= TWO_THIRDS; // help ease the transition
|
||||||
var lastFrequencyTimeIncrement = this.lastFrequencyTimeIncrement > MIN_FT_INCREMENT ?
|
var lastFrequencyTimeIncrement = this.lastFrequencyTimeIncrement > MIN_FT_INCREMENT ?
|
||||||
this.lastFrequencyTimeIncrement : MIN_FT_INCREMENT;
|
this.lastFrequencyTimeIncrement : MIN_FT_INCREMENT;
|
||||||
var timeToFinish = Math.max(motion.deltaTime * this.degreesToTurn / lastFrequencyTimeIncrement,
|
var timeToFinish = Math.max(motion.deltaTime * this.degreesToTurn / lastFrequencyTimeIncrement,
|
||||||
|
@ -719,7 +780,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
|
||||||
|
@ -727,20 +788,20 @@ 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;
|
||||||
if (motion.isComingToHalt) {
|
if (motion.isComingToHalt) {
|
||||||
if (this.lastFrequencyTimeWheelPos < 90) {
|
if (this.lastFrequencyTimeWheelPos < QUARTER_CYCLE) {
|
||||||
this.lastFrequencyTimeWheelPos = 0;
|
this.lastFrequencyTimeWheelPos = 0;
|
||||||
} else {
|
} else {
|
||||||
this.lastFrequencyTimeWheelPos = 180;
|
this.lastFrequencyTimeWheelPos = HALF_CYCLE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
wheelAdvance = this.lastFrequencyTimeIncrement;
|
wheelAdvance = this.lastFrequencyTimeIncrement;
|
||||||
var distanceToTravel = avatar.calibration.strideLength * wheelAdvance / 180;
|
var distanceToTravel = avatar.calibration.strideLength * wheelAdvance / HALF_CYCLE;
|
||||||
if (this.degreesRemaining <= 0) {
|
if (this.degreesRemaining <= 0) {
|
||||||
distanceToTravel = 0;
|
distanceToTravel = 0;
|
||||||
this.degreesRemaining = 0;
|
this.degreesRemaining = 0;
|
||||||
|
@ -754,8 +815,8 @@ Transition = function(nextAnimation, lastAnimation, lastTransition, playTransiti
|
||||||
|
|
||||||
// advance the ft wheel
|
// advance the ft wheel
|
||||||
this.lastFrequencyTimeWheelPos += wheelAdvance;
|
this.lastFrequencyTimeWheelPos += wheelAdvance;
|
||||||
if (this.lastFrequencyTimeWheelPos >= 360) {
|
if (this.lastFrequencyTimeWheelPos >= FULL_CYCLE) {
|
||||||
this.lastFrequencyTimeWheelPos = this.lastFrequencyTimeWheelPos % 360;
|
this.lastFrequencyTimeWheelPos = this.lastFrequencyTimeWheelPos % FULL_CYCLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// advance ft wheel for the nested (previous) Transition
|
// advance ft wheel for the nested (previous) Transition
|
||||||
|
@ -768,9 +829,11 @@ Transition = function(nextAnimation, lastAnimation, lastTransition, playTransiti
|
||||||
};
|
};
|
||||||
|
|
||||||
this.updateProgress = function() {
|
this.updateProgress = function() {
|
||||||
var elapasedTime = (new Date().getTime() - this.startTime) / 1000;
|
const MILLISECONDS_CONVERT = 1000;
|
||||||
|
const ACCURACY_INCREASER = 1000;
|
||||||
|
var elapasedTime = (new Date().getTime() - this.startTime) / MILLISECONDS_CONVERT;
|
||||||
this.progress = elapasedTime / this.parameters.duration;
|
this.progress = elapasedTime / this.parameters.duration;
|
||||||
this.progress = Math.round(this.progress * 1000) / 1000;
|
this.progress = Math.round(this.progress * ACCURACY_INCREASER) / ACCURACY_INCREASER;
|
||||||
|
|
||||||
// updated nested transition/s
|
// updated nested transition/s
|
||||||
if (this.lastTransition !== nullTransition) {
|
if (this.lastTransition !== nullTransition) {
|
||||||
|
@ -792,6 +855,7 @@ 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -896,23 +960,23 @@ FrequencyMultipliers = function(joint, direction) {
|
||||||
this.bobFrequencyMultiplier = 1;
|
this.bobFrequencyMultiplier = 1;
|
||||||
this.thrustFrequencyMultiplier = 1;
|
this.thrustFrequencyMultiplier = 1;
|
||||||
|
|
||||||
if (isDefined(joint)) {
|
if (joint) {
|
||||||
if (isDefined(joint.pitchFrequencyMultiplier)) {
|
if (joint.pitchFrequencyMultiplier) {
|
||||||
this.pitchFrequencyMultiplier = joint.pitchFrequencyMultiplier;
|
this.pitchFrequencyMultiplier = joint.pitchFrequencyMultiplier;
|
||||||
}
|
}
|
||||||
if (isDefined(joint.yawFrequencyMultiplier)) {
|
if (joint.yawFrequencyMultiplier) {
|
||||||
this.yawFrequencyMultiplier = joint.yawFrequencyMultiplier;
|
this.yawFrequencyMultiplier = joint.yawFrequencyMultiplier;
|
||||||
}
|
}
|
||||||
if (isDefined(joint.rollFrequencyMultiplier)) {
|
if (joint.rollFrequencyMultiplier) {
|
||||||
this.rollFrequencyMultiplier = joint.rollFrequencyMultiplier;
|
this.rollFrequencyMultiplier = joint.rollFrequencyMultiplier;
|
||||||
}
|
}
|
||||||
if (isDefined(joint.swayFrequencyMultiplier)) {
|
if (joint.swayFrequencyMultiplier) {
|
||||||
this.swayFrequencyMultiplier = joint.swayFrequencyMultiplier;
|
this.swayFrequencyMultiplier = joint.swayFrequencyMultiplier;
|
||||||
}
|
}
|
||||||
if (isDefined(joint.bobFrequencyMultiplier)) {
|
if (joint.bobFrequencyMultiplier) {
|
||||||
this.bobFrequencyMultiplier = joint.bobFrequencyMultiplier;
|
this.bobFrequencyMultiplier = joint.bobFrequencyMultiplier;
|
||||||
}
|
}
|
||||||
if (isDefined(joint.thrustFrequencyMultiplier)) {
|
if (joint.thrustFrequencyMultiplier) {
|
||||||
this.thrustFrequencyMultiplier = joint.thrustFrequencyMultiplier;
|
this.thrustFrequencyMultiplier = joint.thrustFrequencyMultiplier;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
// walkFilters.js
|
// walkFilters.js
|
||||||
// version 1.1
|
// version 1.1
|
||||||
//
|
//
|
||||||
// Created by David Wooldridge, June 2015
|
// Created by David Wooldridge, Autumn 2014
|
||||||
// Copyright © 2014 - 2015 High Fidelity, Inc.
|
// Copyright © 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+
|
||||||
//
|
//
|
||||||
|
@ -118,6 +118,7 @@ WaveSynth = function(waveShape, numHarmonics, smoothing) {
|
||||||
HarmonicsFilter = function(magnitudes, phaseAngles) {
|
HarmonicsFilter = function(magnitudes, phaseAngles) {
|
||||||
this.magnitudes = magnitudes;
|
this.magnitudes = magnitudes;
|
||||||
this.phaseAngles = phaseAngles;
|
this.phaseAngles = phaseAngles;
|
||||||
|
|
||||||
this.calculate = function(twoPiFT) {
|
this.calculate = function(twoPiFT) {
|
||||||
var harmonics = 0;
|
var harmonics = 0;
|
||||||
var numHarmonics = magnitudes.length;
|
var numHarmonics = magnitudes.length;
|
||||||
|
@ -130,6 +131,9 @@ HarmonicsFilter = function(magnitudes, phaseAngles) {
|
||||||
|
|
||||||
// the main filter object literal
|
// the main filter object literal
|
||||||
filter = (function() {
|
filter = (function() {
|
||||||
|
|
||||||
|
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};
|
||||||
|
@ -144,17 +148,17 @@ filter = (function() {
|
||||||
|
|
||||||
// helper methods
|
// helper methods
|
||||||
degToRad: function(degrees) {
|
degToRad: function(degrees) {
|
||||||
var convertedValue = degrees * Math.PI / 180;
|
var convertedValue = degrees * Math.PI / HALF_CYCLE;
|
||||||
return convertedValue;
|
return convertedValue;
|
||||||
},
|
},
|
||||||
|
|
||||||
radToDeg: function(radians) {
|
radToDeg: function(radians) {
|
||||||
var convertedValue = radians * 180 / Math.PI;
|
var convertedValue = radians * HALF_CYCLE / Math.PI;
|
||||||
return convertedValue;
|
return convertedValue;
|
||||||
},
|
},
|
||||||
|
|
||||||
// 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);
|
||||||
|
@ -180,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/
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
//
|
//
|
||||||
// walkSettings.js
|
// walkSettings.js
|
||||||
// version 1.0
|
// version 0.1
|
||||||
//
|
//
|
||||||
// Created by David Wooldridge, June 2015
|
// Created by David Wooldridge, Summer 2015
|
||||||
// Copyright © 2015 High Fidelity, Inc.
|
// Copyright © 2015 High Fidelity, Inc.
|
||||||
//
|
//
|
||||||
// Presents settings for walk.js
|
// Presents settings for walk.js
|
||||||
|
@ -14,52 +14,83 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
WalkSettings = function() {
|
WalkSettings = function() {
|
||||||
var that = {};
|
var _visible = false;
|
||||||
|
|
||||||
// ui minimised tab
|
|
||||||
var _innerWidth = Window.innerWidth;
|
var _innerWidth = Window.innerWidth;
|
||||||
var visible = false;
|
const MARGIN_RIGHT = 58;
|
||||||
var _minimisedTab = Overlays.addOverlay("image", {
|
const MARGIN_TOP = 145;
|
||||||
x: _innerWidth - 58, y: Window.innerHeight - 145,
|
const ICON_SIZE = 50;
|
||||||
width: 50, height: 50,
|
const ICON_ALPHA = 0.9;
|
||||||
|
|
||||||
|
var minimisedTab = Overlays.addOverlay("image", {
|
||||||
|
x: _innerWidth - MARGIN_RIGHT, y: Window.innerHeight - MARGIN_TOP,
|
||||||
|
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: 0.9
|
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;
|
||||||
webView.setVisible(visible);
|
_webView.setVisible(_visible);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Controller.mousePressEvent.connect(mousePressEvent);
|
Controller.mousePressEvent.connect(mousePressEvent);
|
||||||
function cleanup() {
|
|
||||||
Overlays.deleteOverlay(_minimisedTab);
|
Script.update.connect(function(deltaTime) {
|
||||||
}
|
if (window.innerWidth !== _innerWidth) {
|
||||||
Script.update.connect(function() {
|
_innerWidth = window.innerWidth;
|
||||||
|
Overlays.EditOverlay(minimisedTab, {x: _innerWidth - MARGIN_RIGHT});
|
||||||
if (_innerWidth !== Window.innerWidth) {
|
|
||||||
_innerWidth = Window.innerWidth;
|
|
||||||
Overlays.editOverlay(_minimisedTab, {x: _innerWidth - 58});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function cleanup() {
|
||||||
|
Overlays.deleteOverlay(minimisedTab);
|
||||||
|
}
|
||||||
Script.scriptEnding.connect(cleanup);
|
Script.scriptEnding.connect(cleanup);
|
||||||
|
|
||||||
|
var _control = false;
|
||||||
|
var _shift = false;
|
||||||
|
function keyPressEvent(event) {
|
||||||
|
if (event.text === "CONTROL") {
|
||||||
|
_control = true;
|
||||||
|
}
|
||||||
|
if (event.text === "SHIFT") {
|
||||||
|
_shift = true;
|
||||||
|
}
|
||||||
|
if (_shift && (event.text === 'o' || event.text === 'O')) {
|
||||||
|
_visible = !_visible;
|
||||||
|
_webView.setVisible(_visible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function keyReleaseEvent(event) {
|
||||||
|
if (event.text === "CONTROL") {
|
||||||
|
_control = false;
|
||||||
|
}
|
||||||
|
if (event.text === "SHIFT") {
|
||||||
|
_shift = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Controller.keyPressEvent.connect(keyPressEvent);
|
||||||
|
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
||||||
|
|
||||||
// web window
|
// web window
|
||||||
var url = Script.resolvePath('html/walkSettings.html');
|
var _url = Script.resolvePath('html/walkSettings.html');
|
||||||
var webView = new WebWindow('Walk Settings', url, 200, 180, false);
|
const PANEL_WIDTH = 200;
|
||||||
webView.setVisible(false);
|
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) {
|
_webView.eventBridge.webEventReceived.connect(function(data) {
|
||||||
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 dialog
|
||||||
webView.eventBridge.emitScriptEvent(JSON.stringify({
|
_webView.eventBridge.emitScriptEvent(JSON.stringify({
|
||||||
type: "update",
|
type: "update",
|
||||||
armsFree: avatar.armsFree,
|
armsFree: avatar.armsFree,
|
||||||
footstepSounds: avatar.makesFootStepSounds,
|
footstepSounds: avatar.makesFootStepSounds,
|
||||||
blenderPreRotations: avatar.isBlenderExport
|
blenderPreRotations: avatar.isBlenderExport
|
||||||
}));
|
}));
|
||||||
} 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") {
|
||||||
|
@ -69,6 +100,6 @@ WalkSettings = function() {
|
||||||
avatar.isBlenderExport = data.blenderPreRotations;
|
avatar.isBlenderExport = data.blenderPreRotations;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return that;
|
walkSettings = WalkSettings();
|
||||||
};
|
|
154
examples/walk.js
154
examples/walk.js
|
@ -2,11 +2,11 @@
|
||||||
// walk.js
|
// walk.js
|
||||||
// version 1.25
|
// version 1.25
|
||||||
//
|
//
|
||||||
// Created by David Wooldridge, June 2015
|
// Created by David Wooldridge, May 2015
|
||||||
// Copyright © 2014 - 2015 High Fidelity, Inc.
|
// Copyright © 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.
|
||||||
|
@ -33,30 +33,12 @@ var TRIANGLE = 2;
|
||||||
var SQUARE = 4;
|
var SQUARE = 4;
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
var MOVE_THRESHOLD = 0.075;
|
const MAX_WALK_SPEED = 2.9; // peak, by observation
|
||||||
var MAX_WALK_SPEED = 2.9; // peak, by observation
|
const MAX_FT_WHEEL_INCREMENT = 25; // avoid fast walk when landing
|
||||||
var MAX_FT_WHEEL_INCREMENT = 25; // avoid fast walk when landing
|
const TOP_SPEED = 300;
|
||||||
var TOP_SPEED = 300;
|
const ON_SURFACE_THRESHOLD = 0.1; // height above surface to be considered as on the surface
|
||||||
var ACCELERATION_THRESHOLD = 0.2; // detect stop to walking
|
const TRANSITION_COMPLETE = 1000;
|
||||||
var DECELERATION_THRESHOLD = -6; // detect walking to stop
|
const HIFI_PUBLIC_BUCKET = "https://hifi-public.s3.amazonaws.com/";
|
||||||
var FAST_DECELERATION_THRESHOLD = -150; // detect flying to stop
|
|
||||||
var BOUNCE_ACCELERATION_THRESHOLD = 25; // used to ignore gravity influence fluctuations after landing
|
|
||||||
var GRAVITY_THRESHOLD = 3.0; // height above surface where gravity is in effect
|
|
||||||
var OVERCOME_GRAVITY_SPEED = 0.5; // reaction sensitivity to jumping under gravity
|
|
||||||
var LANDING_THRESHOLD = 0.35; // metres from a surface below which need to prepare for impact
|
|
||||||
var ON_SURFACE_THRESHOLD = 0.1; // height above surface to be considered as on the surface
|
|
||||||
var MAX_TRANSITION_RECURSION = 10; // how many nested transitions are permitted
|
|
||||||
var TRANSITION_COMPLETE = 1000;
|
|
||||||
var HIFI_PUBLIC_BUCKET = "https://hifi-public.s3.amazonaws.com/";
|
|
||||||
|
|
||||||
// check for existence of data file object property
|
|
||||||
function isDefined(value) {
|
|
||||||
try {
|
|
||||||
if (typeof value != 'undefined') return true;
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// path to animations, reach-poses, reachPoses, transitions, overlay images and reference files
|
// path to animations, reach-poses, reachPoses, transitions, overlay images and reference files
|
||||||
var pathToAssets = HIFI_PUBLIC_BUCKET + "procedural-animator/assets/";
|
var pathToAssets = HIFI_PUBLIC_BUCKET + "procedural-animator/assets/";
|
||||||
|
@ -67,13 +49,12 @@ 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();
|
||||||
|
|
||||||
// create settings dialog
|
// create settings dialog
|
||||||
Script.include("./libraries/walkSettings.js");
|
Script.include("./libraries/walkSettings.js");
|
||||||
var walkSettings = WalkSettings();
|
|
||||||
|
|
||||||
// create and initialise Transition
|
// create and initialise Transition
|
||||||
var nullTransition = new Transition();
|
var nullTransition = new Transition();
|
||||||
|
@ -92,14 +73,14 @@ 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);
|
||||||
|
|
||||||
// decide which animation should be playing
|
// decide which animation should be playing
|
||||||
selectAnimation();
|
selectAnimation();
|
||||||
|
|
||||||
// turn the frequency time wheels. determine stride length
|
// turn the frequency time wheels and determine stride length
|
||||||
determineStride();
|
determineStride();
|
||||||
|
|
||||||
// update the progress of any live transitions
|
// update the progress of any live transitions
|
||||||
|
@ -109,7 +90,7 @@ Script.update.connect(function(deltaTime) {
|
||||||
renderMotion();
|
renderMotion();
|
||||||
|
|
||||||
// record this frame's parameters
|
// record this frame's parameters
|
||||||
motion.saveHistory();
|
motion.saveHistory();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -117,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 (isDefined(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;
|
||||||
|
|
||||||
|
@ -156,29 +137,27 @@ 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);
|
||||||
}
|
}
|
||||||
if (motion.state !== STATIC) {
|
motion.state = STATIC;
|
||||||
motion.state = STATIC;
|
|
||||||
}
|
|
||||||
avatar.selectedWalkBlend.lastDirection = NONE;
|
avatar.selectedWalkBlend.lastDirection = NONE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
@ -186,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;
|
||||||
|
@ -203,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);
|
||||||
|
@ -211,13 +190,11 @@ 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);
|
||||||
}
|
}
|
||||||
if (motion.state !== SURFACE_MOTION) {
|
motion.state = SURFACE_MOTION;
|
||||||
motion.state = SURFACE_MOTION;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,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;
|
||||||
|
@ -248,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,9 +251,7 @@ function selectAnimation() {
|
||||||
if (avatar.currentAnimation !== avatar.selectedFlyBlend) {
|
if (avatar.currentAnimation !== avatar.selectedFlyBlend) {
|
||||||
setTransition(avatar.selectedFlyBlend, playTransitionReachPoses);
|
setTransition(avatar.selectedFlyBlend, playTransitionReachPoses);
|
||||||
}
|
}
|
||||||
if (motion.state !== AIR_MOTION) {
|
motion.state = AIR_MOTION;
|
||||||
motion.state = AIR_MOTION;
|
|
||||||
}
|
|
||||||
avatar.selectedWalkBlend.lastDirection = NONE;
|
avatar.selectedWalkBlend.lastDirection = NONE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -299,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) {
|
||||||
|
@ -316,25 +291,25 @@ 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)
|
||||||
var JUST_UNDER_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 > JUST_UNDER_ONE)) {
|
(Vec3.length(motion.velocity) / MAX_WALK_SPEED > ALMOST_ONE)) {
|
||||||
|
|
||||||
var strideMaxAt = avatar.currentAnimation.calibration.strideMaxAt;
|
var strideMaxAt = avatar.currentAnimation.calibration.strideMaxAt;
|
||||||
var tolerance = 1.0;
|
const TOLERANCE = 1.0;
|
||||||
|
|
||||||
if (motion.frequencyTimeWheelPos < (strideMaxAt + tolerance) &&
|
if (motion.frequencyTimeWheelPos < (strideMaxAt + TOLERANCE) &&
|
||||||
motion.frequencyTimeWheelPos > (strideMaxAt - tolerance) &&
|
motion.frequencyTimeWheelPos > (strideMaxAt - TOLERANCE) &&
|
||||||
motion.currentTransition === nullTransition) {
|
motion.currentTransition === nullTransition) {
|
||||||
// measure and save stride length
|
// measure and save stride length
|
||||||
var footRPos = MyAvatar.getJointPosition("RightFoot");
|
var footRPos = MyAvatar.getJointPosition("RightFoot");
|
||||||
|
@ -363,6 +338,7 @@ function updateTransitions() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// update the Transition progress
|
||||||
if (motion.currentTransition.updateProgress() === TRANSITION_COMPLETE) {
|
if (motion.currentTransition.updateProgress() === TRANSITION_COMPLETE) {
|
||||||
motion.currentTransition = nullTransition;
|
motion.currentTransition = nullTransition;
|
||||||
}
|
}
|
||||||
|
@ -372,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) {
|
||||||
|
@ -387,9 +363,10 @@ function getLeanPitch() {
|
||||||
function getLeanRoll() {
|
function getLeanRoll() {
|
||||||
var leanRollProgress = 0;
|
var leanRollProgress = 0;
|
||||||
var linearContribution = 0;
|
var linearContribution = 0;
|
||||||
|
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) + 8) / 8;
|
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) / motion.calibration.DELTA_YAW_MAX;
|
||||||
leanRollProgress = linearContribution;
|
leanRollProgress = linearContribution;
|
||||||
|
@ -398,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;
|
||||||
|
@ -432,6 +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;
|
||||||
|
@ -444,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) {
|
||||||
|
@ -452,14 +430,17 @@ function renderMotion() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (producingFootstepSounds) {
|
if (producingFootstepSounds) {
|
||||||
|
const QUARTER_CYCLE = 90;
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
if (avatar.nextStep === LEFT && ftWheelPosition > 270) {
|
if (avatar.nextStep === LEFT && ftWheelPosition > THREE_QUARTER_CYCLE) {
|
||||||
avatar.makeFootStepSound();
|
avatar.makeFootStepSound();
|
||||||
} else if (avatar.nextStep === RIGHT && (ftWheelPosition < 270 && ftWheelPosition > 90)) {
|
} else if (avatar.nextStep === RIGHT && (ftWheelPosition < THREE_QUARTER_CYCLE && ftWheelPosition > QUARTER_CYCLE)) {
|
||||||
avatar.makeFootStepSound();
|
avatar.makeFootStepSound();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -469,15 +450,15 @@ function renderMotion() {
|
||||||
var joint = walkAssets.animationReference.joints[jointName];
|
var joint = walkAssets.animationReference.joints[jointName];
|
||||||
var jointRotations = undefined;
|
var jointRotations = undefined;
|
||||||
|
|
||||||
// ignore arms / head rotations if avatar options are selected
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there's a live transition, blend rotations with the last animation's rotations
|
// if there's a live transition, blend the rotations with the last animation's rotations
|
||||||
if (motion.currentTransition !== nullTransition) {
|
if (motion.currentTransition !== nullTransition) {
|
||||||
jointRotations = motion.currentTransition.blendRotations(jointName,
|
jointRotations = motion.currentTransition.blendRotations(jointName,
|
||||||
motion.frequencyTimeWheelPos,
|
motion.frequencyTimeWheelPos,
|
||||||
|
@ -488,12 +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));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue