From 5a01bf406e267d7a90fd43792f2761f0197f781d Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 18 Jul 2016 11:29:41 -0700 Subject: [PATCH 1/3] remove obsolete handControllerMouse.js to avoid confusion --- .../system/controllers/handControllerMouse.js | 131 ------------------ 1 file changed, 131 deletions(-) delete mode 100644 scripts/system/controllers/handControllerMouse.js diff --git a/scripts/system/controllers/handControllerMouse.js b/scripts/system/controllers/handControllerMouse.js deleted file mode 100644 index 921999f96a..0000000000 --- a/scripts/system/controllers/handControllerMouse.js +++ /dev/null @@ -1,131 +0,0 @@ -// -// handControllerMouse.js -// examples/controllers -// -// Created by Brad Hefta-Gaub on 2015/12/15 -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -var DEBUGGING = false; -var angularVelocityTrailingAverage = 0.0; // Global trailing average used to decide whether to move reticle at all -var lastX = 0; -var lastY = 0; - -Math.clamp=function(a,b,c) { - return Math.max(b,Math.min(c,a)); -} - -function length(posA, posB) { - var dx = posA.x - posB.x; - var dy = posA.y - posB.y; - var length = Math.sqrt((dx*dx) + (dy*dy)) - return length; -} - -function moveReticleAbsolute(x, y) { - var globalPos = Reticle.getPosition(); - globalPos.x = x; - globalPos.y = y; - Reticle.setPosition(globalPos); -} - -var MAPPING_NAME = "com.highfidelity.testing.reticleWithHandRotation"; -var mapping = Controller.newMapping(MAPPING_NAME); -if (Controller.Hardware.Hydra !== undefined) { - mapping.from(Controller.Hardware.Hydra.L3).peek().to(Controller.Actions.ReticleClick); - mapping.from(Controller.Hardware.Hydra.R4).peek().to(Controller.Actions.ReticleClick); -} -if (Controller.Hardware.Vive !== undefined) { - mapping.from(Controller.Hardware.Vive.LeftPrimaryThumb).peek().to(Controller.Actions.ReticleClick); - mapping.from(Controller.Hardware.Vive.RightPrimaryThumb).peek().to(Controller.Actions.ReticleClick); -} - -mapping.enable(); - -function debugPrint(message) { - if (DEBUGGING) { - print(message); - } -} - -var leftRightBias = 0.0; -var filteredRotatedLeft = Vec3.UNIT_NEG_Y; -var filteredRotatedRight = Vec3.UNIT_NEG_Y; -var lastAlpha = 0; - -Script.update.connect(function(deltaTime) { - - // avatar frame - var poseRight = Controller.getPoseValue(Controller.Standard.RightHand); - var poseLeft = Controller.getPoseValue(Controller.Standard.LeftHand); - - // NOTE: hack for now - var screenSize = Reticle.maximumPosition; - var screenSizeX = screenSize.x; - var screenSizeY = screenSize.y; - - // transform hand facing vectors from avatar frame into sensor frame. - var worldToSensorMatrix = Mat4.inverse(MyAvatar.sensorToWorldMatrix); - var rotatedRight = Mat4.transformVector(worldToSensorMatrix, Vec3.multiplyQbyV(MyAvatar.orientation, Vec3.multiplyQbyV(poseRight.rotation, Vec3.UNIT_NEG_Y))); - var rotatedLeft = Mat4.transformVector(worldToSensorMatrix, Vec3.multiplyQbyV(MyAvatar.orientation, Vec3.multiplyQbyV(poseLeft.rotation, Vec3.UNIT_NEG_Y))); - - lastRotatedRight = rotatedRight; - - // Decide which hand should be controlling the pointer - // by comparing which one is moving more, and by - // tending to stay with the one moving more. - if (deltaTime > 0.001) { - // leftRightBias is a running average of the difference in angular hand speed. - // a positive leftRightBias indicates the right hand is spinning faster then the left hand. - // a negative leftRightBias indicates the left hand is spnning faster. - var BIAS_ADJUST_PERIOD = 1.0; - var tau = Math.clamp(deltaTime / BIAS_ADJUST_PERIOD, 0, 1); - newLeftRightBias = Vec3.length(poseRight.angularVelocity) - Vec3.length(poseLeft.angularVelocity); - leftRightBias = (1 - tau) * leftRightBias + tau * newLeftRightBias; - } - - // add a bit of hysteresis to prevent control flopping back and forth - // between hands when they are both mostly stationary. - var alpha; - var HYSTERESIS_OFFSET = 0.25; - if (lastAlpha > 0.5) { - // prefer right hand over left - alpha = leftRightBias > -HYSTERESIS_OFFSET ? 1 : 0; - } else { - alpha = leftRightBias > HYSTERESIS_OFFSET ? 1 : 0; - } - lastAlpha = alpha; - - // Velocity filter the hand rotation used to position reticle so that it is easier to target small things with the hand controllers - var VELOCITY_FILTER_GAIN = 0.5; - filteredRotatedLeft = Vec3.mix(filteredRotatedLeft, rotatedLeft, Math.clamp(Vec3.length(poseLeft.angularVelocity) * VELOCITY_FILTER_GAIN, 0.0, 1.0)); - filteredRotatedRight = Vec3.mix(filteredRotatedRight, rotatedRight, Math.clamp(Vec3.length(poseRight.angularVelocity) * VELOCITY_FILTER_GAIN, 0.0, 1.0)); - var rotated = Vec3.mix(filteredRotatedLeft, filteredRotatedRight, alpha); - - var absolutePitch = rotated.y; // from 1 down to -1 up ... but note: if you rotate down "too far" it starts to go up again... - var absoluteYaw = -rotated.x; // from -1 left to 1 right - - var x = Math.clamp(screenSizeX * (absoluteYaw + 0.5), 0, screenSizeX); - var y = Math.clamp(screenSizeX * absolutePitch, 0, screenSizeY); - - // don't move the reticle with the hand controllers unless the controllers are actually being moved - // take a time average of angular velocity, and don't move mouse at all if it's below threshold - - var AVERAGING_INTERVAL = 0.95; - var MINIMUM_CONTROLLER_ANGULAR_VELOCITY = 0.03; - var angularVelocityMagnitude = Vec3.length(poseLeft.angularVelocity) * (1.0 - alpha) + Vec3.length(poseRight.angularVelocity) * alpha; - angularVelocityTrailingAverage = angularVelocityTrailingAverage * AVERAGING_INTERVAL + angularVelocityMagnitude * (1.0 - AVERAGING_INTERVAL); - - if ((angularVelocityTrailingAverage > MINIMUM_CONTROLLER_ANGULAR_VELOCITY) && ((x != lastX) || (y != lastY))) { - moveReticleAbsolute(x, y); - lastX = x; - lastY = y; - } -}); - -Script.scriptEnding.connect(function(){ - mapping.disable(); -}); From 959a2f9915e6ef06816135cf4d25b2b9d2b68c46 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 18 Jul 2016 13:10:16 -0700 Subject: [PATCH 2/3] far-grabbed objects no longer fly away when the avatar body shifts Before this fix, a hand vector was being tracked that was the difference between the avatar's hand in avatar space with the avatar's hand in avatar space the previous frame. This hand vector was used to move the grabbed object position. However, when the body shifts, objects in the avatar's space will change rapidly, this would cause this hand vector to be incorrect and cause the object to shoot off in the distance. Now, we track this hand delta in sensor a.k.a. room space. This is immune to the shifts caused by body shifting. --- .../system/controllers/handControllerGrab.js | 64 ++++++++----------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 66c9e10795..50d5d644ac 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -1592,13 +1592,16 @@ function MyController(hand) { this.clearEquipHaptics(); // controller pose is in avatar frame - var avatarControllerPose = - Controller.getPoseValue((this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand); + var device = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; + var avatarControllerPose = Controller.getPoseValue(device); // transform it into world frame - var controllerPositionVSAvatar = Vec3.multiplyQbyV(MyAvatar.orientation, avatarControllerPose.translation); - var controllerPosition = Vec3.sum(MyAvatar.position, controllerPositionVSAvatar); - var controllerRotation = Quat.multiply(MyAvatar.orientation, avatarControllerPose.rotation); + var worldControllerPosition = Vec3.sum(MyAvatar.position, + Vec3.multiplyQbyV(MyAvatar.orientation, avatarControllerPose.translation)); + + // also transform the position into room space + var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix()); + var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); var now = Date.now(); @@ -1609,7 +1612,7 @@ function MyController(hand) { this.currentObjectTime = now; this.currentCameraOrientation = Camera.orientation; - this.grabRadius = Vec3.distance(this.currentObjectPosition, controllerPosition); + this.grabRadius = Vec3.distance(this.currentObjectPosition, worldControllerPosition); this.grabRadialVelocity = 0.0; // compute a constant based on the initial conditions which we use below to exagerate hand motion onto the held object @@ -1644,8 +1647,7 @@ function MyController(hand) { this.turnOffVisualizations(); - this.previousControllerPositionVSAvatar = controllerPositionVSAvatar; - this.previousControllerRotation = controllerRotation; + this.previousRoomControllerPosition = roomControllerPosition; }; this.distanceHolding = function (deltaTime, timestamp) { @@ -1658,13 +1660,17 @@ function MyController(hand) { this.heartBeat(this.grabbedEntity); // controller pose is in avatar frame - var avatarControllerPose = Controller.getPoseValue((this.hand === RIGHT_HAND) ? - Controller.Standard.RightHand : Controller.Standard.LeftHand); + var device = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; + var avatarControllerPose = Controller.getPoseValue(device); // transform it into world frame - var controllerPositionVSAvatar = Vec3.multiplyQbyV(MyAvatar.orientation, avatarControllerPose.translation); - var controllerPosition = Vec3.sum(MyAvatar.position, controllerPositionVSAvatar); - var controllerRotation = Quat.multiply(MyAvatar.orientation, avatarControllerPose.rotation); + var worldControllerPosition = Vec3.sum(MyAvatar.position, + Vec3.multiplyQbyV(MyAvatar.orientation, avatarControllerPose.translation)); + var worldControllerRotation = Quat.multiply(MyAvatar.orientation, avatarControllerPose.rotation); + + // also transform the position into room space + var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix()); + var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); @@ -1673,26 +1679,15 @@ function MyController(hand) { this.currentObjectTime = now; // the action was set up when this.distanceHolding was called. update the targets. - var radius = Vec3.distance(this.currentObjectPosition, controllerPosition) * + var radius = Vec3.distance(this.currentObjectPosition, worldControllerPosition) * this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; if (radius < 1.0) { radius = 1.0; } - // scale delta controller hand movement by radius. - var handMoved = Vec3.multiply(Vec3.subtract(controllerPositionVSAvatar, this.previousControllerPositionVSAvatar), - radius); - - /// double delta controller rotation - // var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did - // var handChange = Quat.multiply(Quat.slerp(this.previousControllerRotation, - // controllerRotation, - // DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), - // Quat.inverse(this.previousControllerRotation)); - - // update the currentObject position and rotation. + var handDelta = Vec3.subtract(roomControllerPosition, this.previousRoomControllerPosition); + var handMoved = Vec3.multiply(handDelta, radius); this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, handMoved); - // this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); this.callEntityMethodOnGrabbed("continueDistantGrab"); @@ -1703,10 +1698,9 @@ function MyController(hand) { var handControllerData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultMoveWithHeadData); // Update radialVelocity - var lastVelocity = Vec3.subtract(controllerPositionVSAvatar, this.previousControllerPositionVSAvatar); - lastVelocity = Vec3.multiply(lastVelocity, 1.0 / deltaObjectTime); - var newRadialVelocity = Vec3.dot(lastVelocity, - Vec3.normalize(Vec3.subtract(grabbedProperties.position, controllerPosition))); + var lastVelocity = Vec3.multiply(handDelta, 1.0 / deltaObjectTime); + var delta = Vec3.normalize(Vec3.subtract(grabbedProperties.position, worldControllerPosition)); + var newRadialVelocity = Vec3.dot(lastVelocity, delta); var VELOCITY_AVERAGING_TIME = 0.016; this.grabRadialVelocity = (deltaObjectTime / VELOCITY_AVERAGING_TIME) * newRadialVelocity + @@ -1718,9 +1712,8 @@ function MyController(hand) { this.grabRadius * RADIAL_GRAB_AMPLIFIER); } - var newTargetPosition = Vec3.multiply(this.grabRadius, Quat.getUp(controllerRotation)); - newTargetPosition = Vec3.sum(newTargetPosition, controllerPosition); - + var newTargetPosition = Vec3.multiply(this.grabRadius, Quat.getUp(worldControllerRotation)); + newTargetPosition = Vec3.sum(newTargetPosition, worldControllerPosition); var objectToAvatar = Vec3.subtract(this.currentObjectPosition, MyAvatar.position); if (handControllerData.disableMoveWithHead !== true) { @@ -1776,8 +1769,7 @@ function MyController(hand) { print("continueDistanceHolding -- updateAction failed"); } - this.previousControllerPositionVSAvatar = controllerPositionVSAvatar; - this.previousControllerRotation = controllerRotation; + this.previousRoomControllerPosition = roomControllerPosition; }; this.setupHoldAction = function () { From 212175bdaabf4db973a978f3ebba487a7987d4e1 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 19 Jul 2016 10:23:00 -0700 Subject: [PATCH 3/3] bug fix for far-grab pulling the object in the wrong direction --- scripts/system/controllers/handControllerGrab.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 50d5d644ac..832346a5fd 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -1685,8 +1685,9 @@ function MyController(hand) { radius = 1.0; } - var handDelta = Vec3.subtract(roomControllerPosition, this.previousRoomControllerPosition); - var handMoved = Vec3.multiply(handDelta, radius); + var roomHandDelta = Vec3.subtract(roomControllerPosition, this.previousRoomControllerPosition); + var worldHandDelta = Mat4.transformVector(MyAvatar.getSensorToWorldMatrix(), roomHandDelta); + var handMoved = Vec3.multiply(worldHandDelta, radius); this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, handMoved); this.callEntityMethodOnGrabbed("continueDistantGrab"); @@ -1698,7 +1699,7 @@ function MyController(hand) { var handControllerData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultMoveWithHeadData); // Update radialVelocity - var lastVelocity = Vec3.multiply(handDelta, 1.0 / deltaObjectTime); + var lastVelocity = Vec3.multiply(worldHandDelta, 1.0 / deltaObjectTime); var delta = Vec3.normalize(Vec3.subtract(grabbedProperties.position, worldControllerPosition)); var newRadialVelocity = Vec3.dot(lastVelocity, delta);