From 99e6e3d1128826f86ec529743032e8da6e2820ce Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 4 Sep 2018 17:18:26 -0700 Subject: [PATCH 01/19] Collision Pick added to teleport.js --- .../controllers/controllerModules/teleport.js | 77 +++++++++++++++---- 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index e4dd1c43fa..c69382a47a 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -22,6 +22,7 @@ Script.include("/~/system/libraries/controllers.js"); (function() { // BEGIN LOCAL_SCOPE var TARGET_MODEL_URL = Script.resolvePath("../../assets/models/teleport-destination.fbx"); + var CANCEL_MODEL_URL = Script.resolvePath("../../assets/models/teleport-cancel.fbx"); var SEAT_MODEL_URL = Script.resolvePath("../../assets/models/teleport-seat.fbx"); var TARGET_MODEL_DIMENSIONS = { @@ -72,6 +73,12 @@ Script.include("/~/system/libraries/controllers.js"); alpha: 1, width: 0.025 }; + var cancelEnd = { + type: "model", + url: CANCEL_MODEL_URL, + dimensions: TARGET_MODEL_DIMENSIONS, + ignorePickIntersection: true + }; var teleportEnd = { type: "model", url: TARGET_MODEL_URL, @@ -84,18 +91,24 @@ Script.include("/~/system/libraries/controllers.js"); dimensions: TARGET_MODEL_DIMENSIONS, ignorePickIntersection: true }; - - - var teleportRenderStates = [{name: "cancel", path: cancelPath}, + + var collisionEnd = { + type: "sphere", + dimensions: {x: 0, y: 0, z: 0}, + ignorePickIntersection: true + }; + + var teleportRenderStates = [{name: "noend", path: cancelPath}, + {name: "cancel", path: cancelPath, end: cancelEnd}, {name: "teleport", path: teleportPath, end: teleportEnd}, - {name: "seat", path: seatPath, end: seatEnd}]; + {name: "seat", path: seatPath, end: seatEnd}, + {name: "invisible", end: collisionEnd}]; var DEFAULT_DISTANCE = 8.0; - var teleportDefaultRenderStates = [{name: "cancel", distance: DEFAULT_DISTANCE, path: cancelPath}]; + var teleportDefaultRenderStates = [{name: "noend", distance: DEFAULT_DISTANCE, path: cancelPath}]; var ignoredEntities = []; - var TELEPORTER_STATES = { IDLE: 'idle', TARGETTING: 'targetting', @@ -106,6 +119,7 @@ Script.include("/~/system/libraries/controllers.js"); NONE: 'none', // Not currently targetting anything INVISIBLE: 'invisible', // The current target is an invvsible surface INVALID: 'invalid', // The current target is invalid (wall, ceiling, etc.) + CANCEL: 'cancel', // Insufficient space to accommodate the avatar capsule SURFACE: 'surface', // The current target is a valid surface SEAT: 'seat' // The current target is a seat }; @@ -122,6 +136,9 @@ Script.include("/~/system/libraries/controllers.js"); this.state = TELEPORTER_STATES.IDLE; this.currentTarget = TARGET.INVALID; this.currentResult = null; + this.capsuleHeight = 2.0; + this.capsuleRadius = 0.25; + this.pickHeightOffset = 0.01; this.getOtherModule = function() { var otherModule = this.hand === RIGHT_HAND ? leftTeleporter : rightTeleporter; @@ -143,6 +160,7 @@ Script.include("/~/system/libraries/controllers.js"); defaultRenderStates: teleportDefaultRenderStates, maxDistance: 8.0 }); + this.teleportParabolaHandInvisible = Pointers.createPointer(PickType.Parabola, { joint: (_this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", dirOffset: { x: 0, y: 1, z: 0.1 }, @@ -157,6 +175,19 @@ Script.include("/~/system/libraries/controllers.js"); renderStates: teleportRenderStates, maxDistance: 8.0 }); + + this.teleportCollisionPick = Picks.createPick(PickType.Collision, { + enabled: true, + filter: Picks.PICK_ENTITIES + Picks.PICK_AVATARS, + shape: { + shapeType: "capsule-y", + dimensions: { x: _this.capsuleRadius * 2.0, y: _this.capsuleHeight - (_this.capsuleRadius * 2.0), z: _this.capsuleRadius * 2.0 } + }, + position: { x: 0, y: _this.pickHeightOffset + (_this.capsuleHeight * 0.5), z: 0 }, + parentID: Pointers.getPointerProperties(_this.teleportParabolaHandInvisible).renderStates["invisible"].end, + threshold: 0.05 + }); + this.teleportParabolaHeadVisible = Pointers.createPointer(PickType.Parabola, { joint: "Avatar", filter: Picks.PICK_ENTITIES, @@ -170,6 +201,7 @@ Script.include("/~/system/libraries/controllers.js"); defaultRenderStates: teleportDefaultRenderStates, maxDistance: 8.0 }); + this.teleportParabolaHeadInvisible = Pointers.createPointer(PickType.Parabola, { joint: "Avatar", filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, @@ -184,11 +216,14 @@ Script.include("/~/system/libraries/controllers.js"); }); this.cleanup = function() { - Pointers.removePointer(this.teleportParabolaHandVisible); - Pointers.removePointer(this.teleportParabolaHandInvisible); - Pointers.removePointer(this.teleportParabolaHeadVisible); - Pointers.removePointer(this.teleportParabolaHeadInvisible); + Pointers.removePointer(_this.teleportParabolaHandVisible); + Pointers.removePointer(_this.teleportParabolaHandInvisible); + Pointers.removePointer(_this.teleportParabolaHeadVisible); + Pointers.removePointer(_this.teleportParabolaHeadInvisible); + Picks.removePick(_this.teleportCollisionPick); }; + + // Picks.setIgnoreItems(_this.teleportCollisionPick, []); this.axisButtonStateX = 0; // Left/right axis button pressed. this.axisButtonStateY = 0; // Up/down axis button pressed. @@ -280,8 +315,9 @@ Script.include("/~/system/libraries/controllers.js"); } else { result = Pointers.getPrevPickResult(_this.teleportParabolaHandInvisible); } - - var teleportLocationType = getTeleportTargetType(result); + var collisionResult = Picks.getPrevPickResult(_this.teleportCollisionPick); + + var teleportLocationType = getTeleportTargetType(result, collisionResult); if (teleportLocationType === TARGET.INVISIBLE) { if (mode === 'head') { result = Pointers.getPrevPickResult(_this.teleportParabolaHeadVisible); @@ -293,11 +329,13 @@ Script.include("/~/system/libraries/controllers.js"); if (teleportLocationType === TARGET.NONE) { // Use the cancel default state - this.setTeleportState(mode, "cancel", ""); + this.setTeleportState(mode, "noend", ""); } else if (teleportLocationType === TARGET.INVALID || teleportLocationType === TARGET.INVISIBLE) { - this.setTeleportState(mode, "", "cancel"); + this.setTeleportState(mode, "", "noend"); + } else if (teleportLocationType === TARGET.CANCEL) { + this.setTeleportState(mode, "cancel", "invisible"); } else if (teleportLocationType === TARGET.SURFACE) { - this.setTeleportState(mode, "teleport", ""); + this.setTeleportState(mode, "teleport", "invisible"); } else if (teleportLocationType === TARGET.SEAT) { this.setTeleportState(mode, "", "seat"); } @@ -355,6 +393,7 @@ Script.include("/~/system/libraries/controllers.js"); // related to repositioning the avatar after you teleport var FOOT_JOINT_NAMES = ["RightToe_End", "RightToeBase", "RightFoot"]; var DEFAULT_ROOT_TO_FOOT_OFFSET = 0.5; + function getAvatarFootOffset() { // find a valid foot jointIndex @@ -395,7 +434,8 @@ Script.include("/~/system/libraries/controllers.js"); // than MAX_ANGLE_FROM_UP_TO_TELEPORT degrees from your avatar's up, then // you can't teleport there. var MAX_ANGLE_FROM_UP_TO_TELEPORT = 70; - function getTeleportTargetType(result) { + + function getTeleportTargetType(result, collisionResult) { if (result.type === Picks.INTERSECTED_NONE) { return TARGET.NONE; } @@ -421,6 +461,11 @@ Script.include("/~/system/libraries/controllers.js"); if (angle > MAX_ANGLE_FROM_UP_TO_TELEPORT) { return TARGET.INVALID; } else { + if (collisionResult.collisionRegion != undefined) { + if (collisionResult.intersects) { + return TARGET.CANCEL; + } + } return TARGET.SURFACE; } } From abb632afda72c9b0d2ee966199e9f2d94726309c Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Wed, 5 Sep 2018 16:51:34 -0700 Subject: [PATCH 02/19] Update capsule when scale/load and teleport without safe landing --- interface/src/avatar/MyAvatar.cpp | 19 +++- interface/src/avatar/MyAvatar.h | 10 +- .../controllers/controllerModules/teleport.js | 100 ++++++++++++++---- 3 files changed, 108 insertions(+), 21 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 640c9821a0..4daa3f5eef 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -113,6 +113,7 @@ MyAvatar::MyAvatar(QThread* thread) : _recentModeReadings(MODE_READINGS_RING_BUFFER_SIZE), _bodySensorMatrix(), _goToPending(false), + _goToSafe(true), _goToPosition(), _goToOrientation(), _prevShouldDrawHead(true), @@ -509,7 +510,9 @@ void MyAvatar::update(float deltaTime) { if (_physicsSafetyPending && qApp->isPhysicsEnabled() && _characterController.isEnabledAndReady()) { // When needed and ready, arrange to check and fix. _physicsSafetyPending = false; - safeLanding(_goToPosition); // no-op if already safe + if (_goToSafe) { + safeLanding(_goToPosition); // no-op if already safe + } } Head* head = getHead(); @@ -3007,7 +3010,7 @@ void MyAvatar::goToFeetLocation(const glm::vec3& newPosition, void MyAvatar::goToLocation(const glm::vec3& newPosition, bool hasOrientation, const glm::quat& newOrientation, - bool shouldFaceLocation) { + bool shouldFaceLocation, bool withSafeLanding) { // Most cases of going to a place or user go through this now. Some possible improvements to think about in the future: // - It would be nice if this used the same teleport steps and smoothing as in the teleport.js script, as long as it @@ -3027,6 +3030,7 @@ void MyAvatar::goToLocation(const glm::vec3& newPosition, _goToPending = true; _goToPosition = newPosition; + _goToSafe = withSafeLanding; _goToOrientation = getWorldOrientation(); if (hasOrientation) { qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - new orientation is " @@ -3299,6 +3303,17 @@ bool MyAvatar::getCollisionsEnabled() { return _characterController.computeCollisionGroup() != BULLET_COLLISION_GROUP_COLLISIONLESS; } +QVariantMap MyAvatar::getCollisionCapsule() { + glm::vec3 start, end; + float radius; + getCapsule(start, end, radius); + QVariantMap capsule; + capsule["start"] = vec3toVariant(start); + capsule["end"] = vec3toVariant(end); + capsule["radius"] = QVariant(radius); + return capsule; +} + void MyAvatar::setCharacterControllerEnabled(bool enabled) { qCDebug(interfaceapp) << "MyAvatar.characterControllerEnabled is deprecated. Use MyAvatar.collisionsEnabled instead."; setCollisionsEnabled(enabled); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 8121b99e55..0f7ecedcad 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1017,6 +1017,12 @@ public: */ Q_INVOKABLE bool getCollisionsEnabled(); + /**jsdoc + * @function MyAvatar.getCollisionCapsule + * @returns {object} + */ + Q_INVOKABLE QVariantMap getCollisionCapsule(); + /**jsdoc * @function MyAvatar.setCharacterControllerEnabled * @param {boolean} enabled @@ -1178,11 +1184,12 @@ public slots: * @param {boolean} [hasOrientation=false] - Set to true to set the orientation of the avatar. * @param {Quat} [orientation=Quat.IDENTITY] - The new orientation for the avatar. * @param {boolean} [shouldFaceLocation=false] - Set to true to position the avatar a short distance away from + * @param {boolean} [withSafeLanding=true] - Set to false MyAvatar::safeLanding will not be called (used when teleporting). * the new position and orientate the avatar to face the position. */ void goToLocation(const glm::vec3& newPosition, bool hasOrientation = false, const glm::quat& newOrientation = glm::quat(), - bool shouldFaceLocation = false); + bool shouldFaceLocation = false, bool withSafeLanding = true); /**jsdoc * @function MyAvatar.goToLocation * @param {object} properties @@ -1720,6 +1727,7 @@ private: bool _goToPending { false }; bool _physicsSafetyPending { false }; + bool _goToSafe { true }; glm::vec3 _goToPosition; glm::quat _goToOrientation; diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index c69382a47a..2dea25fc78 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -136,9 +136,7 @@ Script.include("/~/system/libraries/controllers.js"); this.state = TELEPORTER_STATES.IDLE; this.currentTarget = TARGET.INVALID; this.currentResult = null; - this.capsuleHeight = 2.0; - this.capsuleRadius = 0.25; - this.pickHeightOffset = 0.01; + this.capsuleThreshold = 0.05; this.getOtherModule = function() { var otherModule = this.hand === RIGHT_HAND ? leftTeleporter : rightTeleporter; @@ -176,18 +174,38 @@ Script.include("/~/system/libraries/controllers.js"); maxDistance: 8.0 }); - this.teleportCollisionPick = Picks.createPick(PickType.Collision, { - enabled: true, - filter: Picks.PICK_ENTITIES + Picks.PICK_AVATARS, - shape: { - shapeType: "capsule-y", - dimensions: { x: _this.capsuleRadius * 2.0, y: _this.capsuleHeight - (_this.capsuleRadius * 2.0), z: _this.capsuleRadius * 2.0 } - }, - position: { x: 0, y: _this.pickHeightOffset + (_this.capsuleHeight * 0.5), z: 0 }, - parentID: Pointers.getPointerProperties(_this.teleportParabolaHandInvisible).renderStates["invisible"].end, - threshold: 0.05 - }); - + this.teleportCollisionPick; + + this.recreateCollisionPick = function() { + if (_this.teleportCollisionPick !== undefined) { + Picks.removePick(_this.teleportCollisionPick); + } + + var capsuleData = MyAvatar.getCollisionCapsule(); + var capsuleHeight = Vec3.distance(capsuleData.start, capsuleData.end); + var offset = Vec3.distance(Vec3.sum(capsuleData.start, {x: 0, y: 0.5*capsuleHeight, z: 0}), MyAvatar.position); + var radius = capsuleData.radius; + var height = 2.0 * radius + capsuleHeight; + + _this.teleportCollisionPick = Picks.createPick(PickType.Collision, { + enabled: true, + parentID: Pointers.getPointerProperties(_this.teleportParabolaHandInvisible).renderStates["invisible"].end, + filter: Picks.PICK_ENTITIES + Picks.PICK_AVATARS, + shape: { + shapeType: "capsule-y", + dimensions: { + x: radius * 2.0, + y: height - (radius * 2.0), + z: radius * 2.0 + } + }, + position: { x: 0, y: offset + (height * 0.5), z: 0 }, + threshold: _this.capsuleThreshold + }); + } + + _this.recreateCollisionPick(); + this.teleportParabolaHeadVisible = Pointers.createPointer(PickType.Parabola, { joint: "Avatar", filter: Picks.PICK_ENTITIES, @@ -222,8 +240,6 @@ Script.include("/~/system/libraries/controllers.js"); Pointers.removePointer(_this.teleportParabolaHeadInvisible); Picks.removePick(_this.teleportCollisionPick); }; - - // Picks.setIgnoreItems(_this.teleportCollisionPick, []); this.axisButtonStateX = 0; // Left/right axis button pressed. this.axisButtonStateY = 0; // Up/down axis button pressed. @@ -355,7 +371,7 @@ Script.include("/~/system/libraries/controllers.js"); } else if (target === TARGET.SURFACE) { var offset = getAvatarFootOffset(); result.intersection.y += offset; - MyAvatar.goToLocation(result.intersection, true, HMD.orientation, false); + MyAvatar.goToLocation(result.intersection, true, HMD.orientation, false, false); HMD.centerUI(); MyAvatar.centerBody(); } @@ -558,7 +574,55 @@ Script.include("/~/system/libraries/controllers.js"); } } }; + + // This class execute a function after the param value haven't been set for a certain time + // It's used in this case to recreate the collision picks once when the avatar scale process ends + + var AfterSet = function(time, maxsteps, callback) { + var self = this; + this.time = time; + this.callback = callback; + this.init = false; + this.value = 0; + this.interval; + this.maxsteps = maxsteps; + this.steps = 0; + this.restateValue = function(value) { + if (self.steps++ > self.maxsteps) { + self.callback.call(this, self.value); + self.steps = 0; + } + if (!self.init) { + console.log("Starting apply after"); + } + self.init = true; + self.value = value; + if (self.interval !== undefined) { + Script.clearInterval(self.interval); + } + self.interval = Script.setInterval(function() { + self.callback.call(this, self.value); + self.init = false; + Script.clearInterval(self.interval); + self.interval = undefined; + }, self.time); + } + } + + var afterSet = new AfterSet(100, 30, function(value) { + leftTeleporter.recreateCollisionPick(); + rightTeleporter.recreateCollisionPick(); + }); + MyAvatar.onLoadComplete.connect(function () { + leftTeleporter.recreateCollisionPick(); + rightTeleporter.recreateCollisionPick(); + }); + + MyAvatar.sensorToWorldScaleChanged.connect(function() { + afterSet.restateValue(MyAvatar.getSensorToWorldScale()); + }); + Messages.subscribe('Hifi-Teleport-Disabler'); Messages.subscribe('Hifi-Teleport-Ignore-Add'); Messages.subscribe('Hifi-Teleport-Ignore-Remove'); From 01424b81792f3e2e1a38db327f2be59f899f2851 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 6 Sep 2018 09:39:33 -0700 Subject: [PATCH 03/19] Head Collision Pick added --- .../controllers/controllerModules/teleport.js | 108 +++++++++++------- 1 file changed, 69 insertions(+), 39 deletions(-) diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index 2dea25fc78..92fc91094d 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -173,38 +173,6 @@ Script.include("/~/system/libraries/controllers.js"); renderStates: teleportRenderStates, maxDistance: 8.0 }); - - this.teleportCollisionPick; - - this.recreateCollisionPick = function() { - if (_this.teleportCollisionPick !== undefined) { - Picks.removePick(_this.teleportCollisionPick); - } - - var capsuleData = MyAvatar.getCollisionCapsule(); - var capsuleHeight = Vec3.distance(capsuleData.start, capsuleData.end); - var offset = Vec3.distance(Vec3.sum(capsuleData.start, {x: 0, y: 0.5*capsuleHeight, z: 0}), MyAvatar.position); - var radius = capsuleData.radius; - var height = 2.0 * radius + capsuleHeight; - - _this.teleportCollisionPick = Picks.createPick(PickType.Collision, { - enabled: true, - parentID: Pointers.getPointerProperties(_this.teleportParabolaHandInvisible).renderStates["invisible"].end, - filter: Picks.PICK_ENTITIES + Picks.PICK_AVATARS, - shape: { - shapeType: "capsule-y", - dimensions: { - x: radius * 2.0, - y: height - (radius * 2.0), - z: radius * 2.0 - } - }, - position: { x: 0, y: offset + (height * 0.5), z: 0 }, - threshold: _this.capsuleThreshold - }); - } - - _this.recreateCollisionPick(); this.teleportParabolaHeadVisible = Pointers.createPointer(PickType.Parabola, { joint: "Avatar", @@ -232,13 +200,67 @@ Script.include("/~/system/libraries/controllers.js"); renderStates: teleportRenderStates, maxDistance: 8.0 }); + + this.teleportHeadCollisionPick; + this.teleportHandCollisionPick; + + this.recreateCollisionPicks = function() { + + if (_this.teleportHandCollisionPick !== undefined) { + Picks.removePick(_this.teleportHandCollisionPick); + } + if (_this.teleportHeadCollisionPick !== undefined) { + Picks.removePick(_this.teleportHeadCollisionPick); + } + var capsuleData = MyAvatar.getCollisionCapsule(); + var capsuleHeight = Vec3.distance(capsuleData.start, capsuleData.end); + var offset = Vec3.distance(Vec3.sum(capsuleData.start, {x: 0, y: 0.5*capsuleHeight, z: 0}), MyAvatar.position); + var radius = capsuleData.radius; + var height = 2.0 * radius + capsuleHeight; + var scale = height/2.0; + + _this.teleportHandCollisionPick = Picks.createPick(PickType.Collision, { + enabled: true, + parentID: Pointers.getPointerProperties(_this.teleportParabolaHandInvisible).renderStates["invisible"].end, + filter: Picks.PICK_ENTITIES + Picks.PICK_AVATARS, + shape: { + shapeType: "capsule-y", + dimensions: { + x: radius * 2.0, + y: height - (radius * 2.0), + z: radius * 2.0 + } + }, + position: { x: 0, y: offset + (height * 0.5), z: 0 }, + threshold: scale * _this.capsuleThreshold + }); + + _this.teleportHeadCollisionPick = Picks.createPick(PickType.Collision, { + enabled: true, + parentID: Pointers.getPointerProperties(_this.teleportParabolaHeadInvisible).renderStates["invisible"].end, + filter: Picks.PICK_ENTITIES + Picks.PICK_AVATARS, + shape: { + shapeType: "capsule-y", + dimensions: { + x: radius * 2.0, + y: height - (radius * 2.0), + z: radius * 2.0 + } + }, + position: { x: 0, y: offset + (height * 0.5), z: 0 }, + threshold: scale * _this.capsuleThreshold + }); + } + + _this.recreateCollisionPicks(); this.cleanup = function() { Pointers.removePointer(_this.teleportParabolaHandVisible); Pointers.removePointer(_this.teleportParabolaHandInvisible); Pointers.removePointer(_this.teleportParabolaHeadVisible); Pointers.removePointer(_this.teleportParabolaHeadInvisible); - Picks.removePick(_this.teleportCollisionPick); + Picks.removePick(_this.teleportHandCollisionPick); + Picks.removePick(_this.teleportHeadCollisionPick); }; this.axisButtonStateX = 0; // Left/right axis button pressed. @@ -307,13 +329,17 @@ Script.include("/~/system/libraries/controllers.js"); if (!pose.valid) { Pointers.disablePointer(_this.teleportParabolaHandVisible); Pointers.disablePointer(_this.teleportParabolaHandInvisible); + Picks.disablePick(_this.teleportHandCollisionPick); Pointers.enablePointer(_this.teleportParabolaHeadVisible); Pointers.enablePointer(_this.teleportParabolaHeadInvisible); + Picks.enablePick(_this.teleportHeadCollisionPick); } else { Pointers.enablePointer(_this.teleportParabolaHandVisible); Pointers.enablePointer(_this.teleportParabolaHandInvisible); + Picks.enablePick(_this.teleportHandCollisionPick); Pointers.disablePointer(_this.teleportParabolaHeadVisible); Pointers.disablePointer(_this.teleportParabolaHeadInvisible); + Picks.disablePick(_this.teleportHeadCollisionPick); } // We do up to 2 picks to find a teleport location. @@ -325,15 +351,17 @@ Script.include("/~/system/libraries/controllers.js"); // We might hit an invisible entity that is not a seat, so we need to do a second pass. // * In the second pass we pick against visible entities only. // - var result; + var result, collisionResult; if (mode === 'head') { result = Pointers.getPrevPickResult(_this.teleportParabolaHeadInvisible); + collisionResult = Picks.getPrevPickResult(_this.teleportHeadCollisionPick); } else { result = Pointers.getPrevPickResult(_this.teleportParabolaHandInvisible); + collisionResult = Picks.getPrevPickResult(_this.teleportHandCollisionPick); } - var collisionResult = Picks.getPrevPickResult(_this.teleportCollisionPick); var teleportLocationType = getTeleportTargetType(result, collisionResult); + if (teleportLocationType === TARGET.INVISIBLE) { if (mode === 'head') { result = Pointers.getPrevPickResult(_this.teleportParabolaHeadVisible); @@ -386,6 +414,8 @@ Script.include("/~/system/libraries/controllers.js"); Pointers.disablePointer(_this.teleportParabolaHandInvisible); Pointers.disablePointer(_this.teleportParabolaHeadVisible); Pointers.disablePointer(_this.teleportParabolaHeadInvisible); + Picks.disablePick(_this.teleportParabolaHeadInvisible); + Picks.disablePick(_this.teleportParabolaHandInvisible); }; this.setTeleportState = function(mode, visibleState, invisibleState) { @@ -610,13 +640,13 @@ Script.include("/~/system/libraries/controllers.js"); } var afterSet = new AfterSet(100, 30, function(value) { - leftTeleporter.recreateCollisionPick(); - rightTeleporter.recreateCollisionPick(); + leftTeleporter.recreateCollisionPicks(); + rightTeleporter.recreateCollisionPicks(); }); MyAvatar.onLoadComplete.connect(function () { - leftTeleporter.recreateCollisionPick(); - rightTeleporter.recreateCollisionPick(); + leftTeleporter.recreateCollisionPicks(); + rightTeleporter.recreateCollisionPicks(); }); MyAvatar.sensorToWorldScaleChanged.connect(function() { From d09391faa5f1247c127e554e9e8c8438cdfe5749 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 7 Sep 2018 12:17:40 -0700 Subject: [PATCH 04/19] Fix invisible error --- interface/src/avatar/MyAvatar.cpp | 1 + .../controllers/controllerModules/teleport.js | 104 +++++------------- 2 files changed, 31 insertions(+), 74 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9a78f394e1..1a5f8804e4 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3315,6 +3315,7 @@ QVariantMap MyAvatar::getCollisionCapsule() { capsule["start"] = vec3toVariant(start); capsule["end"] = vec3toVariant(end); capsule["radius"] = QVariant(radius); + capsule["scale"] = QVariant(getModelScale()); return capsule; } diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index 92fc91094d..02b470d332 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -22,7 +22,6 @@ Script.include("/~/system/libraries/controllers.js"); (function() { // BEGIN LOCAL_SCOPE var TARGET_MODEL_URL = Script.resolvePath("../../assets/models/teleport-destination.fbx"); - var CANCEL_MODEL_URL = Script.resolvePath("../../assets/models/teleport-cancel.fbx"); var SEAT_MODEL_URL = Script.resolvePath("../../assets/models/teleport-seat.fbx"); var TARGET_MODEL_DIMENSIONS = { @@ -63,28 +62,26 @@ Script.include("/~/system/libraries/controllers.js"); alpha: 1, width: 0.025 }; + var teleportPath = { color: COLORS_TELEPORT_CAN_TELEPORT, alpha: 1, width: 0.025 }; + var seatPath = { color: COLORS_TELEPORT_SEAT, alpha: 1, width: 0.025 }; - var cancelEnd = { - type: "model", - url: CANCEL_MODEL_URL, - dimensions: TARGET_MODEL_DIMENSIONS, - ignorePickIntersection: true - }; + var teleportEnd = { type: "model", url: TARGET_MODEL_URL, dimensions: TARGET_MODEL_DIMENSIONS, ignorePickIntersection: true }; + var seatEnd = { type: "model", url: SEAT_MODEL_URL, @@ -93,19 +90,20 @@ Script.include("/~/system/libraries/controllers.js"); }; var collisionEnd = { - type: "sphere", - dimensions: {x: 0, y: 0, z: 0}, + type: "shape", + shape: "box", + dimensions: TARGET_MODEL_DIMENSIONS, + alpha: 0.0, ignorePickIntersection: true }; - var teleportRenderStates = [{name: "noend", path: cancelPath}, - {name: "cancel", path: cancelPath, end: cancelEnd}, + var teleportRenderStates = [{name: "cancel", path: cancelPath}, {name: "teleport", path: teleportPath, end: teleportEnd}, {name: "seat", path: seatPath, end: seatEnd}, {name: "invisible", end: collisionEnd}]; var DEFAULT_DISTANCE = 8.0; - var teleportDefaultRenderStates = [{name: "noend", distance: DEFAULT_DISTANCE, path: cancelPath}]; + var teleportDefaultRenderStates = [{name: "cancel", distance: DEFAULT_DISTANCE, path: cancelPath}]; var ignoredEntities = []; @@ -117,9 +115,9 @@ Script.include("/~/system/libraries/controllers.js"); var TARGET = { NONE: 'none', // Not currently targetting anything - INVISIBLE: 'invisible', // The current target is an invvsible surface + INVISIBLE: 'invisible', // The current target is an invisible surface INVALID: 'invalid', // The current target is invalid (wall, ceiling, etc.) - CANCEL: 'cancel', // Insufficient space to accommodate the avatar capsule + COLLIDES: 'collides', // Insufficient space to accommodate the avatar capsule SURFACE: 'surface', // The current target is a valid surface SEAT: 'seat' // The current target is a seat }; @@ -205,20 +203,20 @@ Script.include("/~/system/libraries/controllers.js"); this.teleportHandCollisionPick; this.recreateCollisionPicks = function() { - if (_this.teleportHandCollisionPick !== undefined) { Picks.removePick(_this.teleportHandCollisionPick); } if (_this.teleportHeadCollisionPick !== undefined) { Picks.removePick(_this.teleportHeadCollisionPick); } + var capsuleData = MyAvatar.getCollisionCapsule(); var capsuleHeight = Vec3.distance(capsuleData.start, capsuleData.end); - var offset = Vec3.distance(Vec3.sum(capsuleData.start, {x: 0, y: 0.5*capsuleHeight, z: 0}), MyAvatar.position); - var radius = capsuleData.radius; - var height = 2.0 * radius + capsuleHeight; - var scale = height/2.0; - + var scale = capsuleData.scale; + var offset = Vec3.distance(Vec3.sum(capsuleData.start, {x: 0, y: 0.5*capsuleHeight, z: 0}), MyAvatar.position)/scale; + var radius = capsuleData.radius/scale; + var height = 2.0 * radius + capsuleHeight/scale; + _this.teleportHandCollisionPick = Picks.createPick(PickType.Collision, { enabled: true, parentID: Pointers.getPointerProperties(_this.teleportParabolaHandInvisible).renderStates["invisible"].end, @@ -232,7 +230,7 @@ Script.include("/~/system/libraries/controllers.js"); } }, position: { x: 0, y: offset + (height * 0.5), z: 0 }, - threshold: scale * _this.capsuleThreshold + threshold: _this.capsuleThreshold * scale }); _this.teleportHeadCollisionPick = Picks.createPick(PickType.Collision, { @@ -248,7 +246,7 @@ Script.include("/~/system/libraries/controllers.js"); } }, position: { x: 0, y: offset + (height * 0.5), z: 0 }, - threshold: scale * _this.capsuleThreshold + threshold: _this.capsuleThreshold * scale }); } @@ -368,15 +366,15 @@ Script.include("/~/system/libraries/controllers.js"); } else { result = Pointers.getPrevPickResult(_this.teleportParabolaHandVisible); } - teleportLocationType = getTeleportTargetType(result); + teleportLocationType = getTeleportTargetType(result, collisionResult); } if (teleportLocationType === TARGET.NONE) { // Use the cancel default state - this.setTeleportState(mode, "noend", ""); + this.setTeleportState(mode, "cancel", ""); } else if (teleportLocationType === TARGET.INVALID || teleportLocationType === TARGET.INVISIBLE) { - this.setTeleportState(mode, "", "noend"); - } else if (teleportLocationType === TARGET.CANCEL) { + this.setTeleportState(mode, "", "cancel"); + } else if (teleportLocationType === TARGET.COLLIDES) { this.setTeleportState(mode, "cancel", "invisible"); } else if (teleportLocationType === TARGET.SURFACE) { this.setTeleportState(mode, "teleport", "invisible"); @@ -496,6 +494,12 @@ Script.include("/~/system/libraries/controllers.js"); return TARGET.INVALID; } } + + if (collisionResult.collisionRegion != undefined) { + if (collisionResult.intersects) { + return TARGET.COLLIDES; + } + } if (!props.visible) { return TARGET.INVISIBLE; @@ -507,11 +511,6 @@ Script.include("/~/system/libraries/controllers.js"); if (angle > MAX_ANGLE_FROM_UP_TO_TELEPORT) { return TARGET.INVALID; } else { - if (collisionResult.collisionRegion != undefined) { - if (collisionResult.intersects) { - return TARGET.CANCEL; - } - } return TARGET.SURFACE; } } @@ -605,54 +604,11 @@ Script.include("/~/system/libraries/controllers.js"); } }; - // This class execute a function after the param value haven't been set for a certain time - // It's used in this case to recreate the collision picks once when the avatar scale process ends - - var AfterSet = function(time, maxsteps, callback) { - var self = this; - this.time = time; - this.callback = callback; - this.init = false; - this.value = 0; - this.interval; - this.maxsteps = maxsteps; - this.steps = 0; - this.restateValue = function(value) { - if (self.steps++ > self.maxsteps) { - self.callback.call(this, self.value); - self.steps = 0; - } - if (!self.init) { - console.log("Starting apply after"); - } - self.init = true; - self.value = value; - if (self.interval !== undefined) { - Script.clearInterval(self.interval); - } - self.interval = Script.setInterval(function() { - self.callback.call(this, self.value); - self.init = false; - Script.clearInterval(self.interval); - self.interval = undefined; - }, self.time); - } - } - - var afterSet = new AfterSet(100, 30, function(value) { - leftTeleporter.recreateCollisionPicks(); - rightTeleporter.recreateCollisionPicks(); - }); - MyAvatar.onLoadComplete.connect(function () { leftTeleporter.recreateCollisionPicks(); rightTeleporter.recreateCollisionPicks(); }); - MyAvatar.sensorToWorldScaleChanged.connect(function() { - afterSet.restateValue(MyAvatar.getSensorToWorldScale()); - }); - Messages.subscribe('Hifi-Teleport-Disabler'); Messages.subscribe('Hifi-Teleport-Ignore-Add'); Messages.subscribe('Hifi-Teleport-Ignore-Remove'); From a9f676354b5d6a2466424aeb522c062342d1a5b7 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Mon, 10 Sep 2018 08:54:53 -0700 Subject: [PATCH 05/19] Only invisible pointers and scale fix --- interface/src/avatar/MyAvatar.cpp | 4 +- .../controllers/controllerModules/teleport.js | 242 +++++++++--------- 2 files changed, 117 insertions(+), 129 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1a5f8804e4..4b05015924 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3312,10 +3312,8 @@ QVariantMap MyAvatar::getCollisionCapsule() { float radius; getCapsule(start, end, radius); QVariantMap capsule; - capsule["start"] = vec3toVariant(start); - capsule["end"] = vec3toVariant(end); + capsule["height"] = QVariant(glm::length(start - end)); capsule["radius"] = QVariant(radius); - capsule["scale"] = QVariant(getModelScale()); return capsule; } diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index 02b470d332..ce3b4f2981 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -92,7 +92,7 @@ Script.include("/~/system/libraries/controllers.js"); var collisionEnd = { type: "shape", shape: "box", - dimensions: TARGET_MODEL_DIMENSIONS, + dimensions: { x: 1.0, y: 0.001, z: 1.0 }, alpha: 0.0, ignorePickIntersection: true }; @@ -115,7 +115,6 @@ Script.include("/~/system/libraries/controllers.js"); var TARGET = { NONE: 'none', // Not currently targetting anything - INVISIBLE: 'invisible', // The current target is an invisible surface INVALID: 'invalid', // The current target is invalid (wall, ceiling, etc.) COLLIDES: 'collides', // Insufficient space to accommodate the avatar capsule SURFACE: 'surface', // The current target is a valid surface @@ -127,6 +126,7 @@ Script.include("/~/system/libraries/controllers.js"); function Teleporter(hand) { var _this = this; + this.init = false; this.hand = hand; this.buttonValue = 0; this.disabled = false; // used by the 'Hifi-Teleport-Disabler' message handler @@ -135,122 +135,19 @@ Script.include("/~/system/libraries/controllers.js"); this.currentTarget = TARGET.INVALID; this.currentResult = null; this.capsuleThreshold = 0.05; + this.pickHeightOffset = 0.15; this.getOtherModule = function() { var otherModule = this.hand === RIGHT_HAND ? leftTeleporter : rightTeleporter; return otherModule; }; - this.teleportParabolaHandVisible = Pointers.createPointer(PickType.Parabola, { - joint: (_this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", - dirOffset: { x: 0, y: 1, z: 0.1 }, - posOffset: { x: (_this.hand === RIGHT_HAND) ? 0.03 : -0.03, y: 0.2, z: 0.02 }, - filter: Picks.PICK_ENTITIES, - faceAvatar: true, - scaleWithAvatar: true, - centerEndY: false, - speed: speed, - accelerationAxis: accelerationAxis, - rotateAccelerationWithAvatar: true, - renderStates: teleportRenderStates, - defaultRenderStates: teleportDefaultRenderStates, - maxDistance: 8.0 - }); - - this.teleportParabolaHandInvisible = Pointers.createPointer(PickType.Parabola, { - joint: (_this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", - dirOffset: { x: 0, y: 1, z: 0.1 }, - posOffset: { x: (_this.hand === RIGHT_HAND) ? 0.03 : -0.03, y: 0.2, z: 0.02 }, - filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, - faceAvatar: true, - scaleWithAvatar: true, - centerEndY: false, - speed: speed, - accelerationAxis: accelerationAxis, - rotateAccelerationWithAvatar: true, - renderStates: teleportRenderStates, - maxDistance: 8.0 - }); - - this.teleportParabolaHeadVisible = Pointers.createPointer(PickType.Parabola, { - joint: "Avatar", - filter: Picks.PICK_ENTITIES, - faceAvatar: true, - scaleWithAvatar: true, - centerEndY: false, - speed: speed, - accelerationAxis: accelerationAxis, - rotateAccelerationWithAvatar: true, - renderStates: teleportRenderStates, - defaultRenderStates: teleportDefaultRenderStates, - maxDistance: 8.0 - }); - - this.teleportParabolaHeadInvisible = Pointers.createPointer(PickType.Parabola, { - joint: "Avatar", - filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, - faceAvatar: true, - scaleWithAvatar: true, - centerEndY: false, - speed: speed, - accelerationAxis: accelerationAxis, - rotateAccelerationWithAvatar: true, - renderStates: teleportRenderStates, - maxDistance: 8.0 - }); - this.teleportHeadCollisionPick; this.teleportHandCollisionPick; - - this.recreateCollisionPicks = function() { - if (_this.teleportHandCollisionPick !== undefined) { - Picks.removePick(_this.teleportHandCollisionPick); - } - if (_this.teleportHeadCollisionPick !== undefined) { - Picks.removePick(_this.teleportHeadCollisionPick); - } - - var capsuleData = MyAvatar.getCollisionCapsule(); - var capsuleHeight = Vec3.distance(capsuleData.start, capsuleData.end); - var scale = capsuleData.scale; - var offset = Vec3.distance(Vec3.sum(capsuleData.start, {x: 0, y: 0.5*capsuleHeight, z: 0}), MyAvatar.position)/scale; - var radius = capsuleData.radius/scale; - var height = 2.0 * radius + capsuleHeight/scale; - - _this.teleportHandCollisionPick = Picks.createPick(PickType.Collision, { - enabled: true, - parentID: Pointers.getPointerProperties(_this.teleportParabolaHandInvisible).renderStates["invisible"].end, - filter: Picks.PICK_ENTITIES + Picks.PICK_AVATARS, - shape: { - shapeType: "capsule-y", - dimensions: { - x: radius * 2.0, - y: height - (radius * 2.0), - z: radius * 2.0 - } - }, - position: { x: 0, y: offset + (height * 0.5), z: 0 }, - threshold: _this.capsuleThreshold * scale - }); - - _this.teleportHeadCollisionPick = Picks.createPick(PickType.Collision, { - enabled: true, - parentID: Pointers.getPointerProperties(_this.teleportParabolaHeadInvisible).renderStates["invisible"].end, - filter: Picks.PICK_ENTITIES + Picks.PICK_AVATARS, - shape: { - shapeType: "capsule-y", - dimensions: { - x: radius * 2.0, - y: height - (radius * 2.0), - z: radius * 2.0 - } - }, - position: { x: 0, y: offset + (height * 0.5), z: 0 }, - threshold: _this.capsuleThreshold * scale - }); - } - - _this.recreateCollisionPicks(); + this.teleportParabolaHandVisible; + this.teleportParabolaHandInvisible; + this.teleportParabolaHeadVisible; + this.teleportParabolaHeadInvisible; this.cleanup = function() { Pointers.removePointer(_this.teleportParabolaHandVisible); @@ -261,6 +158,110 @@ Script.include("/~/system/libraries/controllers.js"); Picks.removePick(_this.teleportHeadCollisionPick); }; + this.initPointers = function () { + if (_this.init) { + _this.cleanup(); + } + _this.teleportParabolaHandVisible = Pointers.createPointer(PickType.Parabola, { + joint: (_this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", + dirOffset: { x: 0, y: 1, z: 0.1 }, + posOffset: { x: (_this.hand === RIGHT_HAND) ? 0.03 : -0.03, y: 0.2, z: 0.02 }, + filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, + faceAvatar: true, + scaleWithAvatar: true, + centerEndY: false, + speed: speed, + accelerationAxis: accelerationAxis, + rotateAccelerationWithAvatar: true, + renderStates: teleportRenderStates, + defaultRenderStates: teleportDefaultRenderStates, + maxDistance: 8.0 + }); + + _this.teleportParabolaHandInvisible = Pointers.createPointer(PickType.Parabola, { + joint: (_this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", + dirOffset: { x: 0, y: 1, z: 0.1 }, + posOffset: { x: (_this.hand === RIGHT_HAND) ? 0.03 : -0.03, y: 0.2, z: 0.02 }, + filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, + faceAvatar: true, + scaleWithAvatar: true, + centerEndY: false, + speed: speed, + accelerationAxis: accelerationAxis, + rotateAccelerationWithAvatar: true, + renderStates: teleportRenderStates, + maxDistance: 8.0 + }); + + _this.teleportParabolaHeadVisible = Pointers.createPointer(PickType.Parabola, { + joint: "Avatar", + filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, + faceAvatar: true, + scaleWithAvatar: true, + centerEndY: false, + speed: speed, + accelerationAxis: accelerationAxis, + rotateAccelerationWithAvatar: true, + renderStates: teleportRenderStates, + defaultRenderStates: teleportDefaultRenderStates, + maxDistance: 8.0 + }); + + _this.teleportParabolaHeadInvisible = Pointers.createPointer(PickType.Parabola, { + joint: "Avatar", + filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, + faceAvatar: true, + scaleWithAvatar: true, + centerEndY: false, + speed: speed, + accelerationAxis: accelerationAxis, + rotateAccelerationWithAvatar: true, + renderStates: teleportRenderStates, + maxDistance: 8.0 + }); + + + var capsuleData = MyAvatar.getCollisionCapsule(); + + var radius = capsuleData.radius / MyAvatar.scale; + var height = (capsuleData.height + (radius * 2.0)) / MyAvatar.scale; + + _this.teleportHandCollisionPick = Picks.createPick(PickType.Collision, { + enabled: true, + parentID: Pointers.getPointerProperties(_this.teleportParabolaHandInvisible).renderStates["invisible"].end, + filter: Picks.PICK_ENTITIES + Picks.PICK_AVATARS, + shape: { + shapeType: "capsule-y", + dimensions: { + x: radius * 2.0, + y: height - (radius * 2.0), + z: radius * 2.0 + } + }, + position: { x: 0, y: _this.pickHeightOffset + height * 0.5, z: 0 }, + threshold: _this.capsuleThreshold + }); + + _this.teleportHeadCollisionPick = Picks.createPick(PickType.Collision, { + enabled: true, + parentID: Pointers.getPointerProperties(_this.teleportParabolaHeadInvisible).renderStates["invisible"].end, + filter: Picks.PICK_ENTITIES + Picks.PICK_AVATARS, + shape: { + shapeType: "capsule-y", + dimensions: { + x: radius * 2.0, + y: height - (radius * 2.0), + z: radius * 2.0 + } + }, + position: { x: 0, y: _this.pickHeightOffset + height * 0.5, z: 0 }, + threshold: _this.capsuleThreshold + }); + _this.init = true; + } + + _this.initPointers(); + this.axisButtonStateX = 0; // Left/right axis button pressed. this.axisButtonStateY = 0; // Up/down axis button pressed. this.BUTTON_TRANSITION_DELAY = 100; // Allow time for transition from direction buttons to touch-pad. @@ -359,20 +360,11 @@ Script.include("/~/system/libraries/controllers.js"); } var teleportLocationType = getTeleportTargetType(result, collisionResult); - - if (teleportLocationType === TARGET.INVISIBLE) { - if (mode === 'head') { - result = Pointers.getPrevPickResult(_this.teleportParabolaHeadVisible); - } else { - result = Pointers.getPrevPickResult(_this.teleportParabolaHandVisible); - } - teleportLocationType = getTeleportTargetType(result, collisionResult); - } if (teleportLocationType === TARGET.NONE) { // Use the cancel default state this.setTeleportState(mode, "cancel", ""); - } else if (teleportLocationType === TARGET.INVALID || teleportLocationType === TARGET.INVISIBLE) { + } else if (teleportLocationType === TARGET.INVALID) { this.setTeleportState(mode, "", "cancel"); } else if (teleportLocationType === TARGET.COLLIDES) { this.setTeleportState(mode, "cancel", "invisible"); @@ -501,10 +493,6 @@ Script.include("/~/system/libraries/controllers.js"); } } - if (!props.visible) { - return TARGET.INVISIBLE; - } - var surfaceNormal = result.surfaceNormal; var angle = Math.acos(Vec3.dot(surfaceNormal, Quat.getUp(MyAvatar.orientation))) * (180.0 / Math.PI); @@ -605,8 +593,10 @@ Script.include("/~/system/libraries/controllers.js"); }; MyAvatar.onLoadComplete.connect(function () { - leftTeleporter.recreateCollisionPicks(); - rightTeleporter.recreateCollisionPicks(); + Script.setTimeout(function () { + leftTeleporter.initPointers(); + rightTeleporter.initPointers(); + }, 500); }); Messages.subscribe('Hifi-Teleport-Disabler'); From 9a86b7451be728d5cf7ffb96e977584cb227f9e2 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Mon, 10 Sep 2018 14:35:04 -0700 Subject: [PATCH 06/19] Add collision group parameter to collision pick and set my avatar as the default --- interface/src/raypick/CollisionPick.cpp | 4 ++-- interface/src/raypick/PickScriptingInterface.cpp | 2 ++ libraries/shared/src/RegisteredMetaTypes.h | 13 +++++++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/interface/src/raypick/CollisionPick.cpp b/interface/src/raypick/CollisionPick.cpp index c21ee69b74..e3c982d812 100644 --- a/interface/src/raypick/CollisionPick.cpp +++ b/interface/src/raypick/CollisionPick.cpp @@ -397,7 +397,7 @@ PickResultPointer CollisionPick::getEntityIntersection(const CollisionRegion& pi } getShapeInfoReady(pick); - auto entityIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_ENTITIES, *_mathPick.shapeInfo, pick.transform, USER_COLLISION_GROUP_DYNAMIC, pick.threshold); + auto entityIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_ENTITIES, *_mathPick.shapeInfo, pick.transform, pick.collisionGroup, pick.threshold); filterIntersections(entityIntersections); return std::make_shared(pick, entityIntersections, std::vector()); } @@ -413,7 +413,7 @@ PickResultPointer CollisionPick::getAvatarIntersection(const CollisionRegion& pi } getShapeInfoReady(pick); - auto avatarIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_AVATARS, *_mathPick.shapeInfo, pick.transform, USER_COLLISION_GROUP_DYNAMIC, pick.threshold); + auto avatarIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_AVATARS, *_mathPick.shapeInfo, pick.transform, pick.collisionGroup, pick.threshold); filterIntersections(avatarIntersections); return std::make_shared(pick, std::vector(), avatarIntersections); } diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index 0273b084b2..b9693f6782 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -270,6 +270,8 @@ unsigned int PickScriptingInterface::createParabolaPick(const QVariant& properti * @property {Quat} orientation - The orientation of the collision region, relative to a parent if defined. * @property {float} threshold - The approximate minimum penetration depth for a test object to be considered in contact with the collision region. * The depth is measured in world space, but will scale with the parent if defined. +* @property {CollisionMask} [collisionGroup=8] - The type of object this collision pick collides as. Objects whose collision masks overlap with the pick's collision group +* will be considered colliding with the pick. * @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or an overlay. * @property {number} parentJointIndex - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint) * @property {string} joint - If "Mouse," parents the pick to the mouse. If "Avatar," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar. diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index d59c58def8..4ca94fa222 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -24,6 +24,7 @@ #include "SharedUtil.h" #include "shared/Bilateral.h" #include "Transform.h" +#include "PhysicsCollisionGroups.h" class QColor; class QUrl; @@ -264,6 +265,8 @@ public: * @property {Quat} orientation - The orientation of the collision region, relative to a parent if defined. * @property {float} threshold - The approximate minimum penetration depth for a test object to be considered in contact with the collision region. * The depth is measured in world space, but will scale with the parent if defined. +* @property {CollisionMask} [collisionGroup=8] - The type of object this collision pick collides as. Objects whose collision masks overlap with the pick's collision group +* will be considered colliding with the pick. * @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or an overlay. * @property {number} parentJointIndex - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint) * @property {string} joint - If "Mouse," parents the pick to the mouse. If "Avatar," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar. @@ -277,7 +280,8 @@ public: modelURL(collisionRegion.modelURL), shapeInfo(std::make_shared()), transform(collisionRegion.transform), - threshold(collisionRegion.threshold) + threshold(collisionRegion.threshold), + collisionGroup(collisionRegion.collisionGroup) { shapeInfo->setParams(collisionRegion.shapeInfo->getType(), collisionRegion.shapeInfo->getHalfExtents(), collisionRegion.modelURL.toString()); } @@ -316,6 +320,9 @@ public: if (pickVariant["orientation"].isValid()) { transform.setRotation(quatFromVariant(pickVariant["orientation"])); } + if (pickVariant["collisionGroup"].isValid()) { + collisionGroup = pickVariant["collisionGroup"].toUInt(); + } } QVariantMap toVariantMap() const override { @@ -330,6 +337,7 @@ public: collisionRegion["loaded"] = loaded; collisionRegion["threshold"] = threshold; + collisionRegion["collisionGroup"] = collisionGroup; collisionRegion["position"] = vec3toVariant(transform.getTranslation()); collisionRegion["orientation"] = quatToVariant(transform.getRotation()); @@ -372,7 +380,8 @@ public: // We can't compute the shapeInfo here without loading the model first, so we delegate that responsibility to the owning CollisionPick std::shared_ptr shapeInfo = std::make_shared(); Transform transform; - float threshold; + float threshold { 0.0f }; + uint16_t collisionGroup { USER_COLLISION_GROUP_MY_AVATAR }; }; namespace std { From 3b7dac905896279ddad6c29662fe3ff6621d2cea Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Mon, 10 Sep 2018 15:14:48 -0700 Subject: [PATCH 07/19] Account for collisionGroup in CollisionRegion implementation --- libraries/shared/src/RegisteredMetaTypes.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 4ca94fa222..6ecf9faca7 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -349,12 +349,14 @@ public: return !std::isnan(threshold) && !(glm::any(glm::isnan(transform.getTranslation())) || glm::any(glm::isnan(transform.getRotation())) || - shapeInfo->getType() == SHAPE_TYPE_NONE); + shapeInfo->getType() == SHAPE_TYPE_NONE || + collisionGroup == 0); } bool operator==(const CollisionRegion& other) const { return loaded == other.loaded && threshold == other.threshold && + collisionGroup == other.collisionGroup && glm::all(glm::equal(transform.getTranslation(), other.transform.getTranslation())) && glm::all(glm::equal(transform.getRotation(), other.transform.getRotation())) && glm::all(glm::equal(transform.getScale(), other.transform.getScale())) && @@ -370,6 +372,10 @@ public: return false; } + if (collisionGroup == 0) { + return false; + } + return !shapeInfo->getPointCollection().size(); } From 13de22adb31969a06dbf36334f8704f5ce4fc4d1 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 11 Sep 2018 07:22:59 -0700 Subject: [PATCH 08/19] Fix radius scale --- scripts/system/controllers/controllerModules/teleport.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index ce3b4f2981..a17f592b28 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -135,7 +135,7 @@ Script.include("/~/system/libraries/controllers.js"); this.currentTarget = TARGET.INVALID; this.currentResult = null; this.capsuleThreshold = 0.05; - this.pickHeightOffset = 0.15; + this.pickHeightOffset = 0.1; this.getOtherModule = function() { var otherModule = this.hand === RIGHT_HAND ? leftTeleporter : rightTeleporter; @@ -224,7 +224,7 @@ Script.include("/~/system/libraries/controllers.js"); var capsuleData = MyAvatar.getCollisionCapsule(); var radius = capsuleData.radius / MyAvatar.scale; - var height = (capsuleData.height + (radius * 2.0)) / MyAvatar.scale; + var height = (capsuleData.height + (capsuleData.radius * 2.0)) / MyAvatar.scale; _this.teleportHandCollisionPick = Picks.createPick(PickType.Collision, { enabled: true, From 82b662d08e487118c62399d18ef9b185d8d28eb3 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 11 Sep 2018 09:34:36 -0700 Subject: [PATCH 09/19] Add pick offset --- scripts/system/controllers/controllerModules/teleport.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index a17f592b28..c80cfb52a6 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -135,7 +135,7 @@ Script.include("/~/system/libraries/controllers.js"); this.currentTarget = TARGET.INVALID; this.currentResult = null; this.capsuleThreshold = 0.05; - this.pickHeightOffset = 0.1; + this.pickHeightOffset = 0.15; this.getOtherModule = function() { var otherModule = this.hand === RIGHT_HAND ? leftTeleporter : rightTeleporter; From fedea6e84d75f887f450488beb8a0daec39fa3e8 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 11 Sep 2018 12:23:25 -0700 Subject: [PATCH 10/19] Comply with review comments --- interface/src/avatar/MyAvatar.cpp | 4 +++- scripts/system/controllers/controllerModules/teleport.js | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4b05015924..9d7dd54245 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3311,8 +3311,10 @@ QVariantMap MyAvatar::getCollisionCapsule() { glm::vec3 start, end; float radius; getCapsule(start, end, radius); + QVariantMap capsule; - capsule["height"] = QVariant(glm::length(start - end)); + capsule["start"] = vec3toVariant(start); + capsule["end"] = vec3toVariant(end); capsule["radius"] = QVariant(radius); return capsule; } diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index c80cfb52a6..c9a72a0cba 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -224,12 +224,12 @@ Script.include("/~/system/libraries/controllers.js"); var capsuleData = MyAvatar.getCollisionCapsule(); var radius = capsuleData.radius / MyAvatar.scale; - var height = (capsuleData.height + (capsuleData.radius * 2.0)) / MyAvatar.scale; + var height = (Vec3.distance(capsuleData.start, capsuleData.end) + (capsuleData.radius * 2.0)) / MyAvatar.scale; _this.teleportHandCollisionPick = Picks.createPick(PickType.Collision, { enabled: true, parentID: Pointers.getPointerProperties(_this.teleportParabolaHandInvisible).renderStates["invisible"].end, - filter: Picks.PICK_ENTITIES + Picks.PICK_AVATARS, + filter: Picks.PICK_ENTITIES | Picks.PICK_AVATARS, shape: { shapeType: "capsule-y", dimensions: { @@ -245,7 +245,7 @@ Script.include("/~/system/libraries/controllers.js"); _this.teleportHeadCollisionPick = Picks.createPick(PickType.Collision, { enabled: true, parentID: Pointers.getPointerProperties(_this.teleportParabolaHeadInvisible).renderStates["invisible"].end, - filter: Picks.PICK_ENTITIES + Picks.PICK_AVATARS, + filter: Picks.PICK_ENTITIES | Picks.PICK_AVATARS, shape: { shapeType: "capsule-y", dimensions: { From 87b5605d69bb6d1b7dd11d711f8992da19d935bd Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Tue, 11 Sep 2018 18:05:02 -0700 Subject: [PATCH 11/19] Add normalOnPick to CollisionPickResult --- interface/src/raypick/CollisionPick.cpp | 1 + interface/src/raypick/CollisionPick.h | 3 +++ interface/src/raypick/PickScriptingInterface.h | 1 + libraries/physics/src/PhysicsEngine.cpp | 7 +++++-- libraries/physics/src/PhysicsEngine.h | 10 +++++++--- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/interface/src/raypick/CollisionPick.cpp b/interface/src/raypick/CollisionPick.cpp index e3c982d812..e268918116 100644 --- a/interface/src/raypick/CollisionPick.cpp +++ b/interface/src/raypick/CollisionPick.cpp @@ -51,6 +51,7 @@ void buildObjectIntersectionsMap(IntersectionType intersectionType, const std::v QVariantMap collisionPointPair; collisionPointPair["pointOnPick"] = vec3toVariant(objectIntersection.testCollisionPoint); collisionPointPair["pointOnObject"] = vec3toVariant(objectIntersection.foundCollisionPoint); + collisionPointPair["normalOnPick"] = vec3toVariant(objectIntersection.collisionNormal); collisionPointPairs[objectIntersection.foundID].append(collisionPointPair); } diff --git a/interface/src/raypick/CollisionPick.h b/interface/src/raypick/CollisionPick.h index fe0e5a6337..0662ab6c19 100644 --- a/interface/src/raypick/CollisionPick.h +++ b/interface/src/raypick/CollisionPick.h @@ -70,6 +70,9 @@ protected: CollisionRegion _mathPick; PhysicsEnginePointer _physicsEngine; QSharedPointer _cachedResource; + + // Options for what information to get from collision results + bool _includeNormals; }; #endif // hifi_CollisionPick_h \ No newline at end of file diff --git a/interface/src/raypick/PickScriptingInterface.h b/interface/src/raypick/PickScriptingInterface.h index 4d99309618..36079cec2b 100644 --- a/interface/src/raypick/PickScriptingInterface.h +++ b/interface/src/raypick/PickScriptingInterface.h @@ -167,6 +167,7 @@ public: * @typedef {object} CollisionContact * @property {Vec3} pointOnPick A point representing a penetration of the object's surface into the volume of the pick, in world space. * @property {Vec3} pointOnObject A point representing a penetration of the pick's surface into the volume of the found object, in world space. + * @property {Vec3} normalOnPick The normalized vector pointing away from the pick, representing the direction of collision. */ /**jsdoc diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 58c197d6f4..210c66fbea 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -935,19 +935,22 @@ struct AllContactsCallback : public btCollisionWorld::ContactResultCallback { const btCollisionObject* otherBody; btVector3 penetrationPoint; btVector3 otherPenetrationPoint; + btVector3 normal; if (colObj0->m_collisionObject == &collisionObject) { otherBody = colObj1->m_collisionObject; penetrationPoint = getWorldPoint(cp.m_localPointB, colObj1->getWorldTransform()); otherPenetrationPoint = getWorldPoint(cp.m_localPointA, colObj0->getWorldTransform()); + normal = -cp.m_normalWorldOnB; } else { otherBody = colObj0->m_collisionObject; penetrationPoint = getWorldPoint(cp.m_localPointA, colObj0->getWorldTransform()); otherPenetrationPoint = getWorldPoint(cp.m_localPointB, colObj1->getWorldTransform()); + normal = cp.m_normalWorldOnB; } // TODO: Give MyAvatar a motion state so we don't have to do this if ((m_collisionFilterMask & BULLET_COLLISION_GROUP_MY_AVATAR) && myAvatarCollisionObject && myAvatarCollisionObject == otherBody) { - contacts.emplace_back(Physics::getSessionUUID(), bulletToGLM(penetrationPoint), bulletToGLM(otherPenetrationPoint)); + contacts.emplace_back(Physics::getSessionUUID(), bulletToGLM(penetrationPoint), bulletToGLM(otherPenetrationPoint), bulletToGLM(normal)); return 0; } @@ -963,7 +966,7 @@ struct AllContactsCallback : public btCollisionWorld::ContactResultCallback { } // This is the correct object type. Add it to the list. - contacts.emplace_back(candidate->getObjectID(), bulletToGLM(penetrationPoint), bulletToGLM(otherPenetrationPoint)); + contacts.emplace_back(candidate->getObjectID(), bulletToGLM(penetrationPoint), bulletToGLM(otherPenetrationPoint), bulletToGLM(normal)); return 0; } diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 09b68d9a8b..d10be018b8 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -49,13 +49,15 @@ struct ContactTestResult { ContactTestResult(const ContactTestResult& contactTestResult) : foundID(contactTestResult.foundID), testCollisionPoint(contactTestResult.testCollisionPoint), - foundCollisionPoint(contactTestResult.foundCollisionPoint) { + foundCollisionPoint(contactTestResult.foundCollisionPoint), + collisionNormal(contactTestResult.collisionNormal) { } - ContactTestResult(QUuid foundID, glm::vec3 testCollisionPoint, glm::vec3 otherCollisionPoint) : + ContactTestResult(const QUuid& foundID, const glm::vec3& testCollisionPoint, const glm::vec3& otherCollisionPoint, const glm::vec3& collisionNormal) : foundID(foundID), testCollisionPoint(testCollisionPoint), - foundCollisionPoint(otherCollisionPoint) { + foundCollisionPoint(otherCollisionPoint), + collisionNormal(collisionNormal) { } QUuid foundID; @@ -63,6 +65,8 @@ struct ContactTestResult { glm::vec3 testCollisionPoint; // The deepest point of an intersection within the volume of the found object, in world space. glm::vec3 foundCollisionPoint; + // The normal vector of this intersection + glm::vec3 collisionNormal; }; using ContactMap = std::map; From d2c41f02e5f0cb249f7e091088ac976dbf2fab44 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Tue, 11 Sep 2018 18:07:13 -0700 Subject: [PATCH 12/19] Avoid unnecessary type conversion in CollisionPick::getHUDIntersection --- interface/src/raypick/CollisionPick.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/raypick/CollisionPick.cpp b/interface/src/raypick/CollisionPick.cpp index e268918116..9aee76a3da 100644 --- a/interface/src/raypick/CollisionPick.cpp +++ b/interface/src/raypick/CollisionPick.cpp @@ -420,7 +420,7 @@ PickResultPointer CollisionPick::getAvatarIntersection(const CollisionRegion& pi } PickResultPointer CollisionPick::getHUDIntersection(const CollisionRegion& pick) { - return std::make_shared(pick.toVariantMap(), std::vector(), std::vector()); + return std::make_shared(pick, std::vector(), std::vector()); } Transform CollisionPick::getResultTransform() const { From b517808bc2d731c207535cf0a83dda869a19bdf3 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Wed, 12 Sep 2018 21:24:19 -0700 Subject: [PATCH 13/19] Fix smaller size avatar capsule and land on detailed mesh --- interface/src/avatar/MyAvatar.cpp | 1 - .../controllers/controllerModules/teleport.js | 139 +++++++++++------- 2 files changed, 85 insertions(+), 55 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9d7dd54245..9a78f394e1 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3311,7 +3311,6 @@ QVariantMap MyAvatar::getCollisionCapsule() { glm::vec3 start, end; float radius; getCapsule(start, end, radius); - QVariantMap capsule; capsule["start"] = vec3toVariant(start); capsule["end"] = vec3toVariant(end); diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index c9a72a0cba..707bde7b4f 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -100,7 +100,7 @@ Script.include("/~/system/libraries/controllers.js"); var teleportRenderStates = [{name: "cancel", path: cancelPath}, {name: "teleport", path: teleportPath, end: teleportEnd}, {name: "seat", path: seatPath, end: seatEnd}, - {name: "invisible", end: collisionEnd}]; + {name: "collision", end: collisionEnd}]; var DEFAULT_DISTANCE = 8.0; var teleportDefaultRenderStates = [{name: "cancel", distance: DEFAULT_DISTANCE, path: cancelPath}]; @@ -135,7 +135,7 @@ Script.include("/~/system/libraries/controllers.js"); this.currentTarget = TARGET.INVALID; this.currentResult = null; this.capsuleThreshold = 0.05; - this.pickHeightOffset = 0.15; + this.pickHeightOffset = 0.05; this.getOtherModule = function() { var otherModule = this.hand === RIGHT_HAND ? leftTeleporter : rightTeleporter; @@ -144,16 +144,16 @@ Script.include("/~/system/libraries/controllers.js"); this.teleportHeadCollisionPick; this.teleportHandCollisionPick; - this.teleportParabolaHandVisible; - this.teleportParabolaHandInvisible; - this.teleportParabolaHeadVisible; - this.teleportParabolaHeadInvisible; + this.teleportParabolaHandVisuals; + this.teleportParabolaHandCollisions; + this.teleportParabolaHeadVisuals; + this.teleportParabolaHeadCollisions; this.cleanup = function() { - Pointers.removePointer(_this.teleportParabolaHandVisible); - Pointers.removePointer(_this.teleportParabolaHandInvisible); - Pointers.removePointer(_this.teleportParabolaHeadVisible); - Pointers.removePointer(_this.teleportParabolaHeadInvisible); + Pointers.removePointer(_this.teleportParabolaHandVisuals); + Pointers.removePointer(_this.teleportParabolaHandCollisions); + Pointers.removePointer(_this.teleportParabolaHeadVisuals); + Pointers.removePointer(_this.teleportParabolaHeadCollisions); Picks.removePick(_this.teleportHandCollisionPick); Picks.removePick(_this.teleportHeadCollisionPick); }; @@ -162,11 +162,11 @@ Script.include("/~/system/libraries/controllers.js"); if (_this.init) { _this.cleanup(); } - _this.teleportParabolaHandVisible = Pointers.createPointer(PickType.Parabola, { + _this.teleportParabolaHandVisuals = Pointers.createPointer(PickType.Parabola, { joint: (_this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", dirOffset: { x: 0, y: 1, z: 0.1 }, posOffset: { x: (_this.hand === RIGHT_HAND) ? 0.03 : -0.03, y: 0.2, z: 0.02 }, - filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, + filter: Picks.PICK_ENTITIES + Picks.PICK_INCLUDE_INVISIBLE, faceAvatar: true, scaleWithAvatar: true, centerEndY: false, @@ -178,7 +178,7 @@ Script.include("/~/system/libraries/controllers.js"); maxDistance: 8.0 }); - _this.teleportParabolaHandInvisible = Pointers.createPointer(PickType.Parabola, { + _this.teleportParabolaHandCollisions = Pointers.createPointer(PickType.Parabola, { joint: (_this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", dirOffset: { x: 0, y: 1, z: 0.1 }, posOffset: { x: (_this.hand === RIGHT_HAND) ? 0.03 : -0.03, y: 0.2, z: 0.02 }, @@ -193,9 +193,9 @@ Script.include("/~/system/libraries/controllers.js"); maxDistance: 8.0 }); - _this.teleportParabolaHeadVisible = Pointers.createPointer(PickType.Parabola, { + _this.teleportParabolaHeadVisuals = Pointers.createPointer(PickType.Parabola, { joint: "Avatar", - filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, + filter: Picks.PICK_ENTITIES + Picks.PICK_INCLUDE_INVISIBLE, faceAvatar: true, scaleWithAvatar: true, centerEndY: false, @@ -207,7 +207,7 @@ Script.include("/~/system/libraries/controllers.js"); maxDistance: 8.0 }); - _this.teleportParabolaHeadInvisible = Pointers.createPointer(PickType.Parabola, { + _this.teleportParabolaHeadCollisions = Pointers.createPointer(PickType.Parabola, { joint: "Avatar", filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, faceAvatar: true, @@ -223,12 +223,16 @@ Script.include("/~/system/libraries/controllers.js"); var capsuleData = MyAvatar.getCollisionCapsule(); - var radius = capsuleData.radius / MyAvatar.scale; - var height = (Vec3.distance(capsuleData.start, capsuleData.end) + (capsuleData.radius * 2.0)) / MyAvatar.scale; + var sensorToWorldScale = MyAvatar.getSensorToWorldScale(); + + var radius = capsuleData.radius / sensorToWorldScale; + var height = (Vec3.distance(capsuleData.start, capsuleData.end) + (capsuleData.radius * 2.0)) / sensorToWorldScale; + var capsuleRatio = 10.0 * radius / height; + var offset = _this.pickHeightOffset * capsuleRatio; _this.teleportHandCollisionPick = Picks.createPick(PickType.Collision, { enabled: true, - parentID: Pointers.getPointerProperties(_this.teleportParabolaHandInvisible).renderStates["invisible"].end, + parentID: Pointers.getPointerProperties(_this.teleportParabolaHandCollisions).renderStates["collision"].end, filter: Picks.PICK_ENTITIES | Picks.PICK_AVATARS, shape: { shapeType: "capsule-y", @@ -238,13 +242,13 @@ Script.include("/~/system/libraries/controllers.js"); z: radius * 2.0 } }, - position: { x: 0, y: _this.pickHeightOffset + height * 0.5, z: 0 }, + position: { x: 0, y: offset + height * 0.5, z: 0 }, threshold: _this.capsuleThreshold }); _this.teleportHeadCollisionPick = Picks.createPick(PickType.Collision, { enabled: true, - parentID: Pointers.getPointerProperties(_this.teleportParabolaHeadInvisible).renderStates["invisible"].end, + parentID: Pointers.getPointerProperties(_this.teleportParabolaHeadCollisions).renderStates["collision"].end, filter: Picks.PICK_ENTITIES | Picks.PICK_AVATARS, shape: { shapeType: "capsule-y", @@ -254,7 +258,7 @@ Script.include("/~/system/libraries/controllers.js"); z: radius * 2.0 } }, - position: { x: 0, y: _this.pickHeightOffset + height * 0.5, z: 0 }, + position: { x: 0, y: offset + height * 0.5, z: 0 }, threshold: _this.capsuleThreshold }); _this.init = true; @@ -326,36 +330,40 @@ Script.include("/~/system/libraries/controllers.js"); var pose = Controller.getPoseValue(handInfo[(_this.hand === RIGHT_HAND) ? 'right' : 'left'].controllerInput); var mode = pose.valid ? _this.hand : 'head'; if (!pose.valid) { - Pointers.disablePointer(_this.teleportParabolaHandVisible); - Pointers.disablePointer(_this.teleportParabolaHandInvisible); + Pointers.disablePointer(_this.teleportParabolaHandVisuals); + Pointers.disablePointer(_this.teleportParabolaHandCollisions); Picks.disablePick(_this.teleportHandCollisionPick); - Pointers.enablePointer(_this.teleportParabolaHeadVisible); - Pointers.enablePointer(_this.teleportParabolaHeadInvisible); + Pointers.enablePointer(_this.teleportParabolaHeadVisuals); + Pointers.enablePointer(_this.teleportParabolaHeadCollisions); Picks.enablePick(_this.teleportHeadCollisionPick); } else { - Pointers.enablePointer(_this.teleportParabolaHandVisible); - Pointers.enablePointer(_this.teleportParabolaHandInvisible); + Pointers.enablePointer(_this.teleportParabolaHandVisuals); + Pointers.enablePointer(_this.teleportParabolaHandCollisions); Picks.enablePick(_this.teleportHandCollisionPick); - Pointers.disablePointer(_this.teleportParabolaHeadVisible); - Pointers.disablePointer(_this.teleportParabolaHeadInvisible); + Pointers.disablePointer(_this.teleportParabolaHeadVisuals); + Pointers.disablePointer(_this.teleportParabolaHeadCollisions); Picks.disablePick(_this.teleportHeadCollisionPick); } // We do up to 2 picks to find a teleport location. // There are 2 types of teleport locations we are interested in: - // 1. A visible floor. This can be any entity surface that points within some degree of "up" + // + // 1. A visible floor. This can be any entity surface that points within some degree of "up" + // and where the avatar capsule can be positioned without colliding + // // 2. A seat. The seat can be visible or invisible. // - // * In the first pass we pick against visible and invisible entities so that we can find invisible seats. - // We might hit an invisible entity that is not a seat, so we need to do a second pass. - // * In the second pass we pick against visible entities only. + // The Collision Pick is currently parented to the end overlay on teleportParabolaXXXXCollisions + // + // TODO + // Parent the collision Pick directly to the teleportParabolaXXXXVisuals and get rid of teleportParabolaXXXXCollisions // var result, collisionResult; if (mode === 'head') { - result = Pointers.getPrevPickResult(_this.teleportParabolaHeadInvisible); + result = Pointers.getPrevPickResult(_this.teleportParabolaHeadCollisions); collisionResult = Picks.getPrevPickResult(_this.teleportHeadCollisionPick); } else { - result = Pointers.getPrevPickResult(_this.teleportParabolaHandInvisible); + result = Pointers.getPrevPickResult(_this.teleportParabolaHandCollisions); collisionResult = Picks.getPrevPickResult(_this.teleportHandCollisionPick); } @@ -367,11 +375,11 @@ Script.include("/~/system/libraries/controllers.js"); } else if (teleportLocationType === TARGET.INVALID) { this.setTeleportState(mode, "", "cancel"); } else if (teleportLocationType === TARGET.COLLIDES) { - this.setTeleportState(mode, "cancel", "invisible"); + this.setTeleportState(mode, "cancel", "collision"); } else if (teleportLocationType === TARGET.SURFACE) { - this.setTeleportState(mode, "teleport", "invisible"); + this.setTeleportState(mode, "teleport", "collision"); } else if (teleportLocationType === TARGET.SEAT) { - this.setTeleportState(mode, "", "seat"); + this.setTeleportState(mode, "collision", "seat"); } return this.teleport(result, teleportLocationType); }; @@ -400,29 +408,31 @@ Script.include("/~/system/libraries/controllers.js"); }; this.disableLasers = function() { - Pointers.disablePointer(_this.teleportParabolaHandVisible); - Pointers.disablePointer(_this.teleportParabolaHandInvisible); - Pointers.disablePointer(_this.teleportParabolaHeadVisible); - Pointers.disablePointer(_this.teleportParabolaHeadInvisible); - Picks.disablePick(_this.teleportParabolaHeadInvisible); - Picks.disablePick(_this.teleportParabolaHandInvisible); + Pointers.disablePointer(_this.teleportParabolaHandVisuals); + Pointers.disablePointer(_this.teleportParabolaHandCollisions); + Pointers.disablePointer(_this.teleportParabolaHeadVisuals); + Pointers.disablePointer(_this.teleportParabolaHeadCollisions); + Picks.disablePick(_this.teleportHeadCollisionPick); + Picks.disablePick(_this.teleportHandCollisionPick); }; this.setTeleportState = function(mode, visibleState, invisibleState) { if (mode === 'head') { - Pointers.setRenderState(_this.teleportParabolaHeadVisible, visibleState); - Pointers.setRenderState(_this.teleportParabolaHeadInvisible, invisibleState); + Pointers.setRenderState(_this.teleportParabolaHeadVisuals, visibleState); + Pointers.setRenderState(_this.teleportParabolaHeadCollisions, invisibleState); } else { - Pointers.setRenderState(_this.teleportParabolaHandVisible, visibleState); - Pointers.setRenderState(_this.teleportParabolaHandInvisible, invisibleState); + Pointers.setRenderState(_this.teleportParabolaHandVisuals, visibleState); + Pointers.setRenderState(_this.teleportParabolaHandCollisions, invisibleState); } }; this.setIgnoreEntities = function(entitiesToIgnore) { - Pointers.setIgnoreItems(this.teleportParabolaHandVisible, entitiesToIgnore); - Pointers.setIgnoreItems(this.teleportParabolaHandInvisible, entitiesToIgnore); - Pointers.setIgnoreItems(this.teleportParabolaHeadVisible, entitiesToIgnore); - Pointers.setIgnoreItems(this.teleportParabolaHeadInvisible, entitiesToIgnore); + Pointers.setIgnoreItems(this.teleportParabolaHandVisuals, entitiesToIgnore); + Pointers.setIgnoreItems(this.teleportParabolaHandCollisions, entitiesToIgnore); + Pointers.setIgnoreItems(this.teleportParabolaHeadVisuals, entitiesToIgnore); + Pointers.setIgnoreItems(this.teleportParabolaHeadCollisions, entitiesToIgnore); + Picks.setIgnoreItems(_this.teleportHeadCollisionPick, entitiesToIgnore); + Picks.setIgnoreItems(_this.teleportHandCollisionPick, entitiesToIgnore); }; } @@ -470,6 +480,25 @@ Script.include("/~/system/libraries/controllers.js"); // than MAX_ANGLE_FROM_UP_TO_TELEPORT degrees from your avatar's up, then // you can't teleport there. var MAX_ANGLE_FROM_UP_TO_TELEPORT = 70; + var MAX_DISCREPANCY_DISTANCE = 1.0; + var MAX_DOT_SIGN = -0.6; + + function checkForMeshDiscrepancy(result, collisionResult) { + var intersectingObjects = collisionResult.intersectingObjects; + if (intersectingObjects.length > 0) { + var intersectingObject = collisionResult.intersectingObjects[0]; + for (var i = 0; i < intersectingObject.collisionContacts.length; i++) { + var normal = intersectingObject.collisionContacts[i].normalOnPick; + var distanceToPick = Vec3.distance(intersectingObject.collisionContacts[i].pointOnPick, result.intersection); + var normalSign = Vec3.dot(normal, Quat.getUp(MyAvatar.orientation)); + if ((distanceToPick > MAX_DISCREPANCY_DISTANCE) || (normalSign > MAX_DOT_SIGN)) { + return false; + } + } + return true; + } + return false; + } function getTeleportTargetType(result, collisionResult) { if (result.type === Picks.INTERSECTED_NONE) { @@ -489,7 +518,9 @@ Script.include("/~/system/libraries/controllers.js"); if (collisionResult.collisionRegion != undefined) { if (collisionResult.intersects) { - return TARGET.COLLIDES; + if (!checkForMeshDiscrepancy(result, collisionResult)) { + return TARGET.COLLIDES; + } } } From ceccc6d6ec763425f284249a07dab4b00c7e9651 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 13 Sep 2018 14:49:35 -0700 Subject: [PATCH 14/19] make getCollisionCapsule thread safe --- interface/src/avatar/MyAvatar.cpp | 13 ++++++++++--- interface/src/avatar/MyAvatar.h | 7 ++++++- libraries/avatars/src/AvatarData.h | 2 ++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9a78f394e1..dc29f34bd8 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -149,7 +149,8 @@ MyAvatar::MyAvatar(QThread* thread) : }); connect(_skeletonModel.get(), &Model::rigReady, this, &Avatar::rigReady); connect(_skeletonModel.get(), &Model::rigReset, this, &Avatar::rigReset); - + connect(&_skeletonModel->getRig(), &Rig::onLoadComplete, this, &MyAvatar::updateCollisionCapsule); + connect(this, &MyAvatar::sensorToWorldScaleChanged, this, &MyAvatar::updateCollisionCapsule); using namespace recording; _skeletonModel->flagAsCauterized(); @@ -255,6 +256,7 @@ MyAvatar::MyAvatar(QThread* thread) : }); connect(&(_skeletonModel->getRig()), SIGNAL(onLoadComplete()), this, SIGNAL(onLoadComplete())); + _characterController.setDensity(_density); } @@ -3307,7 +3309,7 @@ bool MyAvatar::getCollisionsEnabled() { return _characterController.computeCollisionGroup() != BULLET_COLLISION_GROUP_COLLISIONLESS; } -QVariantMap MyAvatar::getCollisionCapsule() { +void MyAvatar::updateCollisionCapsule() { glm::vec3 start, end; float radius; getCapsule(start, end, radius); @@ -3315,7 +3317,12 @@ QVariantMap MyAvatar::getCollisionCapsule() { capsule["start"] = vec3toVariant(start); capsule["end"] = vec3toVariant(end); capsule["radius"] = QVariant(radius); - return capsule; + _capsuleShape.set(capsule); +} + +// thread safe +QVariantMap MyAvatar::getCollisionCapsule() const { + return _capsuleShape.get(); } void MyAvatar::setCharacterControllerEnabled(bool enabled) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 7ba17328c0..9786b7a639 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1021,7 +1021,7 @@ public: * @function MyAvatar.getCollisionCapsule * @returns {object} */ - Q_INVOKABLE QVariantMap getCollisionCapsule(); + Q_INVOKABLE QVariantMap getCollisionCapsule() const; /**jsdoc * @function MyAvatar.setCharacterControllerEnabled @@ -1373,6 +1373,11 @@ public slots: */ virtual void setModelScale(float scale) override; + /**jsdoc + * @function MyAvatar.updateCollisionCapsule + */ + void updateCollisionCapsule(); + signals: /**jsdoc diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index e9f1f5f6c3..8ebaa695fa 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -1444,6 +1444,8 @@ protected: ThreadSafeValueCache _farGrabLeftMatrixCache { glm::mat4() }; ThreadSafeValueCache _farGrabMouseMatrixCache { glm::mat4() }; + ThreadSafeValueCache _capsuleShape { QVariantMap() }; + int getFauxJointIndex(const QString& name) const; float _audioLoudness { 0.0f }; From 6a9a898b62c547c391c2f9146807bce48d465601 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 13 Sep 2018 15:07:34 -0700 Subject: [PATCH 15/19] make updateCollisionCapsule private --- interface/src/avatar/MyAvatar.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 9786b7a639..ebc1dab704 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1373,11 +1373,6 @@ public slots: */ virtual void setModelScale(float scale) override; - /**jsdoc - * @function MyAvatar.updateCollisionCapsule - */ - void updateCollisionCapsule(); - signals: /**jsdoc @@ -1510,6 +1505,7 @@ signals: private slots: void leaveDomain(); + void updateCollisionCapsule(); protected: virtual void beParentOfChild(SpatiallyNestablePointer newChild) const override; From c5669ef1f58bb4a147afa1d356807992c4a5470d Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 13 Sep 2018 15:22:18 -0700 Subject: [PATCH 16/19] better property names --- interface/src/avatar/MyAvatar.cpp | 10 +++++----- interface/src/avatar/MyAvatar.h | 2 +- libraries/avatars/src/AvatarData.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index dc29f34bd8..c47cfdb383 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -149,8 +149,8 @@ MyAvatar::MyAvatar(QThread* thread) : }); connect(_skeletonModel.get(), &Model::rigReady, this, &Avatar::rigReady); connect(_skeletonModel.get(), &Model::rigReset, this, &Avatar::rigReset); - connect(&_skeletonModel->getRig(), &Rig::onLoadComplete, this, &MyAvatar::updateCollisionCapsule); - connect(this, &MyAvatar::sensorToWorldScaleChanged, this, &MyAvatar::updateCollisionCapsule); + connect(&_skeletonModel->getRig(), &Rig::onLoadComplete, this, &MyAvatar::updateCollisionCapsuleCache); + connect(this, &MyAvatar::sensorToWorldScaleChanged, this, &MyAvatar::updateCollisionCapsuleCache); using namespace recording; _skeletonModel->flagAsCauterized(); @@ -3309,7 +3309,7 @@ bool MyAvatar::getCollisionsEnabled() { return _characterController.computeCollisionGroup() != BULLET_COLLISION_GROUP_COLLISIONLESS; } -void MyAvatar::updateCollisionCapsule() { +void MyAvatar::updateCollisionCapsuleCache() { glm::vec3 start, end; float radius; getCapsule(start, end, radius); @@ -3317,12 +3317,12 @@ void MyAvatar::updateCollisionCapsule() { capsule["start"] = vec3toVariant(start); capsule["end"] = vec3toVariant(end); capsule["radius"] = QVariant(radius); - _capsuleShape.set(capsule); + _collisionCapsuleCache.set(capsule); } // thread safe QVariantMap MyAvatar::getCollisionCapsule() const { - return _capsuleShape.get(); + return _collisionCapsuleCache.get(); } void MyAvatar::setCharacterControllerEnabled(bool enabled) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index ebc1dab704..139f1f6ea2 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1505,7 +1505,7 @@ signals: private slots: void leaveDomain(); - void updateCollisionCapsule(); + void updateCollisionCapsuleCache(); protected: virtual void beParentOfChild(SpatiallyNestablePointer newChild) const override; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 8ebaa695fa..b10fdf01cd 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -1444,7 +1444,7 @@ protected: ThreadSafeValueCache _farGrabLeftMatrixCache { glm::mat4() }; ThreadSafeValueCache _farGrabMouseMatrixCache { glm::mat4() }; - ThreadSafeValueCache _capsuleShape { QVariantMap() }; + ThreadSafeValueCache _collisionCapsuleCache{ QVariantMap() }; int getFauxJointIndex(const QString& name) const; From fb37e13aaeae87db8a317d757a1bc5334039f289 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 13 Sep 2018 18:21:22 -0700 Subject: [PATCH 17/19] fix hat stand fail --- .../controllers/controllerModules/teleport.js | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index 707bde7b4f..10c3e93727 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -166,7 +166,7 @@ Script.include("/~/system/libraries/controllers.js"); joint: (_this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", dirOffset: { x: 0, y: 1, z: 0.1 }, posOffset: { x: (_this.hand === RIGHT_HAND) ? 0.03 : -0.03, y: 0.2, z: 0.02 }, - filter: Picks.PICK_ENTITIES + Picks.PICK_INCLUDE_INVISIBLE, + filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, faceAvatar: true, scaleWithAvatar: true, centerEndY: false, @@ -195,7 +195,7 @@ Script.include("/~/system/libraries/controllers.js"); _this.teleportParabolaHeadVisuals = Pointers.createPointer(PickType.Parabola, { joint: "Avatar", - filter: Picks.PICK_ENTITIES + Picks.PICK_INCLUDE_INVISIBLE, + filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, faceAvatar: true, scaleWithAvatar: true, centerEndY: false, @@ -485,14 +485,16 @@ Script.include("/~/system/libraries/controllers.js"); function checkForMeshDiscrepancy(result, collisionResult) { var intersectingObjects = collisionResult.intersectingObjects; - if (intersectingObjects.length > 0) { - var intersectingObject = collisionResult.intersectingObjects[0]; - for (var i = 0; i < intersectingObject.collisionContacts.length; i++) { - var normal = intersectingObject.collisionContacts[i].normalOnPick; - var distanceToPick = Vec3.distance(intersectingObject.collisionContacts[i].pointOnPick, result.intersection); - var normalSign = Vec3.dot(normal, Quat.getUp(MyAvatar.orientation)); - if ((distanceToPick > MAX_DISCREPANCY_DISTANCE) || (normalSign > MAX_DOT_SIGN)) { - return false; + if (intersectingObjects.length > 0 && intersectingObjects.length < 3) { + for (var j = 0; j < collisionResult.intersectingObjects.length; j++) { + var intersectingObject = collisionResult.intersectingObjects[j]; + for (var i = 0; i < intersectingObject.collisionContacts.length; i++) { + var normal = intersectingObject.collisionContacts[i].normalOnPick; + var distanceToPick = Vec3.distance(intersectingObject.collisionContacts[i].pointOnPick, result.intersection); + var normalSign = Vec3.dot(normal, Quat.getUp(MyAvatar.orientation)); + if ((distanceToPick > MAX_DISCREPANCY_DISTANCE) || (normalSign > MAX_DOT_SIGN)) { + return false; + } } } return true; From 8c9173b639599c5ae5b3c819ec16c70865f0b3bc Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 14 Sep 2018 11:06:30 -0700 Subject: [PATCH 18/19] Safe landing for discrepancies --- .../controllers/controllerModules/teleport.js | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index 10c3e93727..ea60220c9c 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -117,6 +117,7 @@ Script.include("/~/system/libraries/controllers.js"); NONE: 'none', // Not currently targetting anything INVALID: 'invalid', // The current target is invalid (wall, ceiling, etc.) COLLIDES: 'collides', // Insufficient space to accommodate the avatar capsule + DISCREPANCY: 'discrepancy', // We are not 100% sure the avatar will fit so we trigger safe landing SURFACE: 'surface', // The current target is a valid surface SEAT: 'seat' // The current target is a seat }; @@ -135,7 +136,7 @@ Script.include("/~/system/libraries/controllers.js"); this.currentTarget = TARGET.INVALID; this.currentResult = null; this.capsuleThreshold = 0.05; - this.pickHeightOffset = 0.05; + this.pickHeightOffset = 0.15; this.getOtherModule = function() { var otherModule = this.hand === RIGHT_HAND ? leftTeleporter : rightTeleporter; @@ -376,7 +377,7 @@ Script.include("/~/system/libraries/controllers.js"); this.setTeleportState(mode, "", "cancel"); } else if (teleportLocationType === TARGET.COLLIDES) { this.setTeleportState(mode, "cancel", "collision"); - } else if (teleportLocationType === TARGET.SURFACE) { + } else if (teleportLocationType === TARGET.SURFACE || teleportLocationType === TARGET.DISCREPANCY) { this.setTeleportState(mode, "teleport", "collision"); } else if (teleportLocationType === TARGET.SEAT) { this.setTeleportState(mode, "collision", "seat"); @@ -394,10 +395,11 @@ Script.include("/~/system/libraries/controllers.js"); // Do nothing } else if (target === TARGET.SEAT) { Entities.callEntityMethod(result.objectID, 'sit'); - } else if (target === TARGET.SURFACE) { + } else if (target === TARGET.SURFACE || target === TARGET.DISCREPANCY) { var offset = getAvatarFootOffset(); result.intersection.y += offset; - MyAvatar.goToLocation(result.intersection, true, HMD.orientation, false, false); + var shouldLandSafe = target === TARGET.DISCREPANCY; + MyAvatar.goToLocation(result.intersection, true, HMD.orientation, false, shouldLandSafe); HMD.centerUI(); MyAvatar.centerBody(); } @@ -517,12 +519,13 @@ Script.include("/~/system/libraries/controllers.js"); return TARGET.INVALID; } } - + var isDiscrepancy = false; if (collisionResult.collisionRegion != undefined) { if (collisionResult.intersects) { - if (!checkForMeshDiscrepancy(result, collisionResult)) { + isDiscrepancy = checkForMeshDiscrepancy(result, collisionResult); + if (!isDiscrepancy) { return TARGET.COLLIDES; - } + } } } @@ -531,6 +534,8 @@ Script.include("/~/system/libraries/controllers.js"); if (angle > MAX_ANGLE_FROM_UP_TO_TELEPORT) { return TARGET.INVALID; + } else if (isDiscrepancy) { + return TARGET.DISCREPANCY; } else { return TARGET.SURFACE; } From 04e6225a956e15aeddb311cf9983824f30ae20a3 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 14 Sep 2018 11:22:47 -0700 Subject: [PATCH 19/19] Threshold back --- scripts/system/controllers/controllerModules/teleport.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index ea60220c9c..deaa934f99 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -136,7 +136,7 @@ Script.include("/~/system/libraries/controllers.js"); this.currentTarget = TARGET.INVALID; this.currentResult = null; this.capsuleThreshold = 0.05; - this.pickHeightOffset = 0.15; + this.pickHeightOffset = 0.05; this.getOtherModule = function() { var otherModule = this.hand === RIGHT_HAND ? leftTeleporter : rightTeleporter;