From 1948829ca8eb66f9851644064de0b3c5208b070c Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 15 Sep 2015 15:09:08 -0700 Subject: [PATCH] Improved state machine for right hand. The hand state machine has the following features * There's a idle to point animation, followed by a looping point hold state. * There's a point to idle animation. * The grab state is composed of a linear blend between an open and closed pose. Additionally the C++ code will ramp on the left and right hand overlays, This allows the fingers to be animated normally when the user is not actively pointing or grabbing. --- interface/src/avatar/MyAvatar.cpp | 7 +- interface/src/avatar/SkeletonModel.cpp | 4 +- libraries/animation/src/Rig.cpp | 70 ++++++------- libraries/animation/src/Rig.h | 6 +- tests/animation/src/data/avatar.json | 138 ++++++++++++++++++------- 5 files changed, 144 insertions(+), 81 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 91e7ba191f..da2e78c5a3 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1296,10 +1296,13 @@ void MyAvatar::initAnimGraph() { // ik-avatar.json // https://gist.github.com/hyperlogic/e58e0a24cc341ad5d060 // + // ik-avatar-hands.json + // https://gist.githubusercontent.com/hyperlogic/04a02c47eb56d8bfaebb + // // or run a local web-server // python -m SimpleHTTPServer& - auto graphUrl = QUrl("http://localhost:8000/avatar.json"); - //auto graphUrl = QUrl("https://gist.githubusercontent.com/hyperlogic/e58e0a24cc341ad5d060/raw/8f824da2908fd89ad1befadd1d8f5d7b3b6efa66/ik-avatar.json"); + //auto graphUrl = QUrl("http://localhost:8000/avatar.json"); + auto graphUrl = QUrl("https://gist.githubusercontent.com/hyperlogic/04a02c47eb56d8bfaebb/raw/883c7ce8e75ad3f72a0d513c317fe4b74a41c3b8/ik-avatar-hands.json"); _rig->initAnimGraph(graphUrl, _skeletonModel.getGeometry()->getFBXGeometry()); } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 91222ad30e..856bacbf5d 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -146,7 +146,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { headParams.leftEyeJointIndex = geometry.leftEyeJointIndex; headParams.rightEyeJointIndex = geometry.rightEyeJointIndex; - _rig->updateFromHeadParameters(headParams); + _rig->updateFromHeadParameters(headParams, deltaTime); Rig::HandParameters handParams; @@ -171,7 +171,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { handParams.isRightEnabled = false; } - _rig->updateFromHandParameters(handParams); + _rig->updateFromHandParameters(handParams, deltaTime); } else { // This is a little more work than we really want. diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 6baae8fa3e..076baf92c5 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -952,7 +952,7 @@ glm::quat Rig::getJointDefaultRotationInParentFrame(int jointIndex) { return _jointStates[jointIndex].getDefaultRotationInParentFrame(); } -void Rig::updateFromHeadParameters(const HeadParameters& params) { +void Rig::updateFromHeadParameters(const HeadParameters& params, float dt) { if (params.enableLean) { updateLeanJoint(params.leanJointIndex, params.leanSideways, params.leanForward, params.torsoTwist); } @@ -1048,59 +1048,49 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm } } -void Rig::updateFromHandParameters(const HandParameters& params) { +void Rig::updateFromHandParameters(const HandParameters& params, float dt) { if (_enableAnimGraph && _animSkeleton) { - // AJT: TODO rotate these into the correct coordinate space - /* - if (params.isLeftEnabled) { - auto rootTrans = _animSkeleton->getAbsoluteBindPose(_rootJointIndex).trans; - _animVars.set("leftHandPosition", params.leftPosition + rootTrans); - _animVars.set("leftHandRotation", params.leftOrientation); - } else { - _animVars.unset("leftHandPosition"); - _animVars.unset("leftHandRotation"); - } - - if (params.isRightEnabled) { - auto rootTrans = _animSkeleton->getAbsoluteBindPose(_rootJointIndex).trans; - _animVars.set("rightHandPosition", params.rightPosition + rootTrans); - _animVars.set("rightHandRotation", params.rightOrientation); - } else { - _animVars.unset("rightHandPosition"); - _animVars.unset("rightHandRotation"); - } - */ - - // AJT: REMOVE for grab/point debugging. + // set leftHand grab vars _animVars.set("isLeftHandIdle", false); _animVars.set("isLeftHandPoint", false); - _animVars.set("isLeftHandClose", false); - if (params.leftTrigger > 0.3333f) { - if (params.leftTrigger > 0.6666f) { - _animVars.set("isLeftHandClose", true); - } else { - _animVars.set("isLeftHandPoint", true); - } + _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); - // AJT: REMOVE for grab/point debugging. + + // set leftHand grab vars _animVars.set("isRightHandIdle", false); _animVars.set("isRightHandPoint", false); - _animVars.set("isRightHandClose", false); - if (params.rightTrigger > 0.3333f) { - if (params.rightTrigger > 0.6666f) { - _animVars.set("isRightHandClose", true); - } else { - _animVars.set("isRightHandPoint", true); - } + _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 f57b446417..9939f383b7 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -179,11 +179,11 @@ public: void setEnableAnimGraph(bool isEnabled) { _enableAnimGraph = isEnabled; } bool getEnableAnimGraph() const { return _enableAnimGraph; } - void updateFromHeadParameters(const HeadParameters& params); + void updateFromHeadParameters(const HeadParameters& params, float dt); void updateEyeJoints(int leftEyeIndex, int rightEyeIndex, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade = glm::vec3(0.0f)); - void updateFromHandParameters(const HandParameters& params); + void updateFromHandParameters(const HandParameters& params, float dt); virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation, float scale, float priority) = 0; @@ -228,6 +228,8 @@ public: Move }; RigRole _state = RigRole::Idle; + float _leftHandOverlayAlpha = 0.0f; + float _rightHandOverlayAlpha = 0.0f; }; #endif /* defined(__hifi__Rig__) */ diff --git a/tests/animation/src/data/avatar.json b/tests/animation/src/data/avatar.json index 1348824ba0..72650893d7 100644 --- a/tests/animation/src/data/avatar.json +++ b/tests/animation/src/data/avatar.json @@ -56,7 +56,8 @@ "type": "overlay", "data": { "alpha": 1.0, - "boneSet": "rightHand" + "boneSet": "rightHand", + "alphaVar": "rightHandOverlayAlpha" }, "children": [ { @@ -67,29 +68,49 @@ "states": [ { "id": "rightHandIdle", - "interpTarget": 6, - "interpDuration": 6, + "interpTarget": 3, + "interpDuration": 3, "transitions": [ - { "var": "isRightHandPoint", "state": "rightHandPoint" }, - { "var": "isRightHandClose", "state": "rightHandClose" } + { "var": "isRightHandPoint", "state": "rightHandPointIntro" }, + { "var": "isRightHandGrab", "state": "rightHandGrab" } ] }, { - "id": "rightHandPoint", - "interpTarget": 6, - "interpDuration": 6, + "id": "rightHandPointIntro", + "interpTarget": 3, + "interpDuration": 3, "transitions": [ { "var": "isRightHandIdle", "state": "rightHandIdle" }, - { "var": "isRightHandClose", "state": "rightHandClose" } + { "var": "isRightHandPointIntroOnDone", "state": "rightHandPointHold" }, + { "var": "isRightHandGrab", "state": "rightHandGrab" } ] }, { - "id": "rightHandClose", - "interpTarget": 6, - "interpDuration": 6, + "id": "rightHandPointHold", + "interpTarget": 3, + "interpDuration": 3, + "transitions": [ + { "var": "isRightHandIdle", "state": "rightHandPointOutro" }, + { "var": "isRightHandGrab", "state": "rightHandGrab" } + ] + }, + { + "id": "rightHandPointOutro", + "interpTarget": 3, + "interpDuration": 3, + "transitions": [ + { "var": "isRightHandPointOutroOnDone", "state": "rightHandIdle" }, + { "var": "isRightHandGrab", "state": "rightHandGrab" }, + { "var": "isRightHandPoint", "state": "rightHandPointHold" } + ] + }, + { + "id": "rightHandGrab", + "interpTarget": 3, + "interpDuration": 3, "transitions": [ { "var": "isRightHandIdle", "state": "rightHandIdle" }, - { "var": "isRightHandPoint", "state": "rightHandPoint" } + { "var": "isRightHandPoint_DISABLED", "state": "rightHandPointHold" } ] } ] @@ -99,19 +120,7 @@ "id": "rightHandIdle", "type": "clip", "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/squeeze_hands/right_hand_anim.fbx", - "startFrame": 30.0, - "endFrame": 30.0, - "timeScale": 1.0, - "loopFlag": true - }, - "children": [] - }, - { - "id": "rightHandPoint", - "type": "clip", - "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/squeeze_hands/right_hand_anim.fbx", + "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/right_hand_point.fbx", "startFrame": 0.0, "endFrame": 0.0, "timeScale": 1.0, @@ -120,16 +129,74 @@ "children": [] }, { - "id": "rightHandClose", + "id": "rightHandPointHold", "type": "clip", "data": { - "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/squeeze_hands/right_hand_anim.fbx", - "startFrame": 15.0, - "endFrame": 15.0, + "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/right_hand_point.fbx", + "startFrame": 12.0, + "endFrame": 12.0, "timeScale": 1.0, "loopFlag": true }, "children": [] + }, + { + "id": "rightHandPointIntro", + "type": "clip", + "data": { + "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/right_hand_point.fbx", + "startFrame": 0.0, + "endFrame": 12.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "rightHandPointOutro", + "type": "clip", + "data": { + "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/right_hand_point.fbx", + "startFrame": 0.0, + "endFrame": 65.0, + "timeScale": 1.0, + "loopFlag": false + }, + "children": [] + }, + { + "id": "rightHandGrab", + "type": "blendLinear", + "data": { + "alpha": 0.0, + "alphaVar": "rightHandGrabBlend" + }, + "children": [ + { + "id": "rightHandOpen", + "type": "clip", + "data": { + "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/hand_anims/right_hand_point.fbx", + "startFrame": 0.0, + "endFrame": 0.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "rightHandClose", + "type": "clip", + "data": { + "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/squeeze_hands/right_hand_anim.fbx", + "startFrame": 15.0, + "endFrame": 15.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + } + ] } ] }, @@ -138,7 +205,8 @@ "type": "overlay", "data": { "alpha": 1.0, - "boneSet": "leftHand" + "boneSet": "leftHand", + "alphaVar" : "leftHandOverlay" }, "children": [ { @@ -153,7 +221,7 @@ "interpDuration": 6, "transitions": [ { "var": "isLeftHandPoint", "state": "leftHandPoint" }, - { "var": "isLeftHandClose", "state": "leftHandClose" } + { "var": "isLeftHandGrab", "state": "leftHandGrab" } ] }, { @@ -162,11 +230,11 @@ "interpDuration": 6, "transitions": [ { "var": "isLeftHandIdle", "state": "leftHandIdle" }, - { "var": "isLeftHandClose", "state": "leftHandClose" } + { "var": "isLeftHandGrab", "state": "leftHandGrab" } ] }, { - "id": "leftHandClose", + "id": "leftHandGrab", "interpTarget": 6, "interpDuration": 6, "transitions": [ @@ -202,7 +270,7 @@ "children": [] }, { - "id": "leftHandClose", + "id": "leftHandGrab", "type": "clip", "data": { "url": "http://hifi-public.s3.amazonaws.com/ozan/anim/squeeze_hands/left_hand_anim.fbx",