From 38f0bc9f8df06b8e5f4a2c60419aad18de3e4f2c Mon Sep 17 00:00:00 2001 From: DaveDubUK Date: Thu, 2 Oct 2014 07:47:20 +0100 Subject: [PATCH] Adding followThroughOverlappingAction script The purpose of this project is to validate the principles of animation into a procedural animation script. To test the theory, we implemented a simple procedural arm swing animation that is both realtime and that incorporates Disney's principles of animation (principle of Overlapping Action and Follow Through). When applied to the arm swing, the principles make the shoulder rotation lead the elbow rotation which will lead the wrist rotation. Doing so results in an organic and life-like effect. --- examples/followThroughOverlappingAction.js | 398 +++++++++++++++++++++ 1 file changed, 398 insertions(+) create mode 100644 examples/followThroughOverlappingAction.js diff --git a/examples/followThroughOverlappingAction.js b/examples/followThroughOverlappingAction.js new file mode 100644 index 0000000000..6ae910fa77 --- /dev/null +++ b/examples/followThroughOverlappingAction.js @@ -0,0 +1,398 @@ + // +// follow-through-and-overlapping-action.js +// +// Simple demonstration showing the visual effect of adding the +// follow through and overlapping action technique to avatar movement. +// +// Designed and created by Ozan Serim and Davedub, August 2014 +// +// Version 1.0 +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +// always at the top... +var pathToOverlays = "https://s3-us-west-1.amazonaws.com/highfidelity-public/ArmSwingScript/ArmSwingOverlays/"; + +// animation +var LEFT = 1; +var RIGHT = 2; +var DIRECTION = 0; + +// animation effect variables +var handEffect = 3.4; // 0 to jointEffectMax +var forearmEffect = 2.5; // 0 to jointEffectMax +var limbWeight = 8; // will only use nearest integer, as defines an array length +var effectStrength = 1; // 0 to 1 - overall effect strength +var overShoot = false; // false uses upper arm as driver for forearm and hand, true uses upper arm for forearm and lower arm as driver for hand. + +// min max +var weightMin = 1; +var weightMax = 20; +var jointEffectMax = 5; + +// animate self (tap the 'r' key) +var animateSelf = false; +var selfAnimateFrequency = 7.5; + +// overlay values +var handleValue = 0; +var controlPosX = Window.innerWidth/2 - 500; +var controlPosY = 0; +var minSliderX = controlPosX+18; +var sliderRangeX = 190; +var minHandleX = controlPosX-50; +var handleRangeX = 350/2; +var handlePosition = 0; + +// background overlay +var controllerBackground = Overlays.addOverlay("image", { + bounds: { x: controlPosX, y: controlPosY, width: 250, height: 380}, + imageURL: pathToOverlays+"flourish-augmentation-control-overlay.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +var controllerRadioSelectedBackground = Overlays.addOverlay("image", { + bounds: { x: controlPosX, y: controlPosY, width: 250, height: 380}, + imageURL: pathToOverlays+"flourish-augmentation-control-radio-selected-overlay.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1, + visible: false + }); +// handle overlay +var applyMotionHandle = Overlays.addOverlay("image", { + bounds: { x: minHandleX+handleRangeX-39, y: controlPosY+232, width: 79, height: 100}, + imageURL: pathToOverlays+"flourish-augmentation-handle-overlay.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +// slider overlays +var handEffectSlider = Overlays.addOverlay("image", { + bounds: { x: minSliderX + (handEffect / jointEffectMax * sliderRangeX), y: controlPosY+46, width: 25, height: 25}, + imageURL: pathToOverlays+"ddao-slider-handle.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +var forearmEffectSlider = Overlays.addOverlay("image", { + bounds: { x: minSliderX + (forearmEffect / jointEffectMax * sliderRangeX), y: controlPosY+86, width: 25, height: 25}, + imageURL: pathToOverlays+"ddao-slider-handle.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +var limbWeightSlider = Overlays.addOverlay("image", { + bounds: { x: minSliderX + (limbWeight / weightMax * sliderRangeX), y: controlPosY+126, width: 25, height: 25}, + imageURL: pathToOverlays+"ddao-slider-handle.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); +var effectStrengthSlider = Overlays.addOverlay("image", { + bounds: { x: minSliderX + (effectStrength * sliderRangeX), y: controlPosY+206, width: 25, height: 25}, + imageURL: pathToOverlays+"ddao-slider-handle.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); + + +// main loop - using averaging filters to add limb element follow-through +var upperArmPDampingFilter = []; +upperArmPDampingFilter.length = parseInt(limbWeight); // sets amount of damping for upper arm pitch +var forearmPDampingFilter = []; +forearmPDampingFilter.length = parseInt(limbWeight) + 2; // sets amount of damping for lower arm pitch + +var cumulativeTime = 0; + +Script.update.connect(function(deltaTime) { + + // used for self animating (press r to invoke) + cumulativeTime += deltaTime; + + // blend three keyframes using handle position to determine progress between keyframes + var animationProgress = handleValue; + + if(animateSelf) { + animationProgress = Math.sin(cumulativeTime * selfAnimateFrequency); + animationProgress++; + animationProgress/=2; + } + + var keyframeOneWeight = 0; + var keyframeTwoWeight = 0; + var keyframeThreeWeight = 0; + + if(movingHandle || animateSelf) { + keyframeOneWeight = 0; + keyframeTwoWeight = animationProgress; + keyframeThreeWeight = 1-animationProgress; + } + else if(!movingHandle) { + // idle + keyframeOneWeight = 1; + keyframeTwoWeight = 0; + keyframeThreeWeight = 0; + } + + var shoulderPitch = + keyframeOneWeight * keyFrameOne.joints[8].pitchOffset + + keyframeTwoWeight * keyFrameTwo.joints[8].pitchOffset + + keyframeThreeWeight * keyFrameThree.joints[8].pitchOffset; + + var upperArmPitch = + keyframeOneWeight * keyFrameOne.joints[9].pitchOffset + + keyframeTwoWeight * keyFrameTwo.joints[9].pitchOffset + + keyframeThreeWeight * keyFrameThree.joints[9].pitchOffset; + + // get the change in upper arm pitch and use to add weight effect to forearm (always) and hand (only for overShoot 1) + var deltaUpperArmPitch = effectStrength * (upperArmPDampingFilter[upperArmPDampingFilter.length-1] - upperArmPDampingFilter[0]); + + var forearmPitch = + keyframeOneWeight * keyFrameOne.joints[10].pitchOffset + + keyframeTwoWeight * keyFrameTwo.joints[10].pitchOffset + + keyframeThreeWeight * keyFrameThree.joints[10].pitchOffset - + (deltaUpperArmPitch/(jointEffectMax - forearmEffect)); + + // there are two methods for calculating the hand follow through + var handPitch = 0; + if(overShoot) { + // get the change in forearm pitch and use to add weight effect to hand + var deltaForearmPitch = effectStrength * (forearmPDampingFilter[forearmPDampingFilter.length-1] - forearmPDampingFilter[0]); + handPitch = + keyframeOneWeight * keyFrameOne.joints[11].pitchOffset + + keyframeTwoWeight * keyFrameTwo.joints[11].pitchOffset + + keyframeThreeWeight * keyFrameThree.joints[11].pitchOffset + + (deltaForearmPitch/(jointEffectMax - handEffect)); // driven by forearm + } else { + handPitch = + keyframeOneWeight * keyFrameOne.joints[11].pitchOffset + + keyframeTwoWeight * keyFrameTwo.joints[11].pitchOffset + + keyframeThreeWeight * keyFrameThree.joints[11].pitchOffset - + (deltaUpperArmPitch/(jointEffectMax - handEffect)); // driven by upper arm + } + + var shoulderYaw = + keyframeOneWeight * keyFrameOne.joints[8].yawOffset + + keyframeTwoWeight * keyFrameTwo.joints[8].yawOffset + + keyframeThreeWeight * keyFrameThree.joints[8].yawOffset; + + var upperArmYaw = + keyframeOneWeight * keyFrameOne.joints[9].yawOffset + + keyframeTwoWeight * keyFrameTwo.joints[9].yawOffset + + keyframeThreeWeight * keyFrameThree.joints[9].yawOffset; + + var lowerArmYaw = + keyframeOneWeight * keyFrameOne.joints[10].yawOffset + + keyframeTwoWeight * keyFrameTwo.joints[10].yawOffset + + keyframeThreeWeight * keyFrameThree.joints[10].yawOffset; + + var handYaw = + keyframeOneWeight * keyFrameOne.joints[11].yawOffset + + keyframeTwoWeight * keyFrameTwo.joints[11].yawOffset + + keyframeThreeWeight * keyFrameThree.joints[11].yawOffset; + + var shoulderRoll = + keyframeOneWeight * keyFrameOne.joints[8].rollOffset + + keyframeTwoWeight * keyFrameTwo.joints[8].rollOffset + + keyframeThreeWeight * keyFrameThree.joints[8].rollOffset; + + var upperArmRoll = + keyframeOneWeight * keyFrameOne.joints[9].rollOffset + + keyframeTwoWeight * keyFrameTwo.joints[9].rollOffset + + keyframeThreeWeight * keyFrameThree.joints[9].rollOffset; + + var lowerArmRoll = + keyframeOneWeight * keyFrameOne.joints[10].rollOffset + + keyframeTwoWeight * keyFrameTwo.joints[10].rollOffset + + keyframeThreeWeight * keyFrameThree.joints[10].rollOffset; + + var handRoll = + keyframeOneWeight * keyFrameOne.joints[11].rollOffset + + keyframeTwoWeight * keyFrameTwo.joints[11].rollOffset + + keyframeThreeWeight * keyFrameThree.joints[11].rollOffset; + + // filter upper arm pitch + upperArmPDampingFilter.push(upperArmPitch); + upperArmPDampingFilter.shift(); + var upperArmPitchFiltered = 0; + for(ea in upperArmPDampingFilter) upperArmPitchFiltered += upperArmPDampingFilter[ea]; + upperArmPitchFiltered /= upperArmPDampingFilter.length; + upperArmPitch = (effectStrength*upperArmPitchFiltered) + ((1-(effectStrength)) * upperArmPitch); + + // filter forearm pitch only if using for hand follow-though + if(overShoot) { + forearmPDampingFilter.push(forearmPitch); + forearmPDampingFilter.shift(); + var forearmPitchFiltered = 0; + for(ea in forearmPDampingFilter) forearmPitchFiltered += forearmPDampingFilter[ea]; + forearmPitchFiltered /= forearmPDampingFilter.length; + forearmPitch = (effectStrength*forearmPitchFiltered) + ((1-(effectStrength)) * forearmPitch); + } + + // apply the new rotation data to the joints + MyAvatar.setJointData("RightShoulder", Quat.fromPitchYawRollDegrees( shoulderPitch, shoulderYaw, shoulderRoll)); + MyAvatar.setJointData("RightArm", Quat.fromPitchYawRollDegrees( upperArmPitch, -upperArmYaw, upperArmRoll)); + MyAvatar.setJointData("RightForeArm", Quat.fromPitchYawRollDegrees( forearmPitch, lowerArmYaw, lowerArmRoll)); + MyAvatar.setJointData("RightHand", Quat.fromPitchYawRollDegrees( handPitch, handYaw, handRoll)); +}); + + +// mouse handling +var movingHandEffectSlider = false; +var movingForearmEffectSlider = false; +var movingLimbWeightSlider = false; +var movingDampingSlider = false; +var movingEffectStrengthSlider = false; +var movingHandle = false; + +function mousePressEvent(event) { + + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + + if(clickedOverlay===applyMotionHandle) movingHandle = true; + else if(clickedOverlay===handEffectSlider) movingHandEffectSlider = true; + else if(clickedOverlay===forearmEffectSlider) movingForearmEffectSlider = true; + else if(clickedOverlay===limbWeightSlider) movingLimbWeightSlider = true; + else if(clickedOverlay===effectStrengthSlider) movingEffectStrengthSlider = true; + else if(clickedOverlay===controllerRadioSelectedBackground && + event.x>477&&event.x<497&&event.y>338&&event.y<360) { + overShoot = false; + Overlays.editOverlay(controllerBackground, {visible:true}); + Overlays.editOverlay(controllerRadioSelectedBackground, {visible:false}); + } + else if(clickedOverlay===controllerBackground && + event.x>477&&event.x<497&&event.y>338&&event.y<360){ + overShoot = true; + Overlays.editOverlay(controllerBackground, {visible:false}); + Overlays.editOverlay(controllerRadioSelectedBackground, {visible:true}); + } +} +function mouseMoveEvent(event) { + + if(movingHandle) { + var thumbClickOffsetX = event.x - minHandleX; + var thumbPositionNormalised = (thumbClickOffsetX - handleRangeX + 39) / handleRangeX; + if(thumbPositionNormalised<=-1) thumbPositionNormalised = -1; + else if(thumbPositionNormalised>1) thumbPositionNormalised = 1; + + if(thumbPositionNormalised<0) DIRECTION = LEFT; + else DIRECTION = RIGHT; + + handleValue = (thumbPositionNormalised+1)/2; + var handleX = (thumbPositionNormalised * handleRangeX) + handleRangeX - 39; // sets range + Overlays.editOverlay(applyMotionHandle, { x: handleX + minHandleX} ); + return; + } + else if(movingHandEffectSlider) { + var thumbClickOffsetX = event.x - minSliderX; + var thumbPositionNormalised = thumbClickOffsetX / sliderRangeX; + if(thumbPositionNormalised<0) thumbPositionNormalised = 0; + if(thumbPositionNormalised>1) thumbPositionNormalised = 1; + handEffect = (thumbPositionNormalised-0.08) * jointEffectMax; + var sliderX = thumbPositionNormalised * sliderRangeX ; // sets range + Overlays.editOverlay(handEffectSlider, { x: sliderX + minSliderX} ); + } + else if(movingForearmEffectSlider) { + var thumbClickOffsetX = event.x - minSliderX; + var thumbPositionNormalised = thumbClickOffsetX / sliderRangeX; + if(thumbPositionNormalised<0) thumbPositionNormalised = 0; + if(thumbPositionNormalised>1) thumbPositionNormalised = 1; + forearmEffect = (thumbPositionNormalised-0.1) * jointEffectMax; + var sliderX = thumbPositionNormalised * sliderRangeX ; // sets range + Overlays.editOverlay(forearmEffectSlider, { x: sliderX + minSliderX} ); + } + else if(movingLimbWeightSlider) { + var thumbClickOffsetX = event.x - minSliderX; + var thumbPositionNormalised = thumbClickOffsetX / sliderRangeX; + if(thumbPositionNormalised<0) thumbPositionNormalised = 0; + if(thumbPositionNormalised>1) thumbPositionNormalised = 1; + limbWeight = thumbPositionNormalised * weightMax; + if(limbWeight1) thumbPositionNormalised = 1; + effectStrength = thumbPositionNormalised; + var sliderX = thumbPositionNormalised * sliderRangeX ; // sets range + Overlays.editOverlay(effectStrengthSlider, { x: sliderX + minSliderX} ); + return; + } +} +function mouseReleaseEvent(event) { + + if(movingHandle) { + movingHandle = false; + handleValue = 0; + Overlays.editOverlay(applyMotionHandle, { x: minHandleX+handleRangeX-39} ); + } + else if(movingHandEffectSlider) movingHandEffectSlider = false; + else if(movingForearmEffectSlider) movingForearmEffectSlider = false; + else if(movingLimbWeightSlider) movingLimbWeightSlider = false; + else if(movingEffectStrengthSlider) movingEffectStrengthSlider = false; + else if(movingDampingSlider) movingDampingSlider = false; +} + +// set up mouse and keyboard callbacks +Controller.mouseMoveEvent.connect(mouseMoveEvent); +Controller.mousePressEvent.connect(mousePressEvent); +Controller.mouseReleaseEvent.connect(mouseReleaseEvent); +Controller.keyPressEvent.connect(keyPressEvent); + +// keyboard command +function keyPressEvent(event) { + + if (event.text == "q") { + print('hand effect = ' + handEffect + '\n'); + print('forearmEffect = ' + forearmEffect + '\n'); + print('limbWeight = ' + limbWeight + '\n'); + print('effectStrength = ' + effectStrength + '\n'); + } + else if (event.text == "r") { + animateSelf = !animateSelf; + } + else if (event.text == "[") { + selfAnimateFrequency+=0.5 + print('selfAnimateFrequency = '+selfAnimateFrequency); + } + else if (event.text == "]") { + selfAnimateFrequency-=0.5 + print('selfAnimateFrequency = '+selfAnimateFrequency); + } +} + + +// zero out all joints +function resetJoints() { + + var avatarJointNames = MyAvatar.getJointNames(); + for (var i = 0; i < avatarJointNames.length; i++) { + MyAvatar.clearJointData(avatarJointNames[i]); + } +} + +// Script ending +Script.scriptEnding.connect(function() { + + // delete the overlays + Overlays.deleteOverlay(controllerBackground); + Overlays.deleteOverlay(controllerRadioSelectedBackground); + Overlays.deleteOverlay(handEffectSlider); + Overlays.deleteOverlay(forearmEffectSlider); + Overlays.deleteOverlay(limbWeightSlider); + Overlays.deleteOverlay(effectStrengthSlider); + Overlays.deleteOverlay(applyMotionHandle); + + // leave the avi in zeroed out stance + resetJoints(); +}); + + +// animation / joint data. animation keyframes produced using davedub's procedural animation controller +MyAvatar.setJointData("LeftArm", Quat.fromPitchYawRollDegrees(80,0,0)); // stand nicely please +var keyFrameOne = {"name":"FemaleStandingOne","settings":{"baseFrequency":70,"flyingHipsPitch":60,"takeFlightVelocity":40,"maxBankingAngle":40},"adjusters":{"legsSeparation":{"strength":-0.03679245283018867,"separationAngle":50},"stride":{"strength":0,"upperLegsPitch":30,"lowerLegsPitch":15,"upperLegsPitchOffset":0.2,"lowerLegsPitchOffset":1.5}},"joints":[{"name":"hips","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0,"thrust":0,"bob":0,"sway":0,"thrustPhase":180,"bobPhase":0,"swayPhase":-90,"thrustOffset":0,"bobOffset":0,"swayOffset":0},{"name":"upperLegs","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"lowerLegs","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"feet","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"toes","pitch":2.0377358490566038,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":4.415094339622641,"yawOffset":0,"rollOffset":0},{"name":"spine","pitch":1.660377358490566,"yaw":0,"roll":0,"pitchPhase":-180,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"spine1","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"spine2","pitch":2.1132075471698113,"yaw":0,"roll":0,"pitchPhase":-0.6792452830188722,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"shoulders","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0.6792452830188678,"yawOffset":-5.20754716981132,"rollOffset":-2.9433962264150937},{"name":"upperArms","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":77.77358490566039,"yawOffset":9.169811320754715,"rollOffset":0},{"name":"lowerArms","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"hands","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":1.6981132075471694,"yawOffset":-1.0188679245283017,"rollOffset":1.0188679245283017},{"name":"head","pitch":0,"yaw":1.7358490566037734,"roll":1.5094339622641508,"pitchPhase":-90.33962264150944,"yawPhase":94.41509433962267,"rollPhase":0,"pitchOffset":1.6981132075471694,"yawOffset":0,"rollOffset":0}]}; +var keyFrameTwo = {"name":"FemaleStandingOne","settings":{"baseFrequency":70,"flyingHipsPitch":60,"takeFlightVelocity":40,"maxBankingAngle":40},"adjusters":{"legsSeparation":{"strength":-0.03679245283018867,"separationAngle":50},"stride":{"strength":0,"upperLegsPitch":30,"lowerLegsPitch":15,"upperLegsPitchOffset":0.2,"lowerLegsPitchOffset":1.5}},"joints":[{"name":"hips","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0,"thrust":0,"bob":0,"sway":0,"thrustPhase":180,"bobPhase":0,"swayPhase":-90,"thrustOffset":0,"bobOffset":0,"swayOffset":0},{"name":"upperLegs","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"lowerLegs","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"feet","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"toes","pitch":2.0377358490566038,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":4.415094339622641,"yawOffset":0,"rollOffset":0},{"name":"spine","pitch":1.660377358490566,"yaw":0,"roll":0,"pitchPhase":-180,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"spine1","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"spine2","pitch":2.1132075471698113,"yaw":0,"roll":0,"pitchPhase":-0.6792452830188722,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"shoulders","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0.6792452830188678,"yawOffset":-5.20754716981132,"rollOffset":-2.9433962264150937},{"name":"upperArms","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":49.584905660377345,"yawOffset":9.169811320754715,"rollOffset":0},{"name":"lowerArms","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"hands","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":-13,"yawOffset":-1.0188679245283017,"rollOffset":1.0188679245283017},{"name":"head","pitch":0,"yaw":1.7358490566037734,"roll":1.5094339622641508,"pitchPhase":-90.33962264150944,"yawPhase":94.41509433962267,"rollPhase":0,"pitchOffset":1.6981132075471694,"yawOffset":0,"rollOffset":0}]}; +var keyFrameThree = {"name":"FemaleStandingOne","settings":{"baseFrequency":70,"flyingHipsPitch":60,"takeFlightVelocity":40,"maxBankingAngle":40},"adjusters":{"legsSeparation":{"strength":-0.03679245283018867,"separationAngle":50},"stride":{"strength":0,"upperLegsPitch":30,"lowerLegsPitch":15,"upperLegsPitchOffset":0.2,"lowerLegsPitchOffset":1.5}},"joints":[{"name":"hips","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0,"thrust":0,"bob":0,"sway":0,"thrustPhase":180,"bobPhase":0,"swayPhase":-90,"thrustOffset":0,"bobOffset":0,"swayOffset":0},{"name":"upperLegs","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"lowerLegs","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"feet","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"toes","pitch":2.0377358490566038,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":4.415094339622641,"yawOffset":0,"rollOffset":0},{"name":"spine","pitch":1.660377358490566,"yaw":0,"roll":0,"pitchPhase":-180,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"spine1","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"spine2","pitch":2.1132075471698113,"yaw":0,"roll":0,"pitchPhase":-0.6792452830188722,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"shoulders","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":-21.0566037735849,"yawOffset":-5.20754716981132,"rollOffset":-2.9433962264150937},{"name":"upperArms","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":-33.28301886792452,"yawOffset":9.169811320754715,"rollOffset":0},{"name":"lowerArms","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":0,"yawOffset":0,"rollOffset":0},{"name":"hands","pitch":0,"yaw":0,"roll":0,"pitchPhase":0,"yawPhase":0,"rollPhase":0,"pitchOffset":-13,"yawOffset":-1.0188679245283017,"rollOffset":1.0188679245283017},{"name":"head","pitch":0,"yaw":1.7358490566037734,"roll":1.5094339622641508,"pitchPhase":-90.33962264150944,"yawPhase":94.41509433962267,"rollPhase":0,"pitchOffset":1.6981132075471694,"yawOffset":0,"rollOffset":0}]}; \ No newline at end of file