Merge pull request #4169 from Atlante45/hydra_grab_fix

Hydra grab fix
This commit is contained in:
Philip Rosedale 2015-01-26 17:31:13 -08:00
commit 78e1769468
4 changed files with 116 additions and 71 deletions

View file

@ -14,13 +14,9 @@
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
Script.include("libraries/entityPropertyDialogBox.js"); Script.include("../../libraries/entityPropertyDialogBox.js");
var entityPropertyDialogBox = EntityPropertyDialogBox; var entityPropertyDialogBox = EntityPropertyDialogBox;
var LASER_WIDTH = 4;
var LASER_COLOR = { red: 255, green: 0, blue: 0 };
var LASER_LENGTH_FACTOR = 500;
var MIN_ANGULAR_SIZE = 2; var MIN_ANGULAR_SIZE = 2;
var MAX_ANGULAR_SIZE = 45; var MAX_ANGULAR_SIZE = 45;
var allowLargeModels = false; var allowLargeModels = false;
@ -32,7 +28,44 @@ var RIGHT = 1;
var jointList = MyAvatar.getJointNames(); var jointList = MyAvatar.getJointNames();
var mode = 0; var STICKS = 0;
var MAPPED = 1;
var mode = STICKS;
var LASER_WIDTH = 4;
var LASER_COLOR = [{ red: 200, green: 150, blue: 50 }, // STICKS
{ red: 50, green: 150, blue: 200 }]; // MAPPED
var LASER_LENGTH_FACTOR = 500;
var lastAccurateIntersection = null;
var accurateIntersections = 0;
var totalIntersections = 0;
var inaccurateInARow = 0;
var maxInaccurateInARow = 0;
function getRayIntersection(pickRay) { // pickRay : { origin : {xyz}, direction : {xyz} }
if (lastAccurateIntersection === null) {
lastAccurateIntersection = Entities.findRayIntersectionBlocking(pickRay);
} else {
var intersection = Entities.findRayIntersection(pickRay);
if (intersection.accurate) {
lastAccurateIntersection = intersection;
accurateIntersections++;
maxInaccurateInARow = (maxInaccurateInARow > inaccurateInARow) ? maxInaccurateInARow : inaccurateInARow;
inaccurateInARow = 0;
} else {
inaccurateInARow++;
}
totalIntersections++;
}
return lastAccurateIntersection;
}
function printIntersectionsStats() {
var ratio = accurateIntersections / totalIntersections;
print("Out of " + totalIntersections + " intersections, " + accurateIntersections + " where accurate. (" + ratio * 100 +"%)");
print("Worst case was " + maxInaccurateInARow + " inaccurate intersections in a row.");
}
function controller(wichSide) { function controller(wichSide) {
this.side = wichSide; this.side = wichSide;
@ -42,10 +75,10 @@ function controller(wichSide) {
this.bumper = 6 * wichSide + 5; this.bumper = 6 * wichSide + 5;
this.oldPalmPosition = Controller.getSpatialControlPosition(this.palm); this.oldPalmPosition = Controller.getSpatialControlPosition(this.palm);
this.palmPosition = Controller.getSpatialControlPosition(this.palm); this.palmPosition = this.oldPalmPosition;
this.oldTipPosition = Controller.getSpatialControlPosition(this.tip); this.oldTipPosition = Controller.getSpatialControlPosition(this.tip);
this.tipPosition = Controller.getSpatialControlPosition(this.tip); this.tipPosition = this.oldTipPosition;
this.oldUp = Controller.getSpatialControlNormal(this.palm); this.oldUp = Controller.getSpatialControlNormal(this.palm);
this.up = this.oldUp; this.up = this.oldUp;
@ -81,7 +114,7 @@ function controller(wichSide) {
this.laser = Overlays.addOverlay("line3d", { this.laser = Overlays.addOverlay("line3d", {
start: { x: 0, y: 0, z: 0 }, start: { x: 0, y: 0, z: 0 },
end: { x: 0, y: 0, z: 0 }, end: { x: 0, y: 0, z: 0 },
color: LASER_COLOR, color: LASER_COLOR[mode],
alpha: 1, alpha: 1,
visible: false, visible: false,
lineWidth: LASER_WIDTH, lineWidth: LASER_WIDTH,
@ -245,9 +278,9 @@ function controller(wichSide) {
var inverseRotation = Quat.inverse(MyAvatar.orientation); var inverseRotation = Quat.inverse(MyAvatar.orientation);
var startPosition = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.palmPosition, MyAvatar.position)); var startPosition = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.palmPosition, MyAvatar.position));
startPosition = Vec3.multiply(startPosition, 1 / MyAvatar.scale);
var direction = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.tipPosition, this.palmPosition)); var direction = Vec3.multiplyQbyV(inverseRotation, Vec3.subtract(this.tipPosition, this.palmPosition));
var distance = Vec3.length(direction); direction = Vec3.multiply(direction, LASER_LENGTH_FACTOR / (Vec3.length(direction) * MyAvatar.scale));
direction = Vec3.multiply(direction, LASER_LENGTH_FACTOR / distance);
var endPosition = Vec3.sum(startPosition, direction); var endPosition = Vec3.sum(startPosition, direction);
Overlays.editOverlay(this.laser, { Overlays.editOverlay(this.laser, {
@ -267,17 +300,16 @@ function controller(wichSide) {
start: Vec3.sum(endPosition, Vec3.multiply(this.up, 2 * this.guideScale)), start: Vec3.sum(endPosition, Vec3.multiply(this.up, 2 * this.guideScale)),
end: Vec3.sum(endPosition, Vec3.multiply(this.up, -2 * this.guideScale)) end: Vec3.sum(endPosition, Vec3.multiply(this.up, -2 * this.guideScale))
}); });
this.showLaser(!this.grabbing || mode == 0); this.showLaser(!this.grabbing || mode == STICKS);
if (this.glowedIntersectingModel.isKnownID) { if (this.glowedIntersectingModel.isKnownID) {
Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.0 }); Entities.editEntity(this.glowedIntersectingModel, { glowLevel: 0.0 });
this.glowedIntersectingModel.isKnownID = false; this.glowedIntersectingModel.isKnownID = false;
} }
if (!this.grabbing) { if (!this.grabbing) {
var intersection = Entities.findRayIntersectionBlocking({ var intersection = getRayIntersection({ origin: this.palmPosition,
origin: this.palmPosition, direction: this.front
direction: this.front });
});
var halfDiagonal = Vec3.length(intersection.properties.dimensions) / 2.0; var halfDiagonal = Vec3.length(intersection.properties.dimensions) / 2.0;
@ -304,17 +336,16 @@ function controller(wichSide) {
if (this.grabbing) { if (this.grabbing) {
if (!this.entityID.isKnownID) { if (!this.entityID.isKnownID) {
print("Unknown grabbed ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID); print("Unknown grabbed ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID);
this.entityID = Entities.findRayIntersectionBlocking({ this.entityID = getRayIntersection({ origin: this.palmPosition,
origin: this.palmPosition, direction: this.front
direction: this.front }).entityID;
}).entityID;
print("Identified ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID); print("Identified ID " + this.entityID.id + ", isKnown: " + this.entityID.isKnownID);
} }
var newPosition; var newPosition;
var newRotation; var newRotation;
switch (mode) { switch (mode) {
case 0: case STICKS:
newPosition = Vec3.sum(this.palmPosition, newPosition = Vec3.sum(this.palmPosition,
Vec3.multiply(this.front, this.x)); Vec3.multiply(this.front, this.x));
newPosition = Vec3.sum(newPosition, newPosition = Vec3.sum(newPosition,
@ -328,7 +359,7 @@ function controller(wichSide) {
newRotation = Quat.multiply(newRotation, newRotation = Quat.multiply(newRotation,
this.oldModelRotation); this.oldModelRotation);
break; break;
case 1: case MAPPED:
var forward = Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1 }); var forward = Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1 });
var d = Vec3.dot(forward, MyAvatar.position); var d = Vec3.dot(forward, MyAvatar.position);
@ -397,15 +428,13 @@ function controller(wichSide) {
var bumperValue = Controller.isButtonPressed(this.bumper); var bumperValue = Controller.isButtonPressed(this.bumper);
if (bumperValue && !this.bumperValue) { if (bumperValue && !this.bumperValue) {
if (mode == 0) { if (mode === STICKS) {
mode = 1; mode = MAPPED;
Overlays.editOverlay(leftController.laser, { color: { red: 0, green: 0, blue: 255 } }); } else if (mode === MAPPED) {
Overlays.editOverlay(rightController.laser, { color: { red: 0, green: 0, blue: 255 } }); mode = STICKS;
} else {
mode = 0;
Overlays.editOverlay(leftController.laser, { color: { red: 255, green: 0, blue: 0 } });
Overlays.editOverlay(rightController.laser, { color: { red: 255, green: 0, blue: 0 } });
} }
Overlays.editOverlay(leftController.laser, { color: LASER_COLOR[mode] });
Overlays.editOverlay(rightController.laser, { color: LASER_COLOR[mode] });
} }
this.bumperValue = bumperValue; this.bumperValue = bumperValue;
@ -475,10 +504,10 @@ function controller(wichSide) {
Vec3.print("Looking at: ", this.palmPosition); Vec3.print("Looking at: ", this.palmPosition);
var pickRay = { origin: this.palmPosition, var pickRay = { origin: this.palmPosition,
direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)) }; direction: Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)) };
var foundIntersection = Entities.findRayIntersectionBlocking(pickRay); var foundIntersection = getRayIntersection(pickRay);
if(!foundIntersection.accurate) { if(!foundIntersection.intersects) {
print("No accurate intersection"); print("No intersection");
return; return;
} }
newModel = foundIntersection.entityID; newModel = foundIntersection.entityID;
@ -526,7 +555,7 @@ function moveEntities() {
switch (mode) { switch (mode) {
case 0: case STICKS:
var oldLeftPoint = Vec3.sum(leftController.oldPalmPosition, Vec3.multiply(leftController.oldFront, leftController.x)); var oldLeftPoint = Vec3.sum(leftController.oldPalmPosition, Vec3.multiply(leftController.oldFront, leftController.x));
var oldRightPoint = Vec3.sum(rightController.oldPalmPosition, Vec3.multiply(rightController.oldFront, rightController.x)); var oldRightPoint = Vec3.sum(rightController.oldPalmPosition, Vec3.multiply(rightController.oldFront, rightController.x));
@ -545,7 +574,7 @@ function moveEntities() {
newPosition = Vec3.sum(middle, newPosition = Vec3.sum(middle,
Vec3.multiply(Vec3.subtract(leftController.oldModelPosition, oldMiddle), ratio)); Vec3.multiply(Vec3.subtract(leftController.oldModelPosition, oldMiddle), ratio));
break; break;
case 1: case MAPPED:
var u = Vec3.normalize(Vec3.subtract(rightController.oldPalmPosition, leftController.oldPalmPosition)); var u = Vec3.normalize(Vec3.subtract(rightController.oldPalmPosition, leftController.oldPalmPosition));
var v = Vec3.normalize(Vec3.subtract(rightController.palmPosition, leftController.palmPosition)); var v = Vec3.normalize(Vec3.subtract(rightController.palmPosition, leftController.palmPosition));
@ -628,43 +657,56 @@ var glowedEntityID = { id: -1, isKnownID: false };
// In order for editVoxels and editModels to play nice together, they each check to see if a "delete" menu item already // In order for editVoxels and editModels to play nice together, they each check to see if a "delete" menu item already
// exists. If it doesn't they add it. If it does they don't. They also only delete the menu item if they were the one that // exists. If it doesn't they add it. If it does they don't. They also only delete the menu item if they were the one that
// added it. // added it.
var ROOT_MENU = "Edit";
var ITEM_BEFORE = "Physics";
var MENU_SEPARATOR = "Models";
var EDIT_PROPERTIES = "Edit Properties...";
var INTERSECTION_STATS = "Print Intersection Stats";
var DELETE = "Delete";
var LARGE_MODELS = "Allow Selecting of Large Models";
var SMALL_MODELS = "Allow Selecting of Small Models";
var LIGHTS = "Allow Selecting of Lights";
var modelMenuAddedDelete = false; var modelMenuAddedDelete = false;
var originalLightsArePickable = Entities.getLightsArePickable(); var originalLightsArePickable = Entities.getLightsArePickable();
function setupModelMenus() { function setupModelMenus() {
print("setupModelMenus()"); print("setupModelMenus()");
// adj our menuitems // adj our menuitems
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Models", isSeparator: true, beforeItem: "Physics" }); Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: MENU_SEPARATOR, isSeparator: true, beforeItem: ITEM_BEFORE });
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Edit Properties...", Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: EDIT_PROPERTIES,
shortcutKeyEvent: { text: "`" }, afterItem: "Models" }); shortcutKeyEvent: { text: "`" }, afterItem: MENU_SEPARATOR });
if (!Menu.menuItemExists("Edit", "Delete")) { Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: INTERSECTION_STATS, afterItem: MENU_SEPARATOR });
if (!Menu.menuItemExists(ROOT_MENU, DELETE)) {
print("no delete... adding ours"); print("no delete... adding ours");
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete", Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: DELETE,
shortcutKeyEvent: { text: "backspace" }, afterItem: "Models" }); shortcutKeyEvent: { text: "backspace" }, afterItem: MENU_SEPARATOR });
modelMenuAddedDelete = true; modelMenuAddedDelete = true;
} else { } else {
print("delete exists... don't add ours"); print("delete exists... don't add ours");
} }
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Large Models", shortcutKey: "CTRL+META+L", Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: LARGE_MODELS, shortcutKey: "CTRL+META+L",
afterItem: "Paste Models", isCheckable: true }); afterItem: DELETE, isCheckable: true });
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Small Models", shortcutKey: "CTRL+META+S", Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: SMALL_MODELS, shortcutKey: "CTRL+META+S",
afterItem: "Allow Selecting of Large Models", isCheckable: true }); afterItem: LARGE_MODELS, isCheckable: true });
Menu.addMenuItem({ menuName: "Edit", menuItemName: "Allow Selecting of Lights", shortcutKey: "CTRL+SHIFT+META+L", Menu.addMenuItem({ menuName: ROOT_MENU, menuItemName: LIGHTS, shortcutKey: "CTRL+SHIFT+META+L",
afterItem: "Allow Selecting of Small Models", isCheckable: true }); afterItem: SMALL_MODELS, isCheckable: true });
Entities.setLightsArePickable(false); Entities.setLightsArePickable(false);
} }
function cleanupModelMenus() { function cleanupModelMenus() {
Menu.removeMenuItem("Edit", "Edit Properties..."); Menu.removeSeparator(ROOT_MENU, MENU_SEPARATOR);
Menu.removeMenuItem(ROOT_MENU, EDIT_PROPERTIES);
Menu.removeMenuItem(ROOT_MENU, INTERSECTION_STATS);
if (modelMenuAddedDelete) { if (modelMenuAddedDelete) {
// delete our menuitems // delete our menuitems
Menu.removeMenuItem("Edit", "Delete"); Menu.removeMenuItem(ROOT_MENU, DELETE);
} }
Menu.removeMenuItem("Edit", "Allow Selecting of Large Models"); Menu.removeMenuItem(ROOT_MENU, LARGE_MODELS);
Menu.removeMenuItem("Edit", "Allow Selecting of Small Models"); Menu.removeMenuItem(ROOT_MENU, SMALL_MODELS);
Menu.removeMenuItem("Edit", "Allow Selecting of Lights"); Menu.removeMenuItem(ROOT_MENU, LIGHTS);
} }
@ -688,13 +730,13 @@ function showPropertiesForm(editModelID) {
Menu.menuItemEvent.connect(function (menuItem) { Menu.menuItemEvent.connect(function (menuItem) {
print("menuItemEvent() in JS... menuItem=" + menuItem); print("menuItemEvent() in JS... menuItem=" + menuItem);
if (menuItem == "Allow Selecting of Small Models") { if (menuItem == SMALL_MODELS) {
allowSmallModels = Menu.isOptionChecked("Allow Selecting of Small Models"); allowSmallModels = Menu.isOptionChecked(SMALL_MODELS);
} else if (menuItem == "Allow Selecting of Large Models") { } else if (menuItem == LARGE_MODELS) {
allowLargeModels = Menu.isOptionChecked("Allow Selecting of Large Models"); allowLargeModels = Menu.isOptionChecked(LARGE_MODELS);
} else if (menuItem == "Allow Selecting of Lights") { } else if (menuItem == LIGHTS) {
Entities.setLightsArePickable(Menu.isOptionChecked("Allow Selecting of Lights")); Entities.setLightsArePickable(Menu.isOptionChecked(LIGHTS));
} else if (menuItem == "Delete") { } else if (menuItem == DELETE) {
if (leftController.grabbing) { if (leftController.grabbing) {
print(" Delete Entity.... leftController.entityID="+ leftController.entityID); print(" Delete Entity.... leftController.entityID="+ leftController.entityID);
Entities.deleteEntity(leftController.entityID); Entities.deleteEntity(leftController.entityID);
@ -712,7 +754,7 @@ Menu.menuItemEvent.connect(function (menuItem) {
} else { } else {
print(" Delete Entity.... not holding..."); print(" Delete Entity.... not holding...");
} }
} else if (menuItem == "Edit Properties...") { } else if (menuItem == EDIT_PROPERTIES) {
editModelID = -1; editModelID = -1;
if (leftController.grabbing) { if (leftController.grabbing) {
print(" Edit Properties.... leftController.entityID="+ leftController.entityID); print(" Edit Properties.... leftController.entityID="+ leftController.entityID);
@ -727,16 +769,18 @@ Menu.menuItemEvent.connect(function (menuItem) {
print(" Edit Properties.... about to edit properties..."); print(" Edit Properties.... about to edit properties...");
showPropertiesForm(editModelID); showPropertiesForm(editModelID);
} }
} else if (menuItem == INTERSECTION_STATS) {
printIntersectionsStats();
} }
}); });
Controller.keyReleaseEvent.connect(function (event) { Controller.keyReleaseEvent.connect(function (event) {
// since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items // since sometimes our menu shortcut keys don't work, trap our menu items here also and fire the appropriate menu items
if (event.text == "`") { if (event.text == "`") {
handeMenuEvent("Edit Properties..."); handeMenuEvent(EDIT_PROPERTIES);
} }
if (event.text == "BACKSPACE") { if (event.text == "BACKSPACE") {
handeMenuEvent("Delete"); handeMenuEvent(DELETE);
} }
}); });

View file

@ -171,10 +171,6 @@ void Hand::renderHandTargets(bool isMine) {
glm::vec3 tip = palm.getTipPosition(); glm::vec3 tip = palm.getTipPosition();
glm::vec3 root = palm.getPosition(); glm::vec3 root = palm.getPosition();
//Scale the positions based on avatar scale
myAvatar->scaleVectorRelativeToPosition(tip);
myAvatar->scaleVectorRelativeToPosition(root);
Avatar::renderJointConnectingCone(root, tip, PALM_FINGER_ROD_RADIUS, PALM_FINGER_ROD_RADIUS); Avatar::renderJointConnectingCone(root, tip, PALM_FINGER_ROD_RADIUS, PALM_FINGER_ROD_RADIUS);
// Render sphere at palm/finger root // Render sphere at palm/finger root
glm::vec3 offsetFromPalm = root + palm.getNormal() * PALM_DISK_THICKNESS; glm::vec3 offsetFromPalm = root + palm.getNormal() * PALM_DISK_THICKNESS;

View file

@ -27,7 +27,7 @@ HandData::HandData(AvatarData* owningAvatar) :
} }
glm::vec3 HandData::worldToLocalVector(const glm::vec3& worldVector) const { glm::vec3 HandData::worldToLocalVector(const glm::vec3& worldVector) const {
return glm::inverse(getBaseOrientation()) * worldVector; return glm::inverse(getBaseOrientation()) * worldVector / getBaseScale();
} }
PalmData& HandData::addNewPalm() { PalmData& HandData::addNewPalm() {
@ -108,15 +108,19 @@ glm::quat HandData::getBaseOrientation() const {
glm::vec3 HandData::getBasePosition() const { glm::vec3 HandData::getBasePosition() const {
return _owningAvatarData->getPosition(); return _owningAvatarData->getPosition();
} }
float HandData::getBaseScale() const {
return _owningAvatarData->getTargetScale();
}
glm::vec3 PalmData::getFingerDirection() const { glm::vec3 PalmData::getFingerDirection() const {
const glm::vec3 LOCAL_FINGER_DIRECTION(0.0f, 0.0f, 1.0f); const glm::vec3 LOCAL_FINGER_DIRECTION(0.0f, 0.0f, 1.0f);
return _owningHandData->localToWorldDirection(_rawRotation * LOCAL_FINGER_DIRECTION); return glm::normalize(_owningHandData->localToWorldDirection(_rawRotation * LOCAL_FINGER_DIRECTION));
} }
glm::vec3 PalmData::getNormal() const { glm::vec3 PalmData::getNormal() const {
const glm::vec3 LOCAL_PALM_DIRECTION(0.0f, -1.0f, 0.0f); const glm::vec3 LOCAL_PALM_DIRECTION(0.0f, -1.0f, 0.0f);
return _owningHandData->localToWorldDirection(_rawRotation * LOCAL_PALM_DIRECTION); return glm::normalize(_owningHandData->localToWorldDirection(_rawRotation * LOCAL_PALM_DIRECTION));
} }

View file

@ -36,11 +36,11 @@ public:
// position conversion // position conversion
glm::vec3 localToWorldPosition(const glm::vec3& localPosition) { glm::vec3 localToWorldPosition(const glm::vec3& localPosition) {
return getBasePosition() + getBaseOrientation() * localPosition; return getBasePosition() + getBaseOrientation() * localPosition * getBaseScale();
} }
glm::vec3 localToWorldDirection(const glm::vec3& localVector) { glm::vec3 localToWorldDirection(const glm::vec3& localVector) {
return getBaseOrientation() * localVector; return getBaseOrientation() * localVector * getBaseScale();
} }
glm::vec3 worldToLocalVector(const glm::vec3& worldVector) const; glm::vec3 worldToLocalVector(const glm::vec3& worldVector) const;
@ -71,6 +71,7 @@ protected:
glm::quat getBaseOrientation() const; glm::quat getBaseOrientation() const;
glm::vec3 getBasePosition() const; glm::vec3 getBasePosition() const;
float getBaseScale() const;
private: private:
// privatize copy ctor and assignment operator so copies of this object cannot be made // privatize copy ctor and assignment operator so copies of this object cannot be made