Merge pull request #14464 from ctrlaltdavid/M17406

Fix fax grab to near grab transition and haptic pulses
This commit is contained in:
Jeff Clinton 2018-11-30 09:18:51 -08:00 committed by GitHub
commit 04f09d70e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 26 additions and 40 deletions

View file

@ -61,6 +61,8 @@ Script.include("/~/system/libraries/controllers.js");
this.reticleMinY = MARGIN; this.reticleMinY = MARGIN;
this.reticleMaxY = 0; this.reticleMaxY = 0;
this.lastUnexpectedChildrenCheckTime = 0; this.lastUnexpectedChildrenCheckTime = 0;
this.endedGrab = 0;
this.MIN_HAPTIC_PULSE_INTERVAL = 500; // ms
var FAR_GRAB_JOINTS = [65527, 65528]; // FARGRAB_LEFTHAND_INDEX, FARGRAB_RIGHTHAND_INDEX var FAR_GRAB_JOINTS = [65527, 65528]; // FARGRAB_LEFTHAND_INDEX, FARGRAB_RIGHTHAND_INDEX
@ -144,7 +146,12 @@ Script.include("/~/system/libraries/controllers.js");
// compute the mass for the purpose of energy and how quickly to move object // compute the mass for the purpose of energy and how quickly to move object
this.mass = this.getMass(grabbedProperties.dimensions, grabbedProperties.density); this.mass = this.getMass(grabbedProperties.dimensions, grabbedProperties.density);
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); // Debounce haptic pules. Can occur as near grab controller module vacillates between being ready or not due to
// changing positions and floating point rounding.
if (Date.now() - this.endedGrab > this.MIN_HAPTIC_PULSE_INTERVAL) {
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
}
unhighlightTargetEntity(this.targetEntityID); unhighlightTargetEntity(this.targetEntityID);
var message = { var message = {
hand: this.hand, hand: this.hand,
@ -256,7 +263,7 @@ Script.include("/~/system/libraries/controllers.js");
}; };
this.endFarParentGrab = function (controllerData) { this.endFarParentGrab = function (controllerData) {
this.hapticTargetID = null; this.endedGrab = Date.now();
// var endProps = controllerData.nearbyEntityPropertiesByID[this.targetEntityID]; // var endProps = controllerData.nearbyEntityPropertiesByID[this.targetEntityID];
var endProps = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES); var endProps = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES);
if (this.thisFarGrabJointIsParent(endProps)) { if (this.thisFarGrabJointIsParent(endProps)) {
@ -410,11 +417,6 @@ Script.include("/~/system/libraries/controllers.js");
if (targetEntity) { if (targetEntity) {
var gtProps = Entities.getEntityProperties(targetEntity, DISPATCHER_PROPERTIES); var gtProps = Entities.getEntityProperties(targetEntity, DISPATCHER_PROPERTIES);
if (entityIsGrabbable(gtProps)) { if (entityIsGrabbable(gtProps)) {
// give haptic feedback
if (gtProps.id !== this.hapticTargetID) {
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
this.hapticTargetID = gtProps.id;
}
// if we've attempted to grab a child, roll up to the root of the tree // if we've attempted to grab a child, roll up to the root of the tree
var groupRootProps = findGroupParent(controllerData, gtProps); var groupRootProps = findGroupParent(controllerData, gtProps);
if (entityIsGrabbable(groupRootProps)) { if (entityIsGrabbable(groupRootProps)) {

View file

@ -24,7 +24,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
this.hand = hand; this.hand = hand;
this.targetEntityID = null; this.targetEntityID = null;
this.actionID = null; // action this script created... this.actionID = null; // action this script created...
this.hapticTargetID = null;
this.parameters = makeDispatcherModuleParameters( this.parameters = makeDispatcherModuleParameters(
500, 500,
@ -164,10 +163,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
break; break;
} }
if (entityIsGrabbable(props) || entityIsCloneable(props)) { if (entityIsGrabbable(props) || entityIsCloneable(props)) {
if (props.id !== this.hapticTargetID) {
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
this.hapticTargetID = props.id;
}
if (!entityIsCloneable(props)) { if (!entityIsCloneable(props)) {
// if we've attempted to grab a non-cloneable child, roll up to the root of the tree // if we've attempted to grab a non-cloneable child, roll up to the root of the tree
var groupRootProps = findGroupParent(controllerData, props); var groupRootProps = findGroupParent(controllerData, props);
@ -199,7 +194,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
return makeRunningValues(true, [this.targetEntityID], []); return makeRunningValues(true, [this.targetEntityID], []);
} }
} else { } else {
this.hapticTargetID = null;
return makeRunningValues(false, [], []); return makeRunningValues(false, [], []);
} }
}; };
@ -209,7 +203,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
if (controllerData.triggerClicks[this.hand] < TRIGGER_OFF_VALUE && if (controllerData.triggerClicks[this.hand] < TRIGGER_OFF_VALUE &&
controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) { controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) {
this.endNearGrabAction(); this.endNearGrabAction();
this.hapticTargetID = null;
return makeRunningValues(false, [], []); return makeRunningValues(false, [], []);
} }

View file

@ -11,7 +11,7 @@
TRIGGER_OFF_VALUE, makeDispatcherModuleParameters, entityIsGrabbable, makeRunningValues, NEAR_GRAB_RADIUS, TRIGGER_OFF_VALUE, makeDispatcherModuleParameters, entityIsGrabbable, makeRunningValues, NEAR_GRAB_RADIUS,
findGroupParent, Vec3, cloneEntity, entityIsCloneable, propsAreCloneDynamic, HAPTIC_PULSE_STRENGTH, findGroupParent, Vec3, cloneEntity, entityIsCloneable, propsAreCloneDynamic, HAPTIC_PULSE_STRENGTH,
HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, findHandChildEntities, TEAR_AWAY_DISTANCE, MSECS_PER_SEC, TEAR_AWAY_CHECK_TIME, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE, findHandChildEntities, TEAR_AWAY_DISTANCE, MSECS_PER_SEC, TEAR_AWAY_CHECK_TIME,
TEAR_AWAY_COUNT, distanceBetweenPointAndEntityBoundingBox, print, Uuid, TEAR_AWAY_COUNT, distanceBetweenPointAndEntityBoundingBox, print, Uuid, NEAR_GRAB_DISTANCE,
distanceBetweenEntityLocalPositionAndBoundingBox, getGrabbableData, getGrabPointSphereOffset, DISPATCHER_PROPERTIES distanceBetweenEntityLocalPositionAndBoundingBox, getGrabbableData, getGrabPointSphereOffset, DISPATCHER_PROPERTIES
*/ */
@ -24,15 +24,6 @@ Script.include("/~/system/libraries/controllers.js");
// XXX this.ignoreIK = (grabbableData.ignoreIK !== undefined) ? grabbableData.ignoreIK : true; // XXX this.ignoreIK = (grabbableData.ignoreIK !== undefined) ? grabbableData.ignoreIK : true;
// XXX this.kinematicGrab = (grabbableData.kinematic !== undefined) ? grabbableData.kinematic : NEAR_GRABBING_KINEMATIC; // XXX this.kinematicGrab = (grabbableData.kinematic !== undefined) ? grabbableData.kinematic : NEAR_GRABBING_KINEMATIC;
// this offset needs to match the one in libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp:378
var GRAB_POINT_SPHERE_OFFSET = { x: 0.04, y: 0.13, z: 0.039 }; // x = upward, y = forward, z = lateral
function getGrabOffset(handController) {
var offset = getGrabPointSphereOffset(handController, true);
offset.y = -offset.y;
return Vec3.multiply(MyAvatar.sensorToWorldScale, offset);
}
function NearParentingGrabEntity(hand) { function NearParentingGrabEntity(hand) {
this.hand = hand; this.hand = hand;
this.targetEntityID = null; this.targetEntityID = null;
@ -40,7 +31,6 @@ Script.include("/~/system/libraries/controllers.js");
this.previousParentID = {}; this.previousParentID = {};
this.previousParentJointIndex = {}; this.previousParentJointIndex = {};
this.previouslyUnhooked = {}; this.previouslyUnhooked = {};
this.hapticTargetID = null;
this.lastUnequipCheckTime = 0; this.lastUnequipCheckTime = 0;
this.autoUnequipCounter = 0; this.autoUnequipCounter = 0;
this.lastUnexpectedChildrenCheckTime = 0; this.lastUnexpectedChildrenCheckTime = 0;
@ -138,7 +128,6 @@ Script.include("/~/system/libraries/controllers.js");
}; };
this.endNearParentingGrabEntity = function (controllerData) { this.endNearParentingGrabEntity = function (controllerData) {
this.hapticTargetID = null;
var props = controllerData.nearbyEntityPropertiesByID[this.targetEntityID]; var props = controllerData.nearbyEntityPropertiesByID[this.targetEntityID];
if (this.thisHandIsParent(props) && !this.robbed) { if (this.thisHandIsParent(props) && !this.robbed) {
Entities.editEntity(this.targetEntityID, { Entities.editEntity(this.targetEntityID, {
@ -169,8 +158,10 @@ Script.include("/~/system/libraries/controllers.js");
this.lastUnequipCheckTime = now; this.lastUnequipCheckTime = now;
if (props.parentID === MyAvatar.SELF_ID) { if (props.parentID === MyAvatar.SELF_ID) {
var tearAwayDistance = TEAR_AWAY_DISTANCE * MyAvatar.sensorToWorldScale; var tearAwayDistance = TEAR_AWAY_DISTANCE * MyAvatar.sensorToWorldScale;
var controllerIndex = (this.hand === LEFT_HAND ? Controller.Standard.LeftHand : Controller.Standard.RightHand); var controllerIndex =
var controllerGrabOffset = getGrabOffset(controllerIndex); this.hand === LEFT_HAND ? Controller.Standard.LeftHand : Controller.Standard.RightHand;
var controllerGrabOffset = getGrabPointSphereOffset(controllerIndex, true);
controllerGrabOffset = Vec3.multiply(-MyAvatar.sensorToWorldScale, controllerGrabOffset);
var distance = distanceBetweenEntityLocalPositionAndBoundingBox(props, controllerGrabOffset); var distance = distanceBetweenEntityLocalPositionAndBoundingBox(props, controllerGrabOffset);
if (distance > tearAwayDistance) { if (distance > tearAwayDistance) {
this.autoUnequipCounter++; this.autoUnequipCounter++;
@ -233,21 +224,18 @@ Script.include("/~/system/libraries/controllers.js");
// nearbyEntityProperties is already sorted by length from controller // nearbyEntityProperties is already sorted by length from controller
var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand]; var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand];
var sensorScaleFactor = MyAvatar.sensorToWorldScale; var sensorScaleFactor = MyAvatar.sensorToWorldScale;
var nearGrabDistance = NEAR_GRAB_DISTANCE * sensorScaleFactor;
var nearGrabRadius = NEAR_GRAB_RADIUS * sensorScaleFactor;
for (var i = 0; i < nearbyEntityProperties.length; i++) { for (var i = 0; i < nearbyEntityProperties.length; i++) {
var props = nearbyEntityProperties[i]; var props = nearbyEntityProperties[i];
var handPosition = controllerData.controllerLocations[this.hand].position; var grabPosition = controllerData.controllerLocations[this.hand].position; // Is offset from hand position.
var dist = distanceBetweenPointAndEntityBoundingBox(handPosition, props); var dist = distanceBetweenPointAndEntityBoundingBox(grabPosition, props);
var distance = Vec3.distance(handPosition, props.position); var distance = Vec3.distance(grabPosition, props.position);
if ((dist > TEAR_AWAY_DISTANCE) || if ((dist > nearGrabDistance) ||
(distance > NEAR_GRAB_RADIUS * sensorScaleFactor)) { (distance > nearGrabRadius)) { // Only smallish entities can be near grabbed.
continue; continue;
} }
if (entityIsGrabbable(props) || entityIsCloneable(props)) { if (entityIsGrabbable(props) || entityIsCloneable(props)) {
// give haptic feedback
if (props.id !== this.hapticTargetID) {
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
this.hapticTargetID = props.id;
}
if (!entityIsCloneable(props)) { if (!entityIsCloneable(props)) {
// if we've attempted to grab a non-cloneable child, roll up to the root of the tree // if we've attempted to grab a non-cloneable child, roll up to the root of the tree
var groupRootProps = findGroupParent(controllerData, props); var groupRootProps = findGroupParent(controllerData, props);
@ -284,7 +272,6 @@ Script.include("/~/system/libraries/controllers.js");
return makeRunningValues(true, [this.targetEntityID], []); return makeRunningValues(true, [this.targetEntityID], []);
} }
} else { } else {
this.hapticTargetID = null;
this.robbed = false; this.robbed = false;
return makeRunningValues(false, [], []); return makeRunningValues(false, [], []);
} }
@ -303,7 +290,6 @@ Script.include("/~/system/libraries/controllers.js");
// entity was deleted // entity was deleted
this.grabbing = false; this.grabbing = false;
this.targetEntityID = null; this.targetEntityID = null;
this.hapticTargetID = null;
this.robbed = false; this.robbed = false;
return makeRunningValues(false, [], []); return makeRunningValues(false, [], []);
} }

View file

@ -53,6 +53,7 @@
TEAR_AWAY_DISTANCE:true, TEAR_AWAY_DISTANCE:true,
TEAR_AWAY_COUNT:true, TEAR_AWAY_COUNT:true,
TEAR_AWAY_CHECK_TIME:true, TEAR_AWAY_CHECK_TIME:true,
NEAR_GRAB_DISTANCE: true,
distanceBetweenPointAndEntityBoundingBox:true, distanceBetweenPointAndEntityBoundingBox:true,
entityIsEquipped:true, entityIsEquipped:true,
entityIsFarGrabbedByOther:true, entityIsFarGrabbedByOther:true,
@ -99,6 +100,10 @@ NEAR_GRAB_RADIUS = 1.0;
TEAR_AWAY_DISTANCE = 0.15; // ungrab an entity if its bounding-box moves this far from the hand TEAR_AWAY_DISTANCE = 0.15; // ungrab an entity if its bounding-box moves this far from the hand
TEAR_AWAY_COUNT = 2; // multiply by TEAR_AWAY_CHECK_TIME to know how long the item must be away TEAR_AWAY_COUNT = 2; // multiply by TEAR_AWAY_CHECK_TIME to know how long the item must be away
TEAR_AWAY_CHECK_TIME = 0.15; // seconds, duration between checks TEAR_AWAY_CHECK_TIME = 0.15; // seconds, duration between checks
NEAR_GRAB_DISTANCE = 0.14; // Grab an entity if its bounding box is within this distance.
// Smaller than TEAR_AWAY_DISTANCE for hysteresis.
DISPATCHER_HOVERING_LIST = "dispactherHoveringList"; DISPATCHER_HOVERING_LIST = "dispactherHoveringList";
DISPATCHER_HOVERING_STYLE = { DISPATCHER_HOVERING_STYLE = {
isOutlineSmooth: true, isOutlineSmooth: true,