From 36beea17fabf6e0829e21ba580d84d03890df788 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 28 Dec 2015 14:59:43 -0800 Subject: [PATCH] Improved hand controller reticle movement --- .../controllers/reticleHandRotationTest.js | 192 +++--------------- 1 file changed, 24 insertions(+), 168 deletions(-) diff --git a/examples/controllers/reticleHandRotationTest.js b/examples/controllers/reticleHandRotationTest.js index ece9283deb..a303e5e7b4 100644 --- a/examples/controllers/reticleHandRotationTest.js +++ b/examples/controllers/reticleHandRotationTest.js @@ -22,33 +22,13 @@ function length(posA, posB) { return length; } -var EXPECTED_CHANGE = 50; -var lastPos = Controller.getReticlePosition(); function moveReticleAbsolute(x, y) { var globalPos = Controller.getReticlePosition(); - var dX = x - globalPos.x; - var dY = y - globalPos.y; - - // some debugging to see if position is jumping around on us... - var distanceSinceLastMove = length(lastPos, globalPos); - if (distanceSinceLastMove > EXPECTED_CHANGE) { - debugPrint("------------------ distanceSinceLastMove:" + distanceSinceLastMove + "----------------------------"); - } - - if (Math.abs(dX) > EXPECTED_CHANGE) { - debugPrint("surpressing unexpectedly large change dX:" + dX + "----------------------------"); - } - if (Math.abs(dY) > EXPECTED_CHANGE) { - debugPrint("surpressing unexpectedly large change dY:" + dY + "----------------------------"); - } - globalPos.x = x; globalPos.y = y; Controller.setReticlePosition(globalPos); - lastPos = globalPos; } - var MAPPING_NAME = "com.highfidelity.testing.reticleWithHandRotation"; var mapping = Controller.newMapping(MAPPING_NAME); mapping.from(Controller.Standard.LT).peek().constrainToInteger().to(Controller.Actions.ReticleClick); @@ -56,8 +36,6 @@ mapping.from(Controller.Standard.RT).peek().constrainToInteger().to(Controller.A mapping.enable(); -var lastRotatedLeft = Vec3.UNIT_NEG_Y; -var lastRotatedRight = Vec3.UNIT_NEG_Y; function debugPrint(message) { if (DEBUGGING) { @@ -65,24 +43,9 @@ function debugPrint(message) { } } -var MAX_WAKE_UP_DISTANCE = 0.005; -var MIN_WAKE_UP_DISTANCE = 0.001; -var INITIAL_WAKE_UP_DISTANCE = MIN_WAKE_UP_DISTANCE; -var INCREMENTAL_WAKE_UP_DISTANCE = 0.001; - -var MAX_SLEEP_DISTANCE = 0.0004; -var MIN_SLEEP_DISTANCE = 0.00001; //0.00002; -var INITIAL_SLEEP_DISTANCE = MIN_SLEEP_DISTANCE; -var INCREMENTAL_SLEEP_DISTANCE = 0.000002; // 0.00002; - -var leftAsleep = true; -var rightAsleep = true; - -var leftWakeUpDistance = INITIAL_WAKE_UP_DISTANCE; -var rightWakeUpDistance = INITIAL_WAKE_UP_DISTANCE; - -var leftSleepDistance = INITIAL_SLEEP_DISTANCE; -var rightSleepDistance = INITIAL_SLEEP_DISTANCE; +var leftRightBias = 0.0; +var filteredRotatedLeft = Vec3.UNIT_NEG_Y; +var filteredRotatedRight = Vec3.UNIT_NEG_Y; Script.update.connect(function(deltaTime) { @@ -96,153 +59,46 @@ Script.update.connect(function(deltaTime) { var rotatedRight = Vec3.multiplyQbyV(poseRight.rotation, Vec3.UNIT_NEG_Y); var rotatedLeft = Vec3.multiplyQbyV(poseLeft.rotation, Vec3.UNIT_NEG_Y); - var suppressRight = false; - var suppressLeft = false; - - // What I really want to do is to slowly increase the epsilon you have to move it - // to wake up, the longer you go without moving it - var leftDistance = Vec3.distance(rotatedLeft, lastRotatedLeft); - var rightDistance = Vec3.distance(rotatedRight, lastRotatedRight); - - // check to see if hand should wakeup or sleep - if (leftAsleep) { - if (leftDistance > leftWakeUpDistance) { - leftAsleep = false; - leftSleepDistance = INITIAL_SLEEP_DISTANCE; - leftWakeUpDistance = INITIAL_WAKE_UP_DISTANCE; - } else { - // grow the wake up distance to make it harder to wake up - leftWakeUpDistance = Math.min(leftWakeUpDistance + INCREMENTAL_WAKE_UP_DISTANCE, MAX_WAKE_UP_DISTANCE); - } - } else { - // we are awake, determine if we should fall asleep, if we haven't moved - // at least as much as our sleep distance then we sleep - if (leftDistance < leftSleepDistance) { - leftAsleep = true; - leftSleepDistance = INITIAL_SLEEP_DISTANCE; - leftWakeUpDistance = INITIAL_WAKE_UP_DISTANCE; - } else { - // if we moved more than the sleep amount, but we moved less than the max sleep - // amount, then increase our liklihood of sleep. - if (leftDistance < MAX_SLEEP_DISTANCE) { - print("growing sleep...."); - leftSleepDistance = Math.max(leftSleepDistance + INCREMENTAL_SLEEP_DISTANCE, MAX_SLEEP_DISTANCE); - } else { - // otherwise reset it to initial - leftSleepDistance = INITIAL_SLEEP_DISTANCE; - } - } - } - if (leftAsleep) { - suppressLeft = true; - debugPrint("suppressing left not moving enough"); - } - - // check to see if hand should wakeup or sleep - if (rightAsleep) { - if (rightDistance > rightWakeUpDistance) { - rightAsleep = false; - rightSleepDistance = INITIAL_SLEEP_DISTANCE; - rightWakeUpDistance = INITIAL_WAKE_UP_DISTANCE; - } else { - // grow the wake up distance to make it harder to wake up - rightWakeUpDistance = Math.min(rightWakeUpDistance + INCREMENTAL_WAKE_UP_DISTANCE, MAX_WAKE_UP_DISTANCE); - } - } else { - // we are awake, determine if we should fall asleep, if we haven't moved - // at least as much as our sleep distance then we sleep - if (rightDistance < rightSleepDistance) { - rightAsleep = true; - rightSleepDistance = INITIAL_SLEEP_DISTANCE; - rightWakeUpDistance = INITIAL_WAKE_UP_DISTANCE; - } else { - // if we moved more than the sleep amount, but we moved less than the max sleep - // amount, then increase our liklihood of sleep. - if (rightDistance < MAX_SLEEP_DISTANCE) { - print("growing sleep...."); - rightSleepDistance = Math.max(rightSleepDistance + INCREMENTAL_SLEEP_DISTANCE, MAX_SLEEP_DISTANCE); - } else { - // otherwise reset it to initial - rightSleepDistance = INITIAL_SLEEP_DISTANCE; - } - } - } - if (rightAsleep) { - suppressRight = true; - debugPrint("suppressing right not moving enough"); - } - - // check to see if hand is on base station - if (Vec3.equal(rotatedLeft, Vec3.UNIT_NEG_Y)) { - suppressLeft = true; - debugPrint("suppressing left on base station"); - } - if (Vec3.equal(rotatedRight, Vec3.UNIT_NEG_Y)) { - suppressRight = true; - debugPrint("suppressing right on base station"); - } - - // Keep track of last rotations, to detect resting (but not on base station hands) in the future - lastRotatedLeft = rotatedLeft; lastRotatedRight = rotatedRight; - if (suppressLeft && suppressRight) { - debugPrint("both hands suppressed bail out early"); - return; + + // 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. + var BIAS_ADJUST_RATE = 0.5; + var BIAS_ADJUST_DEADZONE = 0.05; + leftRightBias += (Vec3.length(poseRight.angularVelocity) - Vec3.length(poseLeft.angularVelocity)) * BIAS_ADJUST_RATE; + if (leftRightBias < BIAS_ADJUST_DEADZONE) { + leftRightBias = 0.0; + } else if (leftRightBias > (1.0 - BIAS_ADJUST_DEADZONE)) { + leftRightBias = 1.0; } - if (suppressLeft) { - debugPrint("right only"); - rotatedLeft = rotatedRight; - } - if (suppressRight) { - debugPrint("left only"); - rotatedRight = rotatedLeft; - } - - // Average the two hand positions, if either hand is on base station, the - // other hand becomes the only used hand and the average is the hand in use - var rotated = Vec3.multiply(Vec3.sum(rotatedRight,rotatedLeft), 0.5); - - if (DEBUGGING) { - Vec3.print("rotatedRight:", rotatedRight); - Vec3.print("rotatedLeft:", rotatedLeft); - Vec3.print("rotated:", rotated); - } + // 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 = 1.0; + 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, leftRightBias); 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 - if (DEBUGGING) { - print("absolutePitch:" + absolutePitch); - print("absoluteYaw:" + absoluteYaw); - Vec3.print("rotated:", rotated); - } - var ROTATION_BOUND = 0.6; var clampYaw = Math.clamp(absoluteYaw, -ROTATION_BOUND, ROTATION_BOUND); var clampPitch = Math.clamp(absolutePitch, -ROTATION_BOUND, ROTATION_BOUND); - if (DEBUGGING) { - print("clampYaw:" + clampYaw); - print("clampPitch:" + clampPitch); - } // using only from -ROTATION_BOUND to ROTATION_BOUND var xRatio = (clampYaw + ROTATION_BOUND) / (2 * ROTATION_BOUND); var yRatio = (clampPitch + ROTATION_BOUND) / (2 * ROTATION_BOUND); - if (DEBUGGING) { - print("xRatio:" + xRatio); - print("yRatio:" + yRatio); - } - var x = screenSizeX * xRatio; var y = screenSizeY * yRatio; - if (DEBUGGING) { - print("position x:" + x + " y:" + y); - } - if (!(xRatio == 0.5 && yRatio == 0)) { + // don't move the reticle with the hand controllers unless the controllers are actually being moved + var MINIMUM_CONTROLLER_ANGULAR_VELOCITY = 0.0001; + var angularVelocityMagnitude = Vec3.length(poseLeft.angularVelocity) * (1.0 - leftRightBias) + Vec3.length(poseRight.angularVelocity) * leftRightBias; + + if (!(xRatio == 0.5 && yRatio == 0) && (angularVelocityMagnitude > MINIMUM_CONTROLLER_ANGULAR_VELOCITY)) { moveReticleAbsolute(x, y); } });