diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 51171b9c6b..8b8f8e8c2e 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -244,14 +244,19 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) { // 3 -- ignore i of 0 1 2 // 4 -- ignore i of 1 2 3 // 5 -- ignore i of 2 3 4 - if ((i + 1) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex || - (i + 2) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex || - (i + 3) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex) { - continue; - } + + // This code is now disabled, but I'm leaving it commented-out because I suspect it will come back. + // if ((i + 1) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex || + // (i + 2) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex || + // (i + 3) % AvatarActionHold::velocitySmoothFrames == _measuredLinearVelocitiesIndex) { + // continue; + // } + measuredLinearVelocity += _measuredLinearVelocities[i]; } - measuredLinearVelocity /= (float)(AvatarActionHold::velocitySmoothFrames - 3); // 3 because of the 3 we skipped, above + measuredLinearVelocity /= (float)(AvatarActionHold::velocitySmoothFrames + // - 3 // 3 because of the 3 we skipped, above + ); if (_kinematicSetVelocity) { rigidBody->setLinearVelocity(glmToBullet(measuredLinearVelocity)); diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp index 01f607b0ed..28b19ee9e0 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp @@ -277,27 +277,37 @@ void HmdDisplayPlugin::updateFrameData() { continue; } - const auto& laserDirection = handLaser.direction; - auto model = _presentHandPoses[i]; - auto castDirection = glm::quat_cast(model) * laserDirection; + const vec3& laserDirection = handLaser.direction; + mat4 model = _presentHandPoses[i]; + vec3 castStart = vec3(model[3]); + vec3 castDirection = glm::quat_cast(model) * laserDirection; if (glm::abs(glm::length2(castDirection) - 1.0f) > EPSILON) { castDirection = glm::normalize(castDirection); castDirection = glm::inverse(_presentUiModelTransform.getRotation()) * castDirection; } + // this offset needs to match GRAB_POINT_SPHERE_OFFSET in scripts/system/libraries/controllers.js + static const vec3 GRAB_POINT_SPHERE_OFFSET = vec3(0.1f, 0.04f, -0.32f); + vec3 grabPointOffset = GRAB_POINT_SPHERE_OFFSET; + if (i == 0) { + grabPointOffset.x *= -1.0f; // this changes between left and right hands + } + castStart += glm::quat_cast(model) * grabPointOffset; + // FIXME fetch the actual UI radius from... somewhere? float uiRadius = 1.0f; // Find the intersection of the laser with he UI and use it to scale the model matrix float distance; - if (!glm::intersectRaySphere(vec3(_presentHandPoses[i][3]), castDirection, _presentUiModelTransform.getTranslation(), uiRadius * uiRadius, distance)) { + if (!glm::intersectRaySphere(castStart, castDirection, + _presentUiModelTransform.getTranslation(), uiRadius * uiRadius, distance)) { continue; } - _presentHandLaserPoints[i].first = vec3(_presentHandPoses[i][3]); + _presentHandLaserPoints[i].first = castStart; _presentHandLaserPoints[i].second = _presentHandLaserPoints[i].first + (castDirection * distance); - vec3 intersectionPosition = vec3(_presentHandPoses[i][3]) + (castDirection * distance) - _presentUiModelTransform.getTranslation(); + vec3 intersectionPosition = castStart + (castDirection * distance) - _presentUiModelTransform.getTranslation(); intersectionPosition = glm::inverse(_presentUiModelTransform.getRotation()) * intersectionPosition; // Take the interesection normal and convert it to a texture coordinate diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index b70927d501..951728c4da 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include "BulletUtil.h" #include "EntityMotionState.h" @@ -230,11 +231,17 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { bool positionSuccess; _entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset(), positionSuccess, false); if (!positionSuccess) { + static QString repeatedMessage = + LogHandler::getInstance().addRepeatedMessageRegex("EntityMotionState::setWorldTransform " + "setPosition failed.*"); qDebug() << "EntityMotionState::setWorldTransform setPosition failed" << _entity->getID(); } bool orientationSuccess; _entity->setOrientation(bulletToGLM(worldTrans.getRotation()), orientationSuccess, false); if (!orientationSuccess) { + static QString repeatedMessage = + LogHandler::getInstance().addRepeatedMessageRegex("EntityMotionState::setWorldTransform " + "setOrientation failed.*"); qDebug() << "EntityMotionState::setWorldTransform setOrientation failed" << _entity->getID(); } _entity->setVelocity(getBodyLinearVelocity()); diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index a413602ac7..734ef9e6eb 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -11,12 +11,13 @@ // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -/* global setEntityCustomData, getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings, Reticle, Controller, Camera, Messages, Mat4 */ +/* global setEntityCustomData, getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings, Reticle, Controller, Camera, Messages, Mat4, getControllerWorldLocation, getGrabPointSphereOffset */ (function() { // BEGIN LOCAL_SCOPE Script.include("/~/system/libraries/utils.js"); Script.include("/~/system/libraries/Xform.js"); +Script.include("/~/system/libraries/controllers.js"); // // add lines where the hand ray picking is happening @@ -106,19 +107,16 @@ var MAX_EQUIP_HOTSPOT_RADIUS = 1.0; var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position -var NEAR_GRAB_RADIUS = 0.07; // radius used for palm vs object for near grabbing. +var NEAR_GRAB_RADIUS = 0.04; // radius used for palm vs object for near grabbing. var NEAR_GRAB_MAX_DISTANCE = 1.0; // you cannot grab objects that are this far away from your hand var NEAR_GRAB_PICK_RADIUS = 0.25; // radius used for search ray vs object for near grabbing. - -var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed // if an equipped item is "adjusted" to be too far from the hand it's in, it will be unequipped. var CHECK_TOO_FAR_UNEQUIP_TIME = 0.3; // seconds, duration between checks -var GRAB_POINT_SPHERE_OFFSET = { x: 0.0, y: 0.2, z: 0.0 }; var GRAB_POINT_SPHERE_RADIUS = NEAR_GRAB_RADIUS; var GRAB_POINT_SPHERE_COLOR = { red: 20, green: 90, blue: 238 }; var GRAB_POINT_SPHERE_ALPHA = 0.85; @@ -722,6 +720,7 @@ var equipHotspotBuddy = new EquipHotspotBuddy(); function MyController(hand) { this.hand = hand; this.autoUnequipCounter = 0; + this.grabPointIntersectsEntity = false; // handPosition is where the avatar's hand appears to be, in-world. this.getHandPosition = function () { @@ -738,19 +737,9 @@ function MyController(hand) { return MyAvatar.getLeftPalmRotation(); } }; - // controllerLocation is where the controller would be, in-world. - this.getControllerLocation = function (doOffset) { - var standardControllerValue = (hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - var pose = Controller.getPoseValue(standardControllerValue); - var orientation = Quat.multiply(MyAvatar.orientation, pose.rotation); - var position = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation), MyAvatar.position); - // add to the real position so the grab-point is out in front of the hand, a bit - if (doOffset) { - position = Vec3.sum(position, Vec3.multiplyQbyV(orientation, GRAB_POINT_SPHERE_OFFSET)); - } - - return {position: position, orientation: orientation}; + this.handToController = function() { + return (hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; }; this.actionID = null; // action this script created... @@ -866,7 +855,7 @@ function MyController(hand) { } if (!this.grabPointSphere) { this.grabPointSphere = Overlays.addOverlay("sphere", { - localPosition: GRAB_POINT_SPHERE_OFFSET, + localPosition: getGrabPointSphereOffset(this.handToController()), localRotation: { x: 0, y: 0, z: 0, w: 1 }, dimensions: GRAB_POINT_SPHERE_RADIUS, color: GRAB_POINT_SPHERE_COLOR, @@ -1094,20 +1083,28 @@ function MyController(hand) { } if (!this.waitForTriggerRelease && this.triggerSmoothedSqueezed()) { this.lastPickTime = 0; - this.startingHandRotation = this.getControllerLocation(true).orientation; + this.startingHandRotation = getControllerWorldLocation(this.handToController(), true).orientation; if (this.triggerSmoothedSqueezed()) { this.setState(STATE_SEARCHING, "trigger squeeze detected"); return; } } - this.grabPointSphereOn(); - var candidateEntities = Entities.findEntities(this.getControllerLocation(true).position, MAX_EQUIP_HOTSPOT_RADIUS); + var controllerLocation = getControllerWorldLocation(this.handToController(), true); + var worldHandPosition = controllerLocation.position; + + if (controllerLocation.valid) { + this.grabPointSphereOn(); + } else { + this.grabPointSphereOff(); + } + + var candidateEntities = Entities.findEntities(worldHandPosition, MAX_EQUIP_HOTSPOT_RADIUS); entityPropertiesCache.addEntities(candidateEntities); var potentialEquipHotspot = this.chooseBestEquipHotspot(candidateEntities); if (!this.waitForTriggerRelease) { - this.updateEquipHaptics(potentialEquipHotspot, this.getControllerLocation(true).position); + this.updateEquipHaptics(potentialEquipHotspot, worldHandPosition); } var nearEquipHotspots = this.chooseNearEquipHotspots(candidateEntities, EQUIP_HOTSPOT_RENDER_RADIUS); @@ -1115,6 +1112,20 @@ function MyController(hand) { if (potentialEquipHotspot) { equipHotspotBuddy.highlightHotspot(potentialEquipHotspot); } + + // when the grab-point enters a grabable entity, give a haptic pulse + candidateEntities = Entities.findEntities(worldHandPosition, NEAR_GRAB_RADIUS); + var grabbableEntities = candidateEntities.filter(function(entity) { + return _this.entityIsNearGrabbable(entity, worldHandPosition, NEAR_GRAB_MAX_DISTANCE); + }); + if (grabbableEntities.length > 0) { + if (!this.grabPointIntersectsEntity) { + Controller.triggerHapticPulse(1, 20, this.hand); + this.grabPointIntersectsEntity = true; + } + } else { + this.grabPointIntersectsEntity = false; + } }; this.clearEquipHaptics = function() { @@ -1144,7 +1155,7 @@ function MyController(hand) { // @returns {object} returns object with two keys entityID and distance // this.calcRayPickInfo = function(hand) { - var controllerLocation = this.getControllerLocation(true); + var controllerLocation = getControllerWorldLocation(this.handToController(), true); var worldHandPosition = controllerLocation.position; var worldHandRotation = controllerLocation.orientation; @@ -1168,18 +1179,11 @@ function MyController(hand) { } this.lastPickTime = now; - var directionNormalized = Vec3.normalize(pickRay.direction); - var directionBacked = Vec3.multiply(directionNormalized, PICK_BACKOFF_DISTANCE); - var pickRayBacked = { - origin: Vec3.subtract(pickRay.origin, directionBacked), - direction: pickRay.direction - }; - var intersection; if (USE_BLACKLIST === true && blacklist.length !== 0) { - intersection = findRayIntersection(pickRayBacked, true, [], blacklist); + intersection = findRayIntersection(pickRay, true, [], blacklist); } else { - intersection = findRayIntersection(pickRayBacked, true); + intersection = findRayIntersection(pickRay, true); } if (intersection.intersects) { @@ -1392,7 +1396,8 @@ function MyController(hand) { return _this.collectEquipHotspots(entityID); })).filter(function(hotspot) { return (_this.hotspotIsEquippable(hotspot) && - Vec3.distance(hotspot.worldPosition, _this.getControllerLocation(true).position) < hotspot.radius + distance); + Vec3.distance(hotspot.worldPosition, getControllerWorldLocation(_this.handToController(), true).position) < + hotspot.radius + distance); }); return equippableHotspots; }; @@ -1403,8 +1408,9 @@ function MyController(hand) { if (equippableHotspots.length > 0) { // sort by distance equippableHotspots.sort(function(a, b) { - var aDistance = Vec3.distance(a.worldPosition, this.getControllerLocation(true).position); - var bDistance = Vec3.distance(b.worldPosition, this.getControllerLocation(true).position); + var handControllerLocation = getControllerWorldLocation(this.handToController(), true); + var aDistance = Vec3.distance(a.worldPosition, handControllerLocation.position); + var bDistance = Vec3.distance(b.worldPosition, handControllerLocation.position); return aDistance - bDistance; }); return equippableHotspots[0]; @@ -1430,8 +1436,6 @@ function MyController(hand) { this.isInitialGrab = false; this.shouldResetParentOnRelease = false; - this.grabPointSphereOn(); - this.checkForStrayChildren(); if (this.triggerSmoothedReleased()) { @@ -1439,7 +1443,14 @@ function MyController(hand) { return; } - var handPosition = this.getControllerLocation(true).position; + var controllerLocation = getControllerWorldLocation(this.handToController(), true); + var handPosition = controllerLocation.position; + + if (controllerLocation.valid) { + this.grabPointSphereOn(); + } else { + this.grabPointSphereOff(); + } var rayPickInfo = this.calcRayPickInfo(this.hand); @@ -1624,7 +1635,7 @@ function MyController(hand) { this.clearEquipHaptics(); this.grabPointSphereOff(); - var worldControllerPosition = this.getControllerLocation(true).position; + var worldControllerPosition = getControllerWorldLocation(this.handToController(), true).position; // transform the position into room space var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix()); @@ -1642,7 +1653,8 @@ function MyController(hand) { 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 + // compute a constant based on the initial conditions which we use below to exagerate hand motion + // onto the held object this.radiusScalar = Math.log(this.grabRadius + 1.0); if (this.radiusScalar < 1.0) { this.radiusScalar = 1.0; @@ -1668,7 +1680,7 @@ function MyController(hand) { this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC); if (this.actionID !== null) { - this.activateEntity(this.grabbedEntity, grabbedProperties, false); + this.activateEntity(this.grabbedEntity, grabbedProperties, false, true); this.callEntityMethodOnGrabbed("startDistanceGrab"); } @@ -1683,14 +1695,22 @@ function MyController(hand) { if (!this.triggerClicked) { this.callEntityMethodOnGrabbed("releaseGrab"); + + // if we distance hold something and keep it very still before releasing it, it ends up + // non-dynamic in bullet. If it's too still, give it a little bounce so it will fall. + var velocity = Entities.getEntityProperties(this.grabbedEntity, ["velocity"]).velocity; + if (Vec3.length(velocity) < 0.05) { // see EntityMotionState.cpp DYNAMIC_LINEAR_VELOCITY_THRESHOLD + velocity = { x: 0.0, y: 0.2, z:0.0 }; + Entities.editEntity(this.grabbedEntity, { velocity: velocity }); + } + this.setState(STATE_OFF, "trigger released"); return; } this.heartBeat(this.grabbedEntity); - - var controllerLocation = this.getControllerLocation(true); + var controllerLocation = getControllerWorldLocation(this.handToController(), true); var worldControllerPosition = controllerLocation.position; var worldControllerRotation = controllerLocation.orientation; @@ -1736,7 +1756,13 @@ function MyController(hand) { var RADIAL_GRAB_AMPLIFIER = 10.0; if (Math.abs(this.grabRadialVelocity) > 0.0) { this.grabRadius = this.grabRadius + (this.grabRadialVelocity * deltaObjectTime * - this.grabRadius * RADIAL_GRAB_AMPLIFIER); + this.grabRadius * RADIAL_GRAB_AMPLIFIER); + } + + // don't let grabRadius go all the way to zero, because it can't come back from that + var MINIMUM_GRAB_RADIUS = 0.1; + if (this.grabRadius < MINIMUM_GRAB_RADIUS) { + this.grabRadius = MINIMUM_GRAB_RADIUS; } var newTargetPosition = Vec3.multiply(this.grabRadius, Quat.getUp(worldControllerRotation)); @@ -1827,7 +1853,7 @@ function MyController(hand) { }; this.dropGestureProcess = function(deltaTime) { - var worldHandRotation = this.getControllerLocation(true).orientation; + var worldHandRotation = getControllerWorldLocation(this.handToController(), true).orientation; var localHandUpAxis = this.hand === RIGHT_HAND ? { x: 1, y: 0, @@ -1893,7 +1919,7 @@ function MyController(hand) { } var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - this.activateEntity(this.grabbedEntity, grabbedProperties, false); + this.activateEntity(this.grabbedEntity, grabbedProperties, false, false); var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); if (FORCE_IGNORE_IK) { @@ -1905,7 +1931,7 @@ function MyController(hand) { var handRotation; var handPosition; if (this.ignoreIK) { - var controllerLocation = this.getControllerLocation(false); + var controllerLocation = getControllerWorldLocation(this.handToController(), false); handRotation = controllerLocation.orientation; handPosition = controllerLocation.position; } else { @@ -2085,7 +2111,7 @@ function MyController(hand) { if (props.parentID == MyAvatar.sessionUUID) { var handPosition; if (this.ignoreIK) { - handPosition = this.getControllerLocation(false).position; + handPosition = getControllerWorldLocation(this.handToController(), false).position; } else { handPosition = this.getHandPosition(); } @@ -2201,8 +2227,8 @@ function MyController(hand) { } var pickRay = { - origin: this.getControllerLocation().position, - direction: Quat.getUp(this.getControllerLocation().orientation) + origin: getControllerWorldLocation(this.handToController(), false).position, + direction: Quat.getUp(getControllerWorldLocation(this.handToController(), false).orientation) }; var now = Date.now(); @@ -2231,7 +2257,8 @@ function MyController(hand) { this.entityTouchingEnter = function() { // test for intersection between controller laser and web entity plane. - var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, this.getControllerLocation(true)); + var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, + getControllerWorldLocation(this.handToController(), true)); if (intersectInfo) { var pointerEvent = { type: "Press", @@ -2256,7 +2283,8 @@ function MyController(hand) { this.entityTouchingExit = function() { // test for intersection between controller laser and web entity plane. - var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, this.getControllerLocation(true)); + var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, + getControllerWorldLocation(this.handToController(), true)); if (intersectInfo) { var pointerEvent; if (this.deadspotExpired) { @@ -2295,7 +2323,8 @@ function MyController(hand) { } // test for intersection between controller laser and web entity plane. - var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, this.getControllerLocation(true)); + var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, + getControllerWorldLocation(this.handToController(), true)); if (intersectInfo) { if (Entities.keyboardFocusEntity != this.grabbedEntity) { @@ -2400,7 +2429,7 @@ function MyController(hand) { this.deactivateEntity(entityID, false); }; - this.activateEntity = function(entityID, grabbedProperties, wasLoaded) { + this.activateEntity = function(entityID, grabbedProperties, wasLoaded, collideWithStatic) { this.autoUnequipCounter = 0; if (this.entityActivated) { @@ -2441,15 +2470,10 @@ function MyController(hand) { data.parentJointIndex = grabbedProperties.parentJointIndex; var whileHeldProperties = { - gravity: { - x: 0, - y: 0, - z: 0 - }, - // bummer, it isn't easy to do bitwise collisionMask operations like this: - // "collisionMask": COLLISION_MASK_WHILE_GRABBED | grabbedProperties.collisionMask - // when using string values - "collidesWith": COLLIDES_WITH_WHILE_GRABBED + gravity: { x: 0, y: 0, z: 0 }, + "collidesWith": collideWithStatic ? + COLLIDES_WITH_WHILE_GRABBED + ",static" : + COLLIDES_WITH_WHILE_GRABBED }; Entities.editEntity(entityID, whileHeldProperties); } else if (data.refCount > 1) { @@ -2458,7 +2482,7 @@ function MyController(hand) { // deactivate it before grabbing. this.resetAbandonedGrab(entityID); grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - return this.activateEntity(entityID, grabbedProperties, wasLoaded); + return this.activateEntity(entityID, grabbedProperties, wasLoaded, false); } this.isInitialGrab = false; diff --git a/scripts/system/controllers/handControllerPointer.js b/scripts/system/controllers/handControllerPointer.js index 6b62674be5..ce98ed6d8e 100644 --- a/scripts/system/controllers/handControllerPointer.js +++ b/scripts/system/controllers/handControllerPointer.js @@ -20,6 +20,7 @@ // When partially squeezing over a HUD element, a laser or the reticle is shown where the active hand // controller beam intersects the HUD. +Script.include("/~/system/libraries/controllers.js"); // UTILITIES ------------- // @@ -203,16 +204,13 @@ function overlayFromWorldPoint(point) { } function activeHudPoint2d(activeHand) { // if controller is valid, update reticle position and answer 2d point. Otherwise falsey. - var controllerPose = Controller.getPoseValue(activeHand); - // Valid if any plugged-in hand controller is "on". (uncradled Hydra, green-lighted Vive...) + var controllerPose = getControllerWorldLocation(activeHand, true); if (!controllerPose.valid) { return; // Controller is cradled. } - var controllerPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, controllerPose.translation), - MyAvatar.position); - // This gets point direction right, but if you want general quaternion it would be more complicated: - var controllerDirection = Quat.getUp(Quat.multiply(MyAvatar.orientation, controllerPose.rotation)); - + var controllerPosition = controllerPose.position; + var controllerDirection = Quat.getUp(controllerPose.rotation); + var hudPoint3d = calculateRayUICollisionPoint(controllerPosition, controllerDirection); if (!hudPoint3d) { if (Menu.isOptionChecked("Overlays")) { // With our hud resetting strategy, hudPoint3d should be valid here diff --git a/scripts/system/libraries/controllers.js b/scripts/system/libraries/controllers.js new file mode 100644 index 0000000000..9bae46380e --- /dev/null +++ b/scripts/system/libraries/controllers.js @@ -0,0 +1,46 @@ +// handControllerGrab.js +// +// Created by Seth Alves on 2016-9-7 +// Copyright 2016 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 +/* global MyAvatar, Vec3, Controller, Quat */ + + +// var GRAB_POINT_SPHERE_OFFSET = { x: 0, y: 0.2, z: 0 }; +// var GRAB_POINT_SPHERE_OFFSET = { x: 0.1, y: 0.175, z: 0.04 }; + +// this offset needs to match the one in libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp +var GRAB_POINT_SPHERE_OFFSET = { x: 0.1, y: 0.32, z: 0.04 }; + +getGrabPointSphereOffset = function(handController) { + if (handController === Controller.Standard.RightHand) { + return GRAB_POINT_SPHERE_OFFSET; + } + return { + x: GRAB_POINT_SPHERE_OFFSET.x * -1, + y: GRAB_POINT_SPHERE_OFFSET.y, + z: GRAB_POINT_SPHERE_OFFSET.z + }; +}; + +// controllerWorldLocation is where the controller would be, in-world, with an added offset +getControllerWorldLocation = function (handController, doOffset) { + var orientation; + var position; + var pose = Controller.getPoseValue(handController); + if (pose.valid) { + orientation = Quat.multiply(MyAvatar.orientation, pose.rotation); + position = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation), MyAvatar.position); + // add to the real position so the grab-point is out in front of the hand, a bit + if (doOffset) { + position = Vec3.sum(position, Vec3.multiplyQbyV(orientation, getGrabPointSphereOffset(handController))); + } + } + return {position: position, + translation: position, + orientation: orientation, + rotation: orientation, + valid: pose.valid}; +}; diff --git a/scripts/system/mod.js b/scripts/system/mod.js index b2c9785539..1a7b3b401e 100644 --- a/scripts/system/mod.js +++ b/scripts/system/mod.js @@ -10,9 +10,13 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +/* global Toolbars, Script, Users, Overlays, AvatarList, Controller, Camera, getControllerWorldLocation */ + (function() { // BEGIN LOCAL_SCOPE +Script.include("/~/system/libraries/controllers.js"); + // grab the toolbar var toolbar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system"); @@ -144,7 +148,7 @@ AvatarList.avatarRemovedEvent.connect(function(avatarID){ function handleSelectedOverlay(clickedOverlay) { // see this is one of our mod overlays - var modOverlayKeys = Object.keys(modOverlays) + var modOverlayKeys = Object.keys(modOverlays); for (var i = 0; i < modOverlayKeys.length; ++i) { var avatarID = modOverlayKeys[i]; var modOverlay = modOverlays[avatarID]; @@ -187,13 +191,9 @@ Controller.mousePressEvent.connect(function(event){ var triggerMapping = Controller.newMapping(Script.resolvePath('') + '-click'); function controllerComputePickRay(hand) { - var controllerPose = Controller.getPoseValue(hand); + var controllerPose = getControllerWorldLocation(hand, true); if (controllerPose.valid) { - var controllerPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, controllerPose.translation), - MyAvatar.position); - // This gets point direction right, but if you want general quaternion it would be more complicated: - var controllerDirection = Quat.getUp(Quat.multiply(MyAvatar.orientation, controllerPose.rotation)); - return { origin: controllerPosition, direction: controllerDirection }; + return { origin: controllerPose.position, direction: controllerPose.orientation }; } }