From 28d9409bf064d4cbee58a608da2a8af40ddbd040 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 4 Jan 2018 11:37:37 -0700 Subject: [PATCH] Fix default hand poses --- interface/resources/qml/js/Utils.jsc | Bin 6596 -> 0 bytes interface/src/avatar/MySkeletonModel.cpp | 11 +- interface/src/avatar/MySkeletonModel.h | 2 + scripts/defaultScripts.js | 3 +- .../{libraries => controllers}/handTouch.js | 198 +++++++++++++----- 5 files changed, 159 insertions(+), 55 deletions(-) delete mode 100644 interface/resources/qml/js/Utils.jsc rename scripts/system/{libraries => controllers}/handTouch.js (76%) diff --git a/interface/resources/qml/js/Utils.jsc b/interface/resources/qml/js/Utils.jsc deleted file mode 100644 index ab20e996b9469915ac6a89901da175143e6b5024..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6596 zcmcIoZD?EP6@Kh1ckah_<+cmm)~+s7*+{cEDOm|)Y*uPBiCux$Iwl#JYtNP&7t3}W zIXI&o4oU8EkM2n zXjl7O2dDtRuNCd{@)jY-)d!#zenqKY4sn&W{weu)twmlb!$4JTzv65rm+K1vDC#!F zU$|ZVIZ9zlW+S<`HL;hgR&M8~1sQiLyXg~6*Kx4qHtya=?){4Iz`gR%B^6)FqD(EX zPx0NgjXdr9YAbNP75KOnxYqy<89DFo`<=jA05hh+!CUJc)7q5K-I-U<4BwMhw#!Kold03qHB1qPh=(m57jV zQZO*TlsKpO<^4D&)ji|-UBpF<$-`KmCFTK~acFxKqv8qb`vJ}(jwnv6ynF{ogq(=F zep_Ap)wNGud)4)O>UtbUguEF{VOB&&#)x21=BI^yoeI;=cpet< z8yEavN0<0LF8)1^DU2eDE}X7EzTC=9#(VVvU%?VLXPX@E8u^tC$cdhzrY~ z5|TzSE|9{#2}}z<=It55SzSj%iNA*yHv6nZbjwP_N>*aF82-K7|F|4Z{3((gYY*l1 z1HmPNES&HK!VAmo!G#Z7%nSc2m&=jFSbJz;vopy0hR~Acw-O%(%P$^o0YVGQoxRBc zfA58N%nJ{-l0bHGCbwg^#q(qrrDi+!w<_$cdfT#JQtVa6B|0HZKTvD>SPT8{3FK*i zWU(iZU!oSteUbW{j!MrrowDh%hwMA*Wz%5~+1G_Km+UHco!!3?d2`uawWQAO`Fhz^ zFY9DKQ7^k1!8+Li%B~H>BZmbX7dAVWSkh#gI3&0r zaF0rAW;@0YRTR^~w|fH1=rq7T1!gIn>dAFt!Sy*C45#|hZ zyKMQfPE=zR8BZ12Iu&e;jZ`qZ;(XBNe0X7VdI#CX&hyK$=>L{qIw{h|R_2l4RI7AY z^-G-Fg*Pl@c)U6&I`)6~vWKqD3?b!JxCu1uN`cA?Q-i-75ra?*w4> z7DLeZEXfck*xy13exhOT)~XM$^JKYWuGBjYFUK{J-kQV9*AmCcI=9Ipz3t&zt&~o& zbp5o=j@d0M5iMDXSkX$%t~YJ^dxYvnP2X7@RT0fd+JSJgHI(cgqRD9&=_E-h7ipTL zi!Ra}N%Kz9JRJ@v&Ijf=afs?ImCUopaAUf5Bc(P@)^4QL#!&4B4=hC;lN+q^_W+Q1 zP^n|i{5|@(6kNweRp@!g!IB0$&XzP(9WOq8UKl6|MM0Czbbp-MJtdAmS4|C?43SDf)z9}dNlLtGo5xl*UM-i)V9TyEvOFWw5I(m_-&8|fx011{`>NNH;(6Df(rr#QsN>-}$CJna|wOpzoRcq-Fq`bAH8fghvwNyJ`N_RlpJYiGQZuHu}HZ5Pa zdE8c|q5`8P==g;$uId?L_>-ZdTT7Ja(9^jWIyw}4%`oqUj`vkn%QKo+>hkt%Am^R8 zT%)}GyrqJUtqMAFDsNlV@getLocalOrientation(); _rig.computeMotionAnimationState(deltaTime, position, velocity, orientation, ccState); - // evaluate AnimGraph animation and update jointStates. + //// evaluate AnimGraph animation and update jointStates. Model::updateRig(deltaTime, parentTransform); Rig::EyeParameters eyeParams; @@ -323,17 +323,22 @@ void MySkeletonModel::updateFingers() { for (auto& link : chain) { int index = _rig.indexOfJoint(link.second); if (index >= 0) { + if (_jointRotationFrameOffsetMap.find(index) == _jointRotationFrameOffsetMap.end()) { + _jointRotationFrameOffsetMap.insert(std::pair(index, 0)); + } auto pose = myAvatar->getControllerPoseInSensorFrame(link.first); if (pose.valid) { glm::quat relRot = glm::inverse(prevAbsRot) * pose.getRotation(); // only set the rotation for the finger joints, not the hands. if (link.first != controller::Action::LEFT_HAND && link.first != controller::Action::RIGHT_HAND) { _rig.setJointRotation(index, true, relRot, CONTROLLER_PRIORITY); + _jointRotationFrameOffsetMap.find(index)->second = 0; } prevAbsRot = pose.getRotation(); - } else { - // _rig.clearJointAnimationPriority(index); + } else if (_jointRotationFrameOffsetMap.find(index)->second == 1){ + _rig.clearJointAnimationPriority(index); } + _jointRotationFrameOffsetMap.find(index)->second++; } } } diff --git a/interface/src/avatar/MySkeletonModel.h b/interface/src/avatar/MySkeletonModel.h index d9f57a439a..252b6c293b 100644 --- a/interface/src/avatar/MySkeletonModel.h +++ b/interface/src/avatar/MySkeletonModel.h @@ -28,6 +28,8 @@ private: AnimPose _prevHips; // sensor frame bool _prevHipsValid { false }; + + std::map _jointRotationFrameOffsetMap; }; #endif // hifi_MySkeletonModel_h diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 89d4c75ae4..c14cea63f2 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -32,7 +32,8 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/tablet-ui/tabletUI.js" ]; var DEFAULT_SCRIPTS_SEPARATE = [ - "system/controllers/controllerScripts.js" + "system/controllers/controllerScripts.js", + "system/controllers/handTouch.js" //"system/chat.js" ]; diff --git a/scripts/system/libraries/handTouch.js b/scripts/system/controllers/handTouch.js similarity index 76% rename from scripts/system/libraries/handTouch.js rename to scripts/system/controllers/handTouch.js index 5f917f7247..34f11aa764 100644 --- a/scripts/system/libraries/handTouch.js +++ b/scripts/system/controllers/handTouch.js @@ -11,15 +11,36 @@ (function(){ - var animating = false; var updateFingerWithIndex = 0; + + // Keys to access finger data var dataKeys = ["pinky", "ring", "middle", "index", "thumb"]; + // Additionally close the hands to achieve a grabbing effect var grabPercent = { left: 0, right: 0 }; - var isGrabbing = false; + // var isGrabbing = false; + + // Store which fingers are touching - if all false restate the default poses + var isTouching = { + left: { + pinky: false, + middle: false, + ring: false, + thumb: false, + index: false + }, right: { + pinky: false, + middle: false, + ring: false, + thumb: false, + index: false + } + } + // joint data for opened pose + var dataOpen = { left: { pinky: [{x: -0.18262, y:-2.666, z:-25.11229}, {x: 1.28845, y:0, z:1.06604}, {x: -3.967, y:0, z:-0.8351} ], @@ -35,6 +56,8 @@ index: [{x: -0.111, y: 0, z: -2.2816}, {x: 1.217, y: 0, z: -0.90168}, {x: -3.967, y: 0, z: 2.62649}] } } + + // joint data for closed hand var dataClose = { left: { @@ -52,6 +75,8 @@ } } + // joint data for the current frame + var dataCurrent = { left:{ pinky:[{x: 0, y: 0, z: 0},{x: 0, y: 0, z: 0},{x: 0, y: 0, z: 0}], @@ -68,6 +93,8 @@ index: [{x: 0, y: 0, z: 0},{x: 0, y: 0, z: 0},{x: 0, y: 0, z: 0}] } } + + // interpolated values on joint data to smooth movement var dataDelta = { left:{ @@ -86,16 +113,24 @@ } } + // Acquire an updated value per hand every 5 frames + var animationSteps = 5; + // Debugging info + var showSphere = false; var showLines = false; + // store the rays for the fingers - only for debug purposes + var fingerRays = { left:{pinky: undefined, middle: undefined, ring: undefined, thumb: undefined, index: undefined}, right:{pinky: undefined, middle: undefined, ring: undefined, thumb: undefined, index: undefined} }; + // Register object with API Debugger + var varsToDebug = { toggleDebugSphere: function(){ showSphere = !showSphere; @@ -105,18 +140,18 @@ }, fingerPercent: { left: { - pinky: 0.5, - middle: 0.5, - ring: 0.5, - thumb: 0.5, - index: 0.5 + pinky: 0.75, + middle: 0.75, + ring: 0.75, + thumb: 0.75, + index: 0.75 } , right: { - pinky: 0.5, - middle: 0.5, - ring: 0.5, - thumb: 0.5, - index: 0.5 + pinky: 0.75, + middle: 0.75, + ring: 0.75, + thumb: 0.75, + index: 0.75 } }, triggerValues: { @@ -128,6 +163,8 @@ rightSecondaryValue: 0 } } + + // Add/Subtract the joint data - per finger joint function addVals(val1, val2, sign) { var val = []; @@ -141,6 +178,8 @@ return val; } + // Multiply/Divide the joint data - per finger joint + function multiplyValsBy(val1, num) { var val = []; for (var i = 0; i < val1.length; i++) { @@ -151,6 +190,8 @@ } return val; } + + // Calculate the finger lengths by adding its joint lengths function getJointDistances(jointNamesArray) { var result = {distances: [], totalDistance: 0} @@ -165,23 +206,29 @@ } return result; } + + // Calculate the sphere that look up for entities, the center of the palm, perpendicular vector from the palm plane and origin of the the finger rays function estimatePalmData(side) { - var data = {position: undefined, perpendicular: undefined, distance: undefined, fingers: {pinky: undefined, middle: undefined, ring: undefined, thumb: undefined, index: undefined}}; - - // Calculate the finger lengths by adding its joint lengths + // Return data object + var data = {position: undefined, perpendicular: undefined, distance: undefined, fingers: {pinky: undefined, middle: undefined, ring: undefined, thumb: undefined, index: undefined}}; var jointOffset = { x: 0, y: 0, z: 0 }; + var upperSide = side[0].toUpperCase() + side.substring(1); var jointIndexHand = MyAvatar.getJointIndex(upperSide + "Hand"); + + // Store position of the hand joint var worldPosHand = MyAvatar.jointToWorldPoint(jointOffset, jointIndexHand); var minusWorldPosHand = {x:-worldPosHand.x, y:-worldPosHand.y, z:-worldPosHand.z}; + // Data for finger rays var directions = {pinky: undefined, middle: undefined, ring: undefined, thumb: undefined, index: undefined}; var positions = {pinky: undefined, middle: undefined, ring: undefined, thumb: undefined, index: undefined}; - var sumvec = {x:0, y:0, z:0}; - sumvec = Vec3.sum(worldPosHand, sumvec); + // Calculate palm center + var palmCenter = {x:0, y:0, z:0}; + palmCenter = Vec3.sum(worldPosHand, palmCenter); var thumbLength = 0; @@ -195,15 +242,17 @@ directions[finger] = Vec3.normalize(Vec3.sum(positions[finger], minusWorldPosHand)); data.fingers[finger] = Vec3.sum(positions[finger], Vec3.multiply(fingerLength, directions[finger])); if (finger != "thumb") { - sumvec = Vec3.sum(Vec3.multiply(2, positions[finger]), sumvec); + palmCenter = Vec3.sum(Vec3.multiply(2, positions[finger]), palmCenter); // Hand joint + 2 * 4 fingers(no thumb) = 9 } else { thumbLength = fingerLength; } } data.perpendicular = side == "right" ? Vec3.normalize(Vec3.cross(directions["ring"], directions["pinky"])) : Vec3.normalize(Vec3.cross(directions["pinky"],directions["ring"])); - - data.position = Vec3.multiply(1.0/9, sumvec); + + + data.position = Vec3.multiply(1.0/9, palmCenter); // Hand joint + 2 * 4 fingers(no thumb) = 9 + data.distance = 1.55*Vec3.distance(data.position, positions["index"]); // move back thumb check up origin @@ -213,8 +262,11 @@ return data; } + // Register GlobalDebugger for API Debugger Script.registerValue("GlobalDebugger", varsToDebug); + // Create debug overlays - finger rays + palm rays + spheres + for (var i = 0; i < dataKeys.length; i++) { fingerRays["left"][dataKeys[i]] = Overlays.addOverlay("line3d", { color: { red: 0, green: 0, blue: 255 }, @@ -261,14 +313,18 @@ } function updateSphereHand(side) { + var palmData = estimatePalmData(side); - var dist = 1.5*palmData.distance; var palmPoint = palmData.position; - + var dist = 1.5*palmData.distance; + + // Situate the debugging overlays + var checkOffset = { x: palmData.perpendicular.x * dist, y: palmData.perpendicular.y * dist, z: palmData.perpendicular.z * dist }; - + + var spherePos = Vec3.sum(palmPoint, checkOffset); var checkPoint = Vec3.sum(palmPoint, Vec3.multiply(2, checkOffset)); @@ -287,7 +343,7 @@ }, visible: showSphere }); - var pickRays = []; + for (var i = 0; i < dataKeys.length; i++) { Overlays.editOverlay(fingerRays[side][dataKeys[i]], { start: palmData.fingers[dataKeys[i]], @@ -295,6 +351,9 @@ visible: showLines }); } + + // Update the intersection of only one finger at a time + var finger = dataKeys[updateFingerWithIndex]; var grabbables = Entities.findEntities(spherePos, dist); @@ -303,14 +362,19 @@ var origin = palmData.fingers[finger]; var direction = Vec3.normalize(Vec3.subtract(checkPoint, origin)); var intersection = Entities.findRayIntersection({origin: origin, direction: direction}, true, grabbables, [], true, false); - var percent = 0.5; - if (intersection.intersects && intersection.distance < 2.5*dist) { + var percent = 0.75; + var isAbleToGrab = intersection.intersects && intersection.distance < 2.5*dist; + // Store if this finger is touching something + isTouching[side][finger] = isAbleToGrab; + if (isAbleToGrab) { + // update the open/close percentage for this finger percent = intersection.distance/(2.5*dist); var grabMultiplier = finger === "thumb" ? 0.2 : 0.05; percent += grabMultiplier * grabPercent[side]; } - varsToDebug.fingerPercent[side][finger] = percent; + varsToDebug.fingerPercent[side][finger] = percent; // store the current open/close percentage } + // Calculate new interpolation data var totalDistance = addVals(dataClose[side][finger], dataOpen[side][finger], -1); var percent = varsToDebug.fingerPercent[side][finger]; var newFingerData = addVals(dataOpen[side][finger], multiplyValsBy(totalDistance, percent), 1); @@ -319,6 +383,7 @@ dataDelta[side][finger] = multiplyValsBy(addVals(newFingerData, dataCurrent[side][finger], -1), 1.0/animationSteps); } + // Recreate the finger joint names - and how many 0 to count function getJointNames(side, finger, count) { var names = []; for (var i = 1; i < count+1; i++) { @@ -328,8 +393,11 @@ return names; } + // Capture the controller values + var leftTriggerPress = function (value) { varsToDebug.triggerValues.leftTriggerValue = value; + // the value for the trigger increments the hand-close percentage grabPercent["left"] = value; }; var leftTriggerClick = function (value) { @@ -337,6 +405,7 @@ }; var rightTriggerPress = function (value) { varsToDebug.triggerValues.rightTriggerValue = value; + // the value for the trigger increments the hand-close percentage grabPercent["right"] = value; }; var rightTriggerClick = function (value) { @@ -362,34 +431,61 @@ mapping.from([Controller.Standard.RightGrip]).peek().to(rightSecondaryPress); Controller.enableMapping(MAPPING_NAME); - + + function getTouching(side) { + var animating = false; + for (var i = 0; i < dataKeys.length; i++) { + var finger = dataKeys[i]; + animating = animating || isTouching[side][finger]; + } + return animating; + } + Script.update.connect(function(){ - updateFingerWithIndex = updateFingerWithIndex < dataKeys.length-1 ? updateFingerWithIndex + 1 : 0; + + // iterate fingers + + updateFingerWithIndex = (updateFingerWithIndex < dataKeys.length-1) ? updateFingerWithIndex + 1 : 0; + // precalculate data + updateSphereHand("right"); updateSphereHand("left"); - - for (var i = 0; i < dataKeys.length; i++) { - var finger = dataKeys[i]; - var names = getJointNames("Right", finger, 3); - dataCurrent["right"][finger] = addVals(dataCurrent["right"][finger], dataDelta["right"][finger], 1); - for (var j = 0; j < names.length; j++) { - var index = MyAvatar.getJointIndex(names[j]); - var quatRot = Quat.fromVec3Degrees(dataCurrent["right"][finger][j]); - MyAvatar.setJointRotation(index, quatRot); - } - } - - for (var i = 0; i < dataKeys.length; i++) { - var finger = dataKeys[i]; - var names = getJointNames("Left", finger, 3); - dataCurrent["left"][finger] = addVals(dataCurrent["left"][finger], dataDelta["left"][finger], 1); - for (var j = 0; j < names.length; j++) { - var index = MyAvatar.getJointIndex(names[j]); - var quatRot = Quat.fromVec3Degrees(dataCurrent["left"][finger][j]); - MyAvatar.setJointRotation(index, quatRot); - } - } + + // Assign interpolated values + var i, j, index; + for (i = 0; i < dataKeys.length; i++) { + var finger = dataKeys[i]; + var names = getJointNames("Right", finger, 3); + dataCurrent["right"][finger] = addVals(dataCurrent["right"][finger], dataDelta["right"][finger], 1); + for (j = 0; j < names.length; j++) { + index = MyAvatar.getJointIndex(names[j]); + // if no finger is touching restate the default poses + if (getTouching("right")) { + var quatRot = Quat.fromVec3Degrees(dataCurrent["right"][finger][j]); + MyAvatar.setJointRotation(index, quatRot); + } else { + MyAvatar.clearJointData(index); + } + } + } + + for (i = 0; i < dataKeys.length; i++) { + var finger = dataKeys[i]; + var names = getJointNames("Left", finger, 3); + dataCurrent["left"][finger] = addVals(dataCurrent["left"][finger], dataDelta["left"][finger], 1); + for (j = 0; j < names.length; j++) { + index = MyAvatar.getJointIndex(names[j]); + // if no finger is touching restate the default poses + if (getTouching("left")) { + var quatRot = Quat.fromVec3Degrees(dataCurrent["left"][finger][j]); + MyAvatar.setJointRotation(index, quatRot); + } else { + MyAvatar.clearJointData(index); + } + } + } + }); }())