From 9559f9ffd39ac80fdb7bb6f76c946ee15d5586be Mon Sep 17 00:00:00 2001 From: r3tk0n Date: Tue, 26 Feb 2019 17:52:18 -0800 Subject: [PATCH 1/4] Add off-hand controller manipulation to fargrab. --- .../controllerModules/farGrabEntity.js | 94 +++++++++++++++++-- 1 file changed, 88 insertions(+), 6 deletions(-) diff --git a/scripts/system/controllers/controllerModules/farGrabEntity.js b/scripts/system/controllers/controllerModules/farGrabEntity.js index 197a809e91..d2d8af9dc4 100644 --- a/scripts/system/controllers/controllerModules/farGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farGrabEntity.js @@ -60,6 +60,14 @@ Script.include("/~/system/libraries/controllers.js"); this.reticleMaxY = 0; this.endedGrab = 0; this.MIN_HAPTIC_PULSE_INTERVAL = 500; // ms + this.disabled = false; + var _this = this; + this.leftTrigger = 0.0; + this.rightTrigger = 0.0; + this.initialControllerRotation = Quat.IDENTITY; + this.currentControllerRotation = Quat.IDENTITY; + this.manipulating = false; + this.wasManipulating = false; var FAR_GRAB_JOINTS = [65527, 65528]; // FARGRAB_LEFTHAND_INDEX, FARGRAB_RIGHTHAND_INDEX @@ -75,6 +83,46 @@ Script.include("/~/system/libraries/controllers.js"); 100, makeLaserParams(this.hand, false)); + //enableDispatcherModule("LeftFarGrabEntity", leftFarGrabEntity); + //enableDispatcherModule("RightFarGrabEntity", rightFarGrabEntity); + + this.getOtherModule = function () { + // Used to fetch other module. + return getEnabledModuleByName(this.hand === RIGHT_HAND ? ("RightFarGrabEntity") : ("LeftFarGrabEntity")); + }; + + this.getTargetRotation = function () { + if (this.targetIsNull()) { + return null; + } else { + var props = Entities.getEntityProperties(this.targetEntityID, ["rotation"]); + return props.rotation; + } + }; + + this.getOffhand = function () { + return (this.hand === RIGHT_HAND ? LEFT_HAND : RIGHT_HAND); + } + + this.getOffhandTrigger = function () { + return (_this.hand === RIGHT_HAND ? _this.rightTrigger : _this.leftTrigger); + } + + this.shouldManipulateTarget = function () { + return (_this.getOffhandTrigger() > TRIGGER_ON_VALUE) ? true : false; + }; + + this.calculateEntityRotationManipulation = function (controllerRotation) { + return Quat.multiply(controllerRotation, Quat.inverse(this.initialControllerRotation)); + }; + + this.setJointTranslation = function (newTargetPosLocal) { + MyAvatar.setJointTranslation(FAR_GRAB_JOINTS[this.hand], newTargetPosLocal); + }; + + this.setJointRotation = function (newTargetRotLocal) { + MyAvatar.setJointRotation(FAR_GRAB_JOINTS[this.hand], newTargetRotLocal); + }; this.handToController = function() { return (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; @@ -142,8 +190,9 @@ Script.include("/~/system/libraries/controllers.js"); Messages.sendLocalMessage('Hifi-unhighlight-entity', JSON.stringify(message)); var newTargetPosLocal = MyAvatar.worldToJointPoint(targetProps.position); - MyAvatar.setJointTranslation(FAR_GRAB_JOINTS[this.hand], newTargetPosLocal); - MyAvatar.setJointRotation(FAR_GRAB_JOINTS[this.hand], { x: 0, y: 0, z: 0, w: 1 }); + var newTargetRotLocal = targetProps.rotation; + this.setJointTranslation(newTargetPosLocal); + this.setJointRotation(newTargetRotLocal); var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; Entities.callEntityMethod(targetProps.id, "startDistanceGrab", args); @@ -231,8 +280,31 @@ Script.include("/~/system/libraries/controllers.js"); // var newTargetPosLocal = Mat4.transformPoint(MyAvatar.getSensorToWorldMatrix(), newTargetPosition); var newTargetPosLocal = MyAvatar.worldToJointPoint(newTargetPosition); - MyAvatar.setJointTranslation(FAR_GRAB_JOINTS[this.hand], newTargetPosLocal); - MyAvatar.setJointRotation(FAR_GRAB_JOINTS[this.hand], { x: 0, y: 0, z: 0, w: 1 }); + if (this.shouldManipulateTarget()) { + var pose = Controller.getPoseValue((this.getOffhand() ? Controller.Standard.RightHand : Controller.Standard.LeftHand)); + if (pose.valid) { + if (!this.manipulating) { + if (!this.wasManipulating) { + this.initialEntityRotation = this.getTargetRotation(); // Worldframe. + } + this.initialControllerRotation = Quat.multiply(pose.rotation, MyAvatar.orientation); // Worldframe. + this.manipulating = true; + } + } + + var rot = Quat.multiply(pose.rotation, MyAvatar.orientation); + var rotBetween = this.calculateEntityRotationManipulation(rot); + this.lastJointRotation = Quat.multiply(rotBetween, this.initialEntityRotation); + this.setJointRotation(this.lastJointRotation); + } else { + if (this.manipulating) { + this.initialEntityRotation = this.lastJointRotation; + this.wasManipulating = true; + } + this.manipulating = false; + this.initialControllerRotation = Quat.IDENTITY; + } + this.setJointTranslation(newTargetPosLocal); this.previousRoomControllerPosition = roomControllerPosition; }; @@ -254,9 +326,15 @@ Script.include("/~/system/libraries/controllers.js"); })); unhighlightTargetEntity(this.targetEntityID); this.grabbing = false; - this.targetEntityID = null; this.potentialEntityWithContextOverlay = false; MyAvatar.clearJointData(FAR_GRAB_JOINTS[this.hand]); + this.initialEntityRotation = Quat.IDENTITY; + this.initialControllerRotation = Quat.IDENTITY; + this.targetEntityID = null; + this.manipulating = false; + this.wasManipulating = false; + var otherModule = this.getOtherModule(); + otherModule.disabled = false; }; this.updateRecommendedArea = function() { @@ -326,7 +404,9 @@ Script.include("/~/system/libraries/controllers.js"); this.distanceHolding = false; - if (controllerData.triggerValues[this.hand] > TRIGGER_ON_VALUE) { + if (controllerData.triggerValues[this.hand] > TRIGGER_ON_VALUE && !this.disabled) { + var otherModule = this.getOtherModule(); + otherModule.disabled = true; return makeRunningValues(true, [], []); } else { this.destroyContextOverlay(); @@ -336,6 +416,8 @@ Script.include("/~/system/libraries/controllers.js"); }; this.run = function (controllerData) { + this.leftTrigger = controllerData.triggerValues[LEFT_HAND]; + this.rightTrigger = controllerData.triggerValues[RIGHT_HAND]; if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE || this.targetIsNull()) { this.endFarGrabEntity(controllerData); return makeRunningValues(false, [], []); From 52d80476a8fda0d32abff288815ff75a5f9bae32 Mon Sep 17 00:00:00 2001 From: r3tk0n Date: Tue, 26 Feb 2019 17:55:16 -0800 Subject: [PATCH 2/4] Fix activation criteria. --- scripts/system/controllers/controllerModules/farGrabEntity.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/system/controllers/controllerModules/farGrabEntity.js b/scripts/system/controllers/controllerModules/farGrabEntity.js index d2d8af9dc4..6e08542bda 100644 --- a/scripts/system/controllers/controllerModules/farGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farGrabEntity.js @@ -88,7 +88,7 @@ Script.include("/~/system/libraries/controllers.js"); this.getOtherModule = function () { // Used to fetch other module. - return getEnabledModuleByName(this.hand === RIGHT_HAND ? ("RightFarGrabEntity") : ("LeftFarGrabEntity")); + return getEnabledModuleByName(this.hand === RIGHT_HAND ? ("LeftFarGrabEntity") : ("RightFarGrabEntity")); }; this.getTargetRotation = function () { @@ -105,7 +105,7 @@ Script.include("/~/system/libraries/controllers.js"); } this.getOffhandTrigger = function () { - return (_this.hand === RIGHT_HAND ? _this.rightTrigger : _this.leftTrigger); + return (_this.hand === RIGHT_HAND ? _this.leftTrigger : _this.rightTrigger); } this.shouldManipulateTarget = function () { From ca740c6254229112e3657dd02f2179883ca06ed1 Mon Sep 17 00:00:00 2001 From: r3tk0n Date: Tue, 26 Feb 2019 18:44:00 -0800 Subject: [PATCH 3/4] Add a 2x multiplier for controller movement to entity rotation when manipulating with fargrab. --- .../controllerModules/farGrabEntity.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/scripts/system/controllers/controllerModules/farGrabEntity.js b/scripts/system/controllers/controllerModules/farGrabEntity.js index 6e08542bda..5e621809b2 100644 --- a/scripts/system/controllers/controllerModules/farGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farGrabEntity.js @@ -276,25 +276,31 @@ Script.include("/~/system/libraries/controllers.js"); newTargetPosition = Vec3.sum(newTargetPosition, worldControllerPosition); newTargetPosition = Vec3.sum(newTargetPosition, this.offsetPosition); - // MyAvatar.setJointTranslation(FAR_GRAB_JOINTS[this.hand], MyAvatar.worldToJointPoint(newTargetPosition)); - - // var newTargetPosLocal = Mat4.transformPoint(MyAvatar.getSensorToWorldMatrix(), newTargetPosition); var newTargetPosLocal = MyAvatar.worldToJointPoint(newTargetPosition); + + // This block handles the user's ability to rotate the object they're FarGrabbing if (this.shouldManipulateTarget()) { + // Get the pose of the controller that is not grabbing. var pose = Controller.getPoseValue((this.getOffhand() ? Controller.Standard.RightHand : Controller.Standard.LeftHand)); if (pose.valid) { + // If we weren't manipulating the object yet, initialize the entity's original position. if (!this.manipulating) { + // This will only be triggered if we've let go of the off-hand trigger and pulled it again without ending a grab. + // Need to poll the entity's rotation again here. if (!this.wasManipulating) { - this.initialEntityRotation = this.getTargetRotation(); // Worldframe. + this.initialEntityRotation = this.getTargetRotation(); } - this.initialControllerRotation = Quat.multiply(pose.rotation, MyAvatar.orientation); // Worldframe. + // Save the original controller orientation, we only care about the delta between this rotation and wherever + // the controller rotates, so that we can apply it to the entity's rotation. + this.initialControllerRotation = Quat.multiply(pose.rotation, MyAvatar.orientation); this.manipulating = true; } } var rot = Quat.multiply(pose.rotation, MyAvatar.orientation); var rotBetween = this.calculateEntityRotationManipulation(rot); - this.lastJointRotation = Quat.multiply(rotBetween, this.initialEntityRotation); + var doubleRot = Quat.multiply(rotBetween, rotBetween); + this.lastJointRotation = Quat.multiply(doubleRot, this.initialEntityRotation); this.setJointRotation(this.lastJointRotation); } else { if (this.manipulating) { From a72b02cd25989f7d11af0cf2dd4a511de6b77bde Mon Sep 17 00:00:00 2001 From: r3tk0n Date: Thu, 28 Feb 2019 13:08:05 -0800 Subject: [PATCH 4/4] Clean up code and add comments. --- .../controllers/controllerModules/farGrabEntity.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/scripts/system/controllers/controllerModules/farGrabEntity.js b/scripts/system/controllers/controllerModules/farGrabEntity.js index 5e621809b2..65a3671cae 100644 --- a/scripts/system/controllers/controllerModules/farGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farGrabEntity.js @@ -83,14 +83,11 @@ Script.include("/~/system/libraries/controllers.js"); 100, makeLaserParams(this.hand, false)); - //enableDispatcherModule("LeftFarGrabEntity", leftFarGrabEntity); - //enableDispatcherModule("RightFarGrabEntity", rightFarGrabEntity); - this.getOtherModule = function () { - // Used to fetch other module. return getEnabledModuleByName(this.hand === RIGHT_HAND ? ("LeftFarGrabEntity") : ("RightFarGrabEntity")); }; + // Get the rotation of the fargrabbed entity. this.getTargetRotation = function () { if (this.targetIsNull()) { return null; @@ -108,10 +105,12 @@ Script.include("/~/system/libraries/controllers.js"); return (_this.hand === RIGHT_HAND ? _this.leftTrigger : _this.rightTrigger); } + // Activation criteria for rotating a fargrabbed entity. If we're changing the mapping, this is where to do it. this.shouldManipulateTarget = function () { return (_this.getOffhandTrigger() > TRIGGER_ON_VALUE) ? true : false; }; + // Get the delta between the current rotation and where the controller was when manipulation started. this.calculateEntityRotationManipulation = function (controllerRotation) { return Quat.multiply(controllerRotation, Quat.inverse(this.initialControllerRotation)); }; @@ -303,11 +302,14 @@ Script.include("/~/system/libraries/controllers.js"); this.lastJointRotation = Quat.multiply(doubleRot, this.initialEntityRotation); this.setJointRotation(this.lastJointRotation); } else { + // If we were manipulating but the user isn't currently expressing this intent, we want to know so we preserve the rotation + // between manipulations without ending the fargrab. if (this.manipulating) { this.initialEntityRotation = this.lastJointRotation; this.wasManipulating = true; } this.manipulating = false; + // Reset the inital controller position. this.initialControllerRotation = Quat.IDENTITY; } this.setJointTranslation(newTargetPosLocal);