mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 04:37:48 +02:00
handControllerGrab improvements
* Made handControllerGrab eslint clean * A model overlay is used instead of a sphere to draw equip hotspots. * The equip hotspot model will grow in size by 10% when hand is near enough to equip it. * The hand controller will now perform a haptic pulse when your hand is near enough to an equip hotspot. * Near triggers events will also perform a haptic pulse
This commit is contained in:
parent
a07970f053
commit
2db8160568
1 changed files with 180 additions and 135 deletions
|
@ -72,6 +72,9 @@ var LINE_ENTITY_DIMENSIONS = {
|
|||
var LINE_LENGTH = 500;
|
||||
var PICK_MAX_DISTANCE = 500; // max length of pick-ray
|
||||
|
||||
var EQUIP_RADIUS_TO_MODEL_SCALE_FACTOR = 0.75;
|
||||
var EQUIP_RADIUS_EMBIGGEN_FACTOR = 1.1;
|
||||
|
||||
//
|
||||
// near grabbing
|
||||
//
|
||||
|
@ -865,7 +868,6 @@ function MyController(hand) {
|
|||
};
|
||||
|
||||
this.off = function () {
|
||||
|
||||
if (this.triggerSmoothedReleased()) {
|
||||
this.waitForTriggerRelease = false;
|
||||
}
|
||||
|
@ -875,8 +877,18 @@ function MyController(hand) {
|
|||
this.startingHandRotation = Controller.getPoseValue(controllerHandInput).rotation;
|
||||
if (this.triggerSmoothedSqueezed()) {
|
||||
this.setState(STATE_SEARCHING, "trigger squeeze detected");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.waitForTriggerRelease) {
|
||||
// update haptics when hand is near an equip hotspot
|
||||
this.entityPropertyCache.clear();
|
||||
this.entityPropertyCache.findEntities(this.getHandPosition(), NEAR_GRAB_RADIUS);
|
||||
var candidateEntities = this.entityPropertyCache.getEntities();
|
||||
var potentialEquipHotspot = this.chooseBestEquipHotspot(candidateEntities);
|
||||
this.updateEquipHaptics(potentialEquipHotspot);
|
||||
}
|
||||
};
|
||||
|
||||
this.createHotspots = function () {
|
||||
|
@ -890,9 +902,6 @@ function MyController(hand) {
|
|||
var HAND_GRAB_SPHERE_ALPHA = 0.3;
|
||||
var HAND_GRAB_SPHERE_RADIUS = NEAR_GRAB_RADIUS;
|
||||
|
||||
var EQUIP_SPHERE_COLOR = { red: 90, green: 255, blue: 90 };
|
||||
var EQUIP_SPHERE_ALPHA = 0.3;
|
||||
|
||||
var GRAB_BOX_COLOR = { red: 90, green: 90, blue: 255 };
|
||||
var GRAB_BOX_ALPHA = 0.1;
|
||||
|
||||
|
@ -915,7 +924,9 @@ function MyController(hand) {
|
|||
this.hotspotOverlays.push({
|
||||
entityID: undefined,
|
||||
overlay: overlay,
|
||||
type: "hand"
|
||||
type: "hand",
|
||||
localPosition: {x: 0, y: 0, z: 0},
|
||||
hotspot: {}
|
||||
});
|
||||
|
||||
// add larger blue sphere around the palm.
|
||||
|
@ -933,7 +944,8 @@ function MyController(hand) {
|
|||
entityID: undefined,
|
||||
overlay: overlay,
|
||||
type: "hand",
|
||||
localPosition: {x: 0, y: 0, z: 0}
|
||||
localPosition: {x: 0, y: 0, z: 0},
|
||||
hotspot: {}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -961,7 +973,8 @@ function MyController(hand) {
|
|||
entityID: entityID,
|
||||
overlay: overlay,
|
||||
type: "near",
|
||||
localPosition: {x: 0, y: 0, z: 0}
|
||||
localPosition: {x: 0, y: 0, z: 0},
|
||||
hotspot: {}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -973,38 +986,59 @@ function MyController(hand) {
|
|||
})).filter(function (hotspot) {
|
||||
return _this.hotspotIsEquippable(hotspot);
|
||||
}).forEach(function (hotspot) {
|
||||
var overlay = Overlays.addOverlay("sphere", {
|
||||
var overlay = Overlays.addOverlay("model", {
|
||||
url: "http://hifi-content.s3.amazonaws.com/alan/dev/equip-ico-2.fbx",
|
||||
position: hotspot.worldPosition,
|
||||
size: hotspot.radius * 2,
|
||||
color: EQUIP_SPHERE_COLOR,
|
||||
alpha: EQUIP_SPHERE_ALPHA,
|
||||
solid: true,
|
||||
visible: true,
|
||||
ignoreRayIntersection: true,
|
||||
drawInFront: false
|
||||
rotation: {x: 0, y: 0, z: 0, w: 1},
|
||||
dimensions: (hotspot.radius / EQUIP_RADIUS) * EQUIP_RADIUS_TO_MODEL_SCALE_FACTOR,
|
||||
ignoreRayIntersection: true
|
||||
});
|
||||
_this.hotspotOverlays.push({
|
||||
entityID: hotspot.entityID,
|
||||
overlay: overlay,
|
||||
type: "equip",
|
||||
localPosition: hotspot.localPosition
|
||||
localPosition: hotspot.localPosition,
|
||||
hotspot: hotspot
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
this.updateHotspots = function() {
|
||||
this.clearEquipHaptics = function () {
|
||||
this.prevPotentialEquipHotspot = null;
|
||||
};
|
||||
|
||||
this.updateEquipHaptics = function (potentialEquipHotspot) {
|
||||
if (potentialEquipHotspot && !this.prevPotentialEquipHotspot ||
|
||||
!potentialEquipHotspot && this.prevPotentialEquipHotspot) {
|
||||
Controller.triggerShortHapticPulse(1.0, this.hand);
|
||||
}
|
||||
this.prevPotentialEquipHotspot = potentialEquipHotspot;
|
||||
};
|
||||
|
||||
this.updateHotspots = function (potentialEquipHotspot) {
|
||||
var _this = this;
|
||||
var props;
|
||||
this.hotspotOverlays.forEach(function (overlayInfo) {
|
||||
if (overlayInfo.type === "hand") {
|
||||
Overlays.editOverlay(overlayInfo.overlay, { position: _this.getHandPosition() });
|
||||
} else if (overlayInfo.type === "equip") {
|
||||
|
||||
var radius = (overlayInfo.hotspot.radius / EQUIP_RADIUS) * EQUIP_RADIUS_TO_MODEL_SCALE_FACTOR;
|
||||
|
||||
// embiggen the equipHotspot if it maches the potentialEquipHotspot
|
||||
if (potentialEquipHotspot && overlayInfo.entityID == potentialEquipHotspot.entityID &&
|
||||
Vec3.equal(overlayInfo.localPosition, potentialEquipHotspot.localPosition)) {
|
||||
radius = (overlayInfo.hotspot.radius / EQUIP_RADIUS) * EQUIP_RADIUS_TO_MODEL_SCALE_FACTOR *
|
||||
EQUIP_RADIUS_EMBIGGEN_FACTOR;
|
||||
}
|
||||
|
||||
_this.entityPropertyCache.updateEntity(overlayInfo.entityID);
|
||||
props = _this.entityPropertyCache.getProps(overlayInfo.entityID);
|
||||
var entityXform = new Xform(props.rotation, props.position);
|
||||
Overlays.editOverlay(overlayInfo.overlay, {
|
||||
position: entityXform.xformPoint(overlayInfo.localPosition),
|
||||
rotation: props.rotation
|
||||
rotation: props.rotation,
|
||||
dimensions: radius
|
||||
});
|
||||
} else if (overlayInfo.type === "near") {
|
||||
_this.entityPropertyCache.updateEntity(overlayInfo.entityID);
|
||||
|
@ -1268,12 +1302,31 @@ function MyController(hand) {
|
|||
return true;
|
||||
};
|
||||
|
||||
this.chooseBestEquipHotspot = function (candidateEntities) {
|
||||
var equippableHotspots = flatten(candidateEntities.map(function (entityID) {
|
||||
return _this.collectEquipHotspots(entityID);
|
||||
})).filter(function (hotspot) {
|
||||
return (_this.hotspotIsEquippable(hotspot) &&
|
||||
Vec3.distance(hotspot.worldPosition, _this.getHandPosition()) < hotspot.radius);
|
||||
});
|
||||
|
||||
if (equippableHotspots.length > 0) {
|
||||
// sort by distance
|
||||
equippableHotspots.sort(function (a, b) {
|
||||
var aDistance = Vec3.distance(a.worldPosition, this.getHandPosition());
|
||||
var bDistance = Vec3.distance(b.worldPosition, this.getHandPosition());
|
||||
return aDistance - bDistance;
|
||||
});
|
||||
return equippableHotspots[0];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
this.search = function () {
|
||||
var _this = this;
|
||||
var name;
|
||||
|
||||
this.updateHotspots();
|
||||
|
||||
this.grabbedEntity = null;
|
||||
this.isInitialGrab = false;
|
||||
this.shouldResetParentOnRelease = false;
|
||||
|
@ -1291,27 +1344,13 @@ function MyController(hand) {
|
|||
this.entityPropertyCache.findEntities(handPosition, NEAR_GRAB_RADIUS);
|
||||
var candidateEntities = this.entityPropertyCache.getEntities();
|
||||
|
||||
var equippableHotspots = flatten(candidateEntities.map(function(entityID) {
|
||||
return _this.collectEquipHotspots(entityID);
|
||||
})).filter(function(hotspot) {
|
||||
return _this.hotspotIsEquippable(hotspot) && Vec3.distance(hotspot.worldPosition, handPosition) < hotspot.radius;
|
||||
});
|
||||
|
||||
var entity;
|
||||
if (equippableHotspots.length > 0) {
|
||||
// sort by distance
|
||||
equippableHotspots.sort(function(a, b) {
|
||||
var aDistance = Vec3.distance(a.worldPosition, handPosition);
|
||||
var bDistance = Vec3.distance(b.worldPosition, handPosition);
|
||||
return aDistance - bDistance;
|
||||
});
|
||||
var potentialEquipHotspot = this.chooseBestEquipHotspot(candidateEntities);
|
||||
if (potentialEquipHotspot) {
|
||||
if (this.triggerSmoothedGrab()) {
|
||||
this.grabbedHotspot = equippableHotspots[0];
|
||||
this.grabbedEntity = equippableHotspots[0].entityID;
|
||||
this.grabbedHotspot = potentialEquipHotspot;
|
||||
this.grabbedEntity = potentialEquipHotspot.entityID;
|
||||
this.setState(STATE_HOLD, "eqipping '" + this.entityPropertyCache.getProps(this.grabbedEntity).name + "'");
|
||||
return;
|
||||
} else {
|
||||
// TODO: highlight the equippable object?
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1330,6 +1369,7 @@ function MyController(hand) {
|
|||
this.intersectionDistance = 0;
|
||||
}
|
||||
|
||||
var entity;
|
||||
if (grabbableEntities.length > 0) {
|
||||
// sort by distance
|
||||
grabbableEntities.sort(function (a, b) {
|
||||
|
@ -1345,11 +1385,10 @@ function MyController(hand) {
|
|||
this.setState(STATE_NEAR_TRIGGER, "near trigger '" + name + "'");
|
||||
return;
|
||||
} else {
|
||||
// TODO: highlight the near-triggerable object?
|
||||
// potentialNearTriggerEntity = entity;
|
||||
}
|
||||
} else {
|
||||
if (this.triggerSmoothedGrab()) {
|
||||
|
||||
var props = this.entityPropertyCache.getProps(entity);
|
||||
var grabProps = this.entityPropertyCache.getGrabProps(entity);
|
||||
var refCount = grabProps.refCount ? grabProps.refCount : 0;
|
||||
|
@ -1364,10 +1403,9 @@ function MyController(hand) {
|
|||
this.setState(STATE_NEAR_GRABBING, "near grab '" + name + "'");
|
||||
return;
|
||||
} else {
|
||||
// TODO: highlight the grabbable object?
|
||||
// potentialNearGrabEntity = entity;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (rayPickInfo.entityID) {
|
||||
|
@ -1379,7 +1417,7 @@ function MyController(hand) {
|
|||
this.setState(STATE_FAR_TRIGGER, "far trigger '" + name + "'");
|
||||
return;
|
||||
} else {
|
||||
// TODO: highlight the far-triggerable object?
|
||||
// potentialFarTriggerEntity = entity;
|
||||
}
|
||||
} else if (this.entityIsDistanceGrabbable(rayPickInfo.entityID, handPosition)) {
|
||||
if (this.triggerSmoothedGrab()) {
|
||||
|
@ -1387,11 +1425,14 @@ function MyController(hand) {
|
|||
this.setState(STATE_DISTANCE_HOLDING, "distance hold '" + name + "'");
|
||||
return;
|
||||
} else {
|
||||
// TODO: highlight the far-grabbable object?
|
||||
// potentialFarGrabEntity = entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.updateEquipHaptics(potentialEquipHotspot);
|
||||
this.updateHotspots(potentialEquipHotspot);
|
||||
|
||||
// search line visualizations
|
||||
if (USE_ENTITY_LINES_FOR_SEARCHING === true) {
|
||||
this.lineOn(rayPickInfo.searchRay.origin,
|
||||
|
@ -1419,6 +1460,8 @@ function MyController(hand) {
|
|||
|
||||
this.distanceHoldingEnter = function () {
|
||||
|
||||
this.clearEquipHaptics();
|
||||
|
||||
// controller pose is in avatar frame
|
||||
var avatarControllerPose =
|
||||
Controller.getPoseValue((this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand);
|
||||
|
@ -1694,6 +1737,7 @@ function MyController(hand) {
|
|||
this.overlayLineOff();
|
||||
|
||||
this.dropGestureReset();
|
||||
this.clearEquipHaptics();
|
||||
|
||||
if (this.entityActivated) {
|
||||
var saveGrabbedID = this.grabbedEntity;
|
||||
|
@ -1911,6 +1955,7 @@ function MyController(hand) {
|
|||
};
|
||||
|
||||
this.nearTriggerEnter = function () {
|
||||
Controller.triggerShortHapticPulse(1.0, this.hand);
|
||||
this.callEntityMethodOnGrabbed("startNearTrigger");
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue