diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index bab356ee2c..0e1a42863e 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -18,6 +18,7 @@ Script.include("../libraries/utils.js"); // add lines where the hand ray picking is happening // var WANT_DEBUG = false; +var WANT_DEBUG_STATE = false; // // these tune time-averaging and "on" value for analog trigger @@ -156,7 +157,12 @@ var STATE_CONTINUE_EQUIP = 14; var STATE_WAITING_FOR_BUMPER_RELEASE = 15; var STATE_EQUIP_SPRING = 16; - +// Used by the HandAnimaitonBuddy to play hand animations +var IDLE_HAND_STATES = [STATE_OFF, STATE_RELEASE]; +var OPEN_HAND_STATES = [STATE_SEARCHING, STATE_EQUIP_SEARCHING]; +var POINT_HAND_STATES = [STATE_NEAR_TRIGGER, STATE_CONTINUE_NEAR_TRIGGER, STATE_FAR_TRIGGER, STATE_CONTINUE_FAR_TRIGGER]; +var FAR_GRASP_HAND_STATES = [STATE_DISTANCE_HOLDING, STATE_CONTINUE_DISTANCE_HOLDING]; +// otherwise grasp function stateToName(state) { switch (state) { @@ -264,6 +270,94 @@ function getSpatialOffsetRotation(hand, spatialKey) { return rotation; } +var HAND_IDLE_RAMP_ON_RATE = 0.1; +var HAND_IDLE_RAMP_OFF_RATE = 0.02; + +// ctor +function HandAnimationBuddy(handController) { + + this.handController = handController; + this.hand = handController.hand; + this.handIdleAlpha = 0; + + var handPrefix = (this.hand === RIGHT_HAND) ? "right" : "left"; + this.animVarKeys = { + idle: handPrefix + "HandIdle", + overlayAlpha: handPrefix + "HandOverlayAlpha", + open: handPrefix + "HandOpen", + point: handPrefix + "HandPoint", + farGrasp: handPrefix + "HandFarGrasp", + grasp: handPrefix + "HandGrasp" + }; + + // hook up anim var handler + var self = this; + this.animHandlerId = MyAvatar.addAnimationStateHandler(function (props) { + return self.animStateHandler(props); + }, []); +} + +HandAnimationBuddy.prototype.animStateHandler = function (props) { + var foundState = false; + var result = {}; + + var state = this.handController.state; + var keys = this.animVarKeys; + + // idle check & process + if (IDLE_HAND_STATES.indexOf(state) != -1) { + // ramp down handIdleAlpha + this.handIdleAlpha = Math.max(0, this.handIdleAlpha - HAND_IDLE_RAMP_OFF_RATE); + result[keys.idle] = true; + foundState = true; + } else { + // ramp up handIdleAlpha + this.handIdleAlpha = Math.min(1, this.handIdleAlpha + HAND_IDLE_RAMP_ON_RATE); + result[keys.idle] = false; + } + result[keys.overlayAlpha] = this.handIdleAlpha; + + // open check + if (OPEN_HAND_STATES.indexOf(state) != -1) { + result[keys.open] = true; + foundState = true; + } else { + result[keys.open] = false; + } + + // point check + if (POINT_HAND_STATES.indexOf(state) != -1) { + result[keys.point] = true; + foundState = true; + } else { + result[keys.point] = false; + } + + // far grasp check + if (FAR_GRASP_HAND_STATES.indexOf(state) != -1) { + result[keys.farGrasp] = true; + foundState = true; + } else { + result[keys.farGrasp] = false; + } + + // grasp check + if (!foundState) { + result[keys.grasp] = true; + } else { + result[keys.grasp] = false; + } + + return result; +}; + +HandAnimationBuddy.prototype.cleanup = function () { + if (this.animHandlerId) { + MyAvatar.removeAnimationStateHandler(this.animHandlerId); + this.animHandlerId = undefined; + } +}; + function MyController(hand) { this.hand = hand; if (this.hand === RIGHT_HAND) { @@ -304,6 +398,8 @@ function MyController(hand) { this.offsetPosition = Vec3.ZERO; this.offsetRotation = Quat.IDENTITY; + this.handAnimationBuddy = new HandAnimationBuddy(this); + var _this = this; this.update = function() { @@ -361,7 +457,7 @@ function MyController(hand) { }; this.setState = function(newState) { - if (WANT_DEBUG) { + if (WANT_DEBUG || WANT_DEBUG_STATE) { print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand); } this.state = newState; @@ -1385,8 +1481,6 @@ function MyController(hand) { } else { // equipping Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); - this.startHandGrasp(); - this.setState(STATE_CONTINUE_EQUIP_BD); } @@ -1473,7 +1567,6 @@ function MyController(hand) { this.setState(STATE_RELEASE); Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); Entities.callEntityMethod(this.grabbedEntity, "unequip"); - this.endHandGrasp(); } }; @@ -1722,10 +1815,10 @@ function MyController(hand) { this.cleanup = function() { this.release(); - this.endHandGrasp(); Entities.deleteEntity(this.particleBeam); Entities.deleteEntity(this.spotLight); Entities.deleteEntity(this.pointLight); + this.handAnimationBuddy.cleanup(); }; this.activateEntity = function(entityID, grabbedProperties) { @@ -1774,45 +1867,6 @@ function MyController(hand) { } setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data); }; - - - //this is our handler, where we do the actual work of changing animation settings - this.graspHand = function(animationProperties) { - var result = {}; - //full alpha on overlay for this hand - //set grab to true - //set idle to false - //full alpha on the blend btw open and grab - if (_this.hand === RIGHT_HAND) { - result['rightHandOverlayAlpha'] = 1.0; - result['isRightHandGrab'] = true; - result['isRightHandIdle'] = false; - result['rightHandGrabBlend'] = 1.0; - } else if (_this.hand === LEFT_HAND) { - result['leftHandOverlayAlpha'] = 1.0; - result['isLeftHandGrab'] = true; - result['isLeftHandIdle'] = false; - result['leftHandGrabBlend'] = 1.0; - } - //return an object with our updated settings - return result; - }; - - this.graspHandler = null - - this.startHandGrasp = function() { - if (this.hand === RIGHT_HAND) { - this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']); - } else if (this.hand === LEFT_HAND) { - this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']); - } - }; - - this.endHandGrasp = function() { - // Tell the animation system we don't need any more callbacks. - MyAvatar.removeAnimationStateHandler(this.graspHandler); - }; - }; var rightController = new MyController(RIGHT_HAND); @@ -1927,4 +1981,4 @@ function renewParticleBeamLifetimes(deltaTime) { } rightController.renewParticleBeamLifetime(); leftController.renewParticleBeamLifetime(); -} \ No newline at end of file +} diff --git a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json index d63942c510..efd16576ee 100644 --- a/interface/resources/meshes/defaultAvatar_full/avatar-animation.json +++ b/interface/resources/meshes/defaultAvatar_full/avatar-animation.json @@ -129,46 +129,54 @@ "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isRightHandPoint", "state": "rightHandPointIntro" }, - { "var": "isRightHandGrab", "state": "rightHandGrab" } + { "var": "rightHandOpen", "state": "rightHandOpen" }, + { "var": "rightHandGrasp", "state": "rightHandGrasp" }, + { "var": "rightHandPoint", "state": "rightHandPoint" }, + { "var": "rightHandFarGrasp", "state": "rightHandFarGrasp" } ] }, { - "id": "rightHandPointIntro", + "id": "rightHandOpen", "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isRightHandIdle", "state": "rightHandIdle" }, - { "var": "isRightHandPointIntroOnDone", "state": "rightHandPointHold" }, - { "var": "isRightHandGrab", "state": "rightHandGrab" } + { "var": "rightHandIdle", "state": "rightHandIdle" }, + { "var": "rightHandGrasp", "state": "rightHandGrasp" }, + { "var": "rightHandPoint", "state": "rightHandPoint" }, + { "var": "rightHandFarGrasp", "state": "rightHandFarGrasp" } ] }, { - "id": "rightHandPointHold", + "id": "rightHandGrasp", "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isRightHandIdle", "state": "rightHandPointOutro" }, - { "var": "isRightHandGrab", "state": "rightHandGrab" } + { "var": "rightHandOpen", "state": "rightHandOpen" }, + { "var": "rightHandIdle", "state": "rightHandIdle" }, + { "var": "rightHandPoint", "state": "rightHandPoint" }, + { "var": "rightHandFarGrasp", "state": "rightHandFarGrasp" } ] }, { - "id": "rightHandPointOutro", + "id": "rightHandPoint", "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isRightHandPointOutroOnDone", "state": "rightHandIdle" }, - { "var": "isRightHandGrab", "state": "rightHandGrab" }, - { "var": "isRightHandPoint", "state": "rightHandPointHold" } + { "var": "rightHandOpen", "state": "rightHandOpen" }, + { "var": "rightHandIdle", "state": "rightHandIdle" }, + { "var": "rightHandGrasp", "state": "rightHandGrasp" }, + { "var": "rightHandFarGrasp", "state": "rightHandFarGrasp" } ] }, { - "id": "rightHandGrab", + "id": "rightHandFarGrasp", "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isRightHandIdle", "state": "rightHandIdle" }, - { "var": "isRightHandPoint_DISABLED", "state": "rightHandPointHold" } + { "var": "rightHandOpen", "state": "rightHandOpen" }, + { "var": "rightHandIdle", "state": "rightHandIdle" }, + { "var": "rightHandGrasp", "state": "rightHandGrasp" }, + { "var": "rightHandPoint", "state": "rightHandPoint" } ] } ] @@ -187,74 +195,52 @@ "children": [] }, { - "id": "rightHandPointHold", + "id": "rightHandOpen", "type": "clip", "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_right_hand.fbx", - "startFrame": 12.0, - "endFrame": 12.0, + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/search_right.fbx", + "startFrame": 0.0, + "endFrame": 0.0, "timeScale": 1.0, "loopFlag": true }, "children": [] }, { - "id": "rightHandPointIntro", + "id": "rightHandGrasp", "type": "clip", "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_right_hand.fbx", + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/grasp_right.fbx", "startFrame": 0.0, - "endFrame": 12.0, + "endFrame": 0.0, "timeScale": 1.0, - "loopFlag": false + "loopFlag": true }, "children": [] }, { - "id": "rightHandPointOutro", + "id": "rightHandPoint", "type": "clip", "data": { "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_right_hand.fbx", - "startFrame": 12.0, - "endFrame": 65.0, + "startFrame": 20.0, + "endFrame": 20.0, "timeScale": 1.0, - "loopFlag": false + "loopFlag": true }, "children": [] }, { - "id": "rightHandGrab", - "type": "blendLinear", + "id": "rightHandFarGrasp", + "type": "clip", "data": { - "alpha": 0.0, - "alphaVar": "rightHandGrabBlend" + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/far_grasp_right.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": true }, - "children": [ - { - "id": "rightHandOpen", - "type": "clip", - "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_right.fbx", - "startFrame": 0.0, - "endFrame": 0.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "rightHandClose", - "type": "clip", - "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_right.fbx", - "startFrame": 10.0, - "endFrame": 10.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - } - ] + "children": [] } ] }, @@ -264,7 +250,7 @@ "data": { "alpha": 1.0, "boneSet": "leftHand", - "alphaVar" : "leftHandOverlay" + "alphaVar" : "leftHandOverlayAlpha" }, "children": [ { @@ -278,46 +264,54 @@ "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isLeftHandPoint", "state": "leftHandPointIntro" }, - { "var": "isLeftHandGrab", "state": "leftHandGrab" } + { "var": "leftHandOpen", "state": "leftHandOpen" }, + { "var": "leftHandGrasp", "state": "leftHandGrasp" }, + { "var": "leftHandPoint", "state": "leftHandPoint" }, + { "var": "leftHandFarGrasp", "state": "leftHandFarGrasp" } ] }, { - "id": "leftHandPointIntro", + "id": "leftHandOpen", "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isLeftHandIdle", "state": "leftHandIdle" }, - { "var": "isLeftHandPointIntroOnDone", "state": "leftHandPointHold" }, - { "var": "isLeftHandGrab", "state": "leftHandGrab" } + { "var": "leftHandIdle", "state": "leftHandIdle" }, + { "var": "leftHandGrasp", "state": "leftHandGrasp" }, + { "var": "leftHandPoint", "state": "leftHandPoint" }, + { "var": "leftHandFarGrasp", "state": "leftHandFarGrasp" } ] }, { - "id": "leftHandPointHold", + "id": "leftHandGrasp", "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isLeftHandIdle", "state": "leftHandPointOutro" }, - { "var": "isLeftHandGrab", "state": "leftHandGrab" } + { "var": "leftHandOpen", "state": "leftHandOpen" }, + { "var": "leftHandIdle", "state": "leftHandIdle" }, + { "var": "leftHandPoint", "state": "leftHandPoint" }, + { "var": "leftHandFarGrasp", "state": "leftHandFarGrasp" } ] }, { - "id": "leftHandPointOutro", + "id": "leftHandPoint", "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isLeftHandPointOutroOnDone", "state": "leftHandIdle" }, - { "var": "isLeftHandGrab", "state": "leftHandGrab" }, - { "var": "isLeftHandPoint", "state": "leftHandPointHold" } + { "var": "leftHandOpen", "state": "leftHandOpen" }, + { "var": "leftHandIdle", "state": "leftHandIdle" }, + { "var": "leftHandGrasp", "state": "leftHandGrasp" }, + { "var": "leftHandFarGrasp", "state": "leftHandFarGrasp" } ] }, { - "id": "leftHandGrab", + "id": "leftHandFarGrasp", "interpTarget": 3, "interpDuration": 3, "transitions": [ - { "var": "isLeftHandIdle", "state": "leftHandIdle" }, - { "var": "isLeftHandPoint_DISABLED", "state": "leftHandPointHold" } + { "var": "leftHandOpen", "state": "leftHandOpen" }, + { "var": "leftHandIdle", "state": "leftHandIdle" }, + { "var": "leftHandGrasp", "state": "leftHandGrasp" }, + { "var": "leftHandPoint", "state": "leftHandPoint" } ] } ] @@ -336,7 +330,32 @@ "children": [] }, { - "id": "leftHandPointHold", + "id": "leftHandOpen", + "type": "clip", + "data": { + + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/search_left.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "leftHandGrasp", + "type": "clip", + "data": { + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/grasp_left.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "leftHandPoint", "type": "clip", "data": { "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_left_hand.fbx", @@ -348,62 +367,17 @@ "children": [] }, { - "id": "leftHandPointIntro", + "id": "leftHandFarGrasp", "type": "clip", "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_left_hand.fbx", + + "url": "https://hifi-content.s3.amazonaws.com/ozan/dev/anim/hand_anims/far_grasp_left.fbx", "startFrame": 0.0, - "endFrame": 12.0, + "endFrame": 0.0, "timeScale": 1.0, - "loopFlag": false + "loopFlag": true }, "children": [] - }, - { - "id": "leftHandPointOutro", - "type": "clip", - "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/point_left_hand.fbx", - "startFrame": 12.0, - "endFrame": 65.0, - "timeScale": 1.0, - "loopFlag": false - }, - "children": [] - }, - { - "id": "leftHandGrab", - "type": "blendLinear", - "data": { - "alpha": 0.0, - "alphaVar": "leftHandGrabBlend" - }, - "children": [ - { - "id": "leftHandOpen", - "type": "clip", - "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_left.fbx", - "startFrame": 0.0, - "endFrame": 0.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "leftHandClose", - "type": "clip", - "data": { - "url": "https://hifi-public.s3.amazonaws.com/ozan/anim/grab/grab_left.fbx", - "startFrame": 10.0, - "endFrame": 10.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - } - ] } ] }, diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index e8d952973b..3cd74afb81 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -119,7 +119,6 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { handParams.isLeftEnabled = true; handParams.leftPosition = Quaternions::Y_180 * leftPalm.getRawPosition(); handParams.leftOrientation = Quaternions::Y_180 * leftPalm.getRawRotation(); - handParams.leftTrigger = leftPalm.getTrigger(); } else { handParams.isLeftEnabled = false; } @@ -129,7 +128,6 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { handParams.isRightEnabled = true; handParams.rightPosition = Quaternions::Y_180 * rightPalm.getRawPosition(); handParams.rightOrientation = Quaternions::Y_180 * rightPalm.getRawRotation(); - handParams.rightTrigger = rightPalm.getTrigger(); } else { handParams.isRightEnabled = false; } diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index c6060d791a..bcda3e8f5c 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -960,7 +960,6 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm } void Rig::updateFromHandParameters(const HandParameters& params, float dt) { - if (_animSkeleton && _animNode) { if (params.isLeftEnabled) { _animVars.set("leftHandPosition", params.leftPosition); @@ -980,45 +979,6 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) { _animVars.unset("rightHandRotation"); _animVars.set("rightHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition); } - - // set leftHand grab vars - _animVars.set("isLeftHandIdle", false); - _animVars.set("isLeftHandPoint", false); - _animVars.set("isLeftHandGrab", false); - - // Split the trigger range into three zones. - bool rampOut = false; - if (params.leftTrigger > 0.6666f) { - _animVars.set("isLeftHandGrab", true); - } else if (params.leftTrigger > 0.3333f) { - _animVars.set("isLeftHandPoint", true); - } else { - _animVars.set("isLeftHandIdle", true); - rampOut = true; - } - const float OVERLAY_RAMP_OUT_SPEED = 6.0f; // ramp in and out over 1/6th of a sec - _leftHandOverlayAlpha = glm::clamp(_leftHandOverlayAlpha + (rampOut ? -1.0f : 1.0f) * OVERLAY_RAMP_OUT_SPEED * dt, 0.0f, 1.0f); - _animVars.set("leftHandOverlayAlpha", _leftHandOverlayAlpha); - _animVars.set("leftHandGrabBlend", params.leftTrigger); - - // set leftHand grab vars - _animVars.set("isRightHandIdle", false); - _animVars.set("isRightHandPoint", false); - _animVars.set("isRightHandGrab", false); - - // Split the trigger range into three zones - rampOut = false; - if (params.rightTrigger > 0.6666f) { - _animVars.set("isRightHandGrab", true); - } else if (params.rightTrigger > 0.3333f) { - _animVars.set("isRightHandPoint", true); - } else { - _animVars.set("isRightHandIdle", true); - rampOut = true; - } - _rightHandOverlayAlpha = glm::clamp(_rightHandOverlayAlpha + (rampOut ? -1.0f : 1.0f) * OVERLAY_RAMP_OUT_SPEED * dt, 0.0f, 1.0f); - _animVars.set("rightHandOverlayAlpha", _rightHandOverlayAlpha); - _animVars.set("rightHandGrabBlend", params.rightTrigger); } } diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 669af2ea64..0636230678 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -71,8 +71,6 @@ public: glm::quat leftOrientation = glm::quat(); // rig space (z forward) glm::vec3 rightPosition = glm::vec3(); // rig space glm::quat rightOrientation = glm::quat(); // rig space (z forward) - float leftTrigger = 0.0f; - float rightTrigger = 0.0f; }; virtual ~Rig() {}