From 106b0ad8bb7e1118d6abd2f0f7aa747588fedc3e Mon Sep 17 00:00:00 2001 From: seefo Date: Mon, 31 Jul 2017 14:37:40 -0700 Subject: [PATCH 1/6] Added Vive pucks as an input channel --- interface/resources/controllers/standard.json | 19 ++++++++++++++++++- interface/resources/controllers/vive.json | 19 ++++++++++++++++++- .../controllers/src/controllers/Actions.cpp | 17 +++++++++++++++++ .../controllers/src/controllers/Actions.h | 17 +++++++++++++++++ .../src/controllers/StandardController.cpp | 17 +++++++++++++++++ scripts/developer/tests/puck-attach.js | 6 +++--- scripts/developer/tests/viveTrackedObjects.js | 2 +- 7 files changed, 91 insertions(+), 6 deletions(-) diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json index 166f1a6869..0d5c095585 100644 --- a/interface/resources/controllers/standard.json +++ b/interface/resources/controllers/standard.json @@ -109,6 +109,23 @@ { "from": "Standard.Head", "to": "Actions.Head" }, { "from": "Standard.LeftArm", "to": "Actions.LeftArm" }, - { "from": "Standard.RightArm", "to": "Actions.RightArm" } + { "from": "Standard.RightArm", "to": "Actions.RightArm" }, + + { "from": "Standard.TrackedObject00", "to" : "Actions.TrackedObject00" }, + { "from": "Standard.TrackedObject01", "to" : "Actions.TrackedObject01" }, + { "from": "Standard.TrackedObject02", "to" : "Actions.TrackedObject02" }, + { "from": "Standard.TrackedObject03", "to" : "Actions.TrackedObject03" }, + { "from": "Standard.TrackedObject04", "to" : "Actions.TrackedObject04" }, + { "from": "Standard.TrackedObject05", "to" : "Actions.TrackedObject05" }, + { "from": "Standard.TrackedObject06", "to" : "Actions.TrackedObject06" }, + { "from": "Standard.TrackedObject07", "to" : "Actions.TrackedObject07" }, + { "from": "Standard.TrackedObject08", "to" : "Actions.TrackedObject08" }, + { "from": "Standard.TrackedObject09", "to" : "Actions.TrackedObject09" }, + { "from": "Standard.TrackedObject10", "to" : "Actions.TrackedObject10" }, + { "from": "Standard.TrackedObject11", "to" : "Actions.TrackedObject11" }, + { "from": "Standard.TrackedObject12", "to" : "Actions.TrackedObject12" }, + { "from": "Standard.TrackedObject13", "to" : "Actions.TrackedObject13" }, + { "from": "Standard.TrackedObject14", "to" : "Actions.TrackedObject14" }, + { "from": "Standard.TrackedObject15", "to" : "Actions.TrackedObject15" } ] } diff --git a/interface/resources/controllers/vive.json b/interface/resources/controllers/vive.json index 73ab5cb2ae..02fc09c815 100644 --- a/interface/resources/controllers/vive.json +++ b/interface/resources/controllers/vive.json @@ -77,6 +77,23 @@ { "from": "Vive.Head", "to" : "Standard.Head"}, { "from": "Vive.RightArm", "to" : "Standard.RightArm" }, - { "from": "Vive.LeftArm", "to" : "Standard.LeftArm" } + { "from": "Vive.LeftArm", "to" : "Standard.LeftArm" }, + + { "from": "Vive.TrackedObject00", "to" : "Standard.TrackedObject00" }, + { "from": "Vive.TrackedObject01", "to" : "Standard.TrackedObject01" }, + { "from": "Vive.TrackedObject02", "to" : "Standard.TrackedObject02" }, + { "from": "Vive.TrackedObject03", "to" : "Standard.TrackedObject03" }, + { "from": "Vive.TrackedObject04", "to" : "Standard.TrackedObject04" }, + { "from": "Vive.TrackedObject05", "to" : "Standard.TrackedObject05" }, + { "from": "Vive.TrackedObject06", "to" : "Standard.TrackedObject06" }, + { "from": "Vive.TrackedObject07", "to" : "Standard.TrackedObject07" }, + { "from": "Vive.TrackedObject08", "to" : "Standard.TrackedObject08" }, + { "from": "Vive.TrackedObject09", "to" : "Standard.TrackedObject09" }, + { "from": "Vive.TrackedObject10", "to" : "Standard.TrackedObject10" }, + { "from": "Vive.TrackedObject11", "to" : "Standard.TrackedObject11" }, + { "from": "Vive.TrackedObject12", "to" : "Standard.TrackedObject12" }, + { "from": "Vive.TrackedObject13", "to" : "Standard.TrackedObject13" }, + { "from": "Vive.TrackedObject14", "to" : "Standard.TrackedObject14" }, + { "from": "Vive.TrackedObject15", "to" : "Standard.TrackedObject15" } ] } diff --git a/libraries/controllers/src/controllers/Actions.cpp b/libraries/controllers/src/controllers/Actions.cpp index b3c0ed3f05..d8dd7f5e35 100644 --- a/libraries/controllers/src/controllers/Actions.cpp +++ b/libraries/controllers/src/controllers/Actions.cpp @@ -101,6 +101,23 @@ namespace controller { makePosePair(Action::RIGHT_HAND_PINKY3, "RightHandPinky3"), makePosePair(Action::RIGHT_HAND_PINKY4, "RightHandPinky4"), + makePosePair(Action::TRACKED_OBJECT_00, "TrackedObject00"), + makePosePair(Action::TRACKED_OBJECT_01, "TrackedObject01"), + makePosePair(Action::TRACKED_OBJECT_02, "TrackedObject02"), + makePosePair(Action::TRACKED_OBJECT_03, "TrackedObject03"), + makePosePair(Action::TRACKED_OBJECT_04, "TrackedObject04"), + makePosePair(Action::TRACKED_OBJECT_05, "TrackedObject05"), + makePosePair(Action::TRACKED_OBJECT_06, "TrackedObject06"), + makePosePair(Action::TRACKED_OBJECT_07, "TrackedObject07"), + makePosePair(Action::TRACKED_OBJECT_08, "TrackedObject08"), + makePosePair(Action::TRACKED_OBJECT_09, "TrackedObject09"), + makePosePair(Action::TRACKED_OBJECT_10, "TrackedObject10"), + makePosePair(Action::TRACKED_OBJECT_11, "TrackedObject11"), + makePosePair(Action::TRACKED_OBJECT_12, "TrackedObject12"), + makePosePair(Action::TRACKED_OBJECT_13, "TrackedObject13"), + makePosePair(Action::TRACKED_OBJECT_14, "TrackedObject14"), + makePosePair(Action::TRACKED_OBJECT_15, "TrackedObject15"), + makeButtonPair(Action::LEFT_HAND_CLICK, "LeftHandClick"), makeButtonPair(Action::RIGHT_HAND_CLICK, "RightHandClick"), diff --git a/libraries/controllers/src/controllers/Actions.h b/libraries/controllers/src/controllers/Actions.h index ec4800c9aa..6319b5746e 100644 --- a/libraries/controllers/src/controllers/Actions.h +++ b/libraries/controllers/src/controllers/Actions.h @@ -146,6 +146,23 @@ enum class Action { RIGHT_HAND_PINKY3, RIGHT_HAND_PINKY4, + TRACKED_OBJECT_00, + TRACKED_OBJECT_01, + TRACKED_OBJECT_02, + TRACKED_OBJECT_03, + TRACKED_OBJECT_04, + TRACKED_OBJECT_05, + TRACKED_OBJECT_06, + TRACKED_OBJECT_07, + TRACKED_OBJECT_08, + TRACKED_OBJECT_09, + TRACKED_OBJECT_10, + TRACKED_OBJECT_11, + TRACKED_OBJECT_12, + TRACKED_OBJECT_13, + TRACKED_OBJECT_14, + TRACKED_OBJECT_15, + NUM_ACTIONS, }; diff --git a/libraries/controllers/src/controllers/StandardController.cpp b/libraries/controllers/src/controllers/StandardController.cpp index 40b87bc6b2..ed729867df 100644 --- a/libraries/controllers/src/controllers/StandardController.cpp +++ b/libraries/controllers/src/controllers/StandardController.cpp @@ -166,6 +166,23 @@ Input::NamedVector StandardController::getAvailableInputs() const { makePair(DD, "Down"), makePair(DL, "Left"), makePair(DR, "Right"), + + makePair(TRACKED_OBJECT_00, "TrackedObject00"), + makePair(TRACKED_OBJECT_01, "TrackedObject01"), + makePair(TRACKED_OBJECT_02, "TrackedObject02"), + makePair(TRACKED_OBJECT_03, "TrackedObject03"), + makePair(TRACKED_OBJECT_04, "TrackedObject04"), + makePair(TRACKED_OBJECT_05, "TrackedObject05"), + makePair(TRACKED_OBJECT_06, "TrackedObject06"), + makePair(TRACKED_OBJECT_07, "TrackedObject07"), + makePair(TRACKED_OBJECT_08, "TrackedObject08"), + makePair(TRACKED_OBJECT_09, "TrackedObject09"), + makePair(TRACKED_OBJECT_10, "TrackedObject10"), + makePair(TRACKED_OBJECT_11, "TrackedObject11"), + makePair(TRACKED_OBJECT_12, "TrackedObject12"), + makePair(TRACKED_OBJECT_13, "TrackedObject13"), + makePair(TRACKED_OBJECT_14, "TrackedObject14"), + makePair(TRACKED_OBJECT_15, "TrackedObject15") }; return availableInputs; } diff --git a/scripts/developer/tests/puck-attach.js b/scripts/developer/tests/puck-attach.js index 2d0a2e6d02..dd94f81a99 100644 --- a/scripts/developer/tests/puck-attach.js +++ b/scripts/developer/tests/puck-attach.js @@ -84,7 +84,7 @@ function getAvailableTrackedObjects() { var i; for (i = 0; i < NUM_TRACKED_OBJECTS; i++) { var key = indexToTrackedObjectName(i); - var pose = Controller.getPoseValue(Controller.Hardware.Vive[key]); + var pose = Controller.getPoseValue(Controller.Standard[key]); if (pose && pose.valid) { available.push(i); } @@ -126,8 +126,8 @@ function pad(num, size) { } function update() { - if (attachedEntity && attachedObj && Controller.Hardware.Vive) { - var pose = Controller.getPoseValue(Controller.Hardware.Vive[attachedObj.key]); + if (attachedEntity && attachedObj && Controller.Standard) { + var pose = Controller.getPoseValue(Controller.Standard[attachedObj.key]); var avatarXform = new Xform(MyAvatar.orientation, MyAvatar.position); var puckXform = new Xform(pose.rotation, pose.translation); var finalXform = Xform.mul(avatarXform, Xform.mul(puckXform, attachedObj.localXform)); diff --git a/scripts/developer/tests/viveTrackedObjects.js b/scripts/developer/tests/viveTrackedObjects.js index 4155afb82b..1d60f658d9 100644 --- a/scripts/developer/tests/viveTrackedObjects.js +++ b/scripts/developer/tests/viveTrackedObjects.js @@ -23,7 +23,7 @@ var BLUE = {x: 0, y: 0, z: 1, w: 1}; function update(dt) { if (Controller.Hardware.Vive) { TRACKED_OBJECT_POSES.forEach(function (key) { - var pose = Controller.getPoseValue(Controller.Hardware.Vive[key]); + var pose = Controller.getPoseValue(Controller.Standard[key]); if (pose.valid) { DebugDraw.addMyAvatarMarker(key, pose.rotation, pose.translation, BLUE); } else { From 620f1a65c0f4cfe1519e008749a9a18c4c6d32c0 Mon Sep 17 00:00:00 2001 From: seefo Date: Wed, 2 Aug 2017 12:29:30 -0700 Subject: [PATCH 2/6] New puck-attach script --- scripts/developer/tests/puck-attach.js | 205 +++++++++++++++---------- 1 file changed, 121 insertions(+), 84 deletions(-) diff --git a/scripts/developer/tests/puck-attach.js b/scripts/developer/tests/puck-attach.js index dd94f81a99..25aeee54eb 100644 --- a/scripts/developer/tests/puck-attach.js +++ b/scripts/developer/tests/puck-attach.js @@ -1,21 +1,13 @@ // // Created by Anthony J. Thibault on 2017/06/20 +// Modified by Robbie Uvanni to support multiple pucks and easier placement of pucks on entities, on 2017/08/01 // Copyright 2017 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // // When this script is running, a new app button, named "PUCKTACH", will be added to the toolbar/tablet. -// Click this app to bring up the puck attachment panel. This panel contains the following fields. -// -// * Tracked Object - A drop down list of all the available pucks found. If no pucks are found this list will only have a single NONE entry. -// Closing and re-opening the app will refresh this list. -// * Model URL - A model url of the model you wish to be attached to the specified puck. -// * Position X, Y, Z - used to apply an offset between the puck and the attached model. -// * Rot X, Y, Z - used to apply euler angle offsets, in degrees, between the puck and the attached model. -// * Create Attachment - when this button is pressed a new Entity will be created at the specified puck's location. -// If a puck atttachment already exists, it will be destroyed before the new entity is created. -// * Destroy Attachmetn - destroies the entity attached to the puck. +// Click this app to bring up the puck attachment panel. // /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ @@ -25,7 +17,7 @@ Script.include("/~/system/libraries/Xform.js"); (function() { // BEGIN LOCAL_SCOPE var TABLET_BUTTON_NAME = "PUCKTACH"; -var HTML_URL = "https://s3.amazonaws.com/hifi-public/tony/html/puck-attach.html"; +var TABLET_APP_URL = "http://content.highfidelity.com/seefo/production/puck-attach/puck-attach.html"; var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var tabletButton = tablet.addButton({ @@ -34,20 +26,9 @@ var tabletButton = tablet.addButton({ activeIcon: "https://s3.amazonaws.com/hifi-public/tony/icons/puck-a.svg" }); -tabletButton.clicked.connect(function () { - if (shown) { - tablet.gotoHomeScreen(); - } else { - tablet.gotoWebScreen(HTML_URL); - } -}); - var shown = false; -var attachedEntity; -var attachedObj; - function onScreenChanged(type, url) { - if (type === "Web" && url === HTML_URL) { + if (type === "Web" && url === TABLET_APP_URL) { tabletButton.editProperties({isActive: true}); if (!shown) { // hook up to event bridge @@ -57,9 +38,7 @@ function onScreenChanged(type, url) { // send available tracked objects to the html running in the tablet. var availableTrackedObjects = getAvailableTrackedObjects(); tablet.emitScriptEvent(JSON.stringify(availableTrackedObjects)); - - // print("PUCK-ATTACH: availableTrackedObjects = " + JSON.stringify(availableTrackedObjects)); - }, 1000); // wait 1 sec before sending.. + }, 1000); // wait 1 sec before sending.. } shown = true; } else { @@ -71,13 +50,15 @@ function onScreenChanged(type, url) { shown = false; } } - tablet.screenChanged.connect(onScreenChanged); +function pad(num, size) { + var tempString = "000000000" + num; + return tempString.substr(tempString.length - size); +} function indexToTrackedObjectName(index) { return "TrackedObject" + pad(index, 2); } - function getAvailableTrackedObjects() { var available = []; var NUM_TRACKED_OBJECTS = 16; @@ -92,83 +73,139 @@ function getAvailableTrackedObjects() { return available; } -function attach(obj) { - attachedEntity = Entities.addEntity({ - type: "Model", - name: "puck-attach-entity", - modelURL: obj.modelurl - }); - attachedObj = obj; - var localPos = {x: Number(obj.posx), y: Number(obj.posy), z: Number(obj.posz)}; - var localRot = Quat.fromVec3Degrees({x: Number(obj.rotx), y: Number(obj.roty), z: Number(obj.rotz)}); - attachedObj.localXform = new Xform(localRot, localPos); - var key = indexToTrackedObjectName(Number(attachedObj.puckno)); - attachedObj.key = key; - - // print("PUCK-ATTACH: attachedObj = " + JSON.stringify(attachedObj)); - - Script.update.connect(update); - update(); +function getRelativePosition(origin, rotation, offset) { + var relativeOffset = Vec3.multiplyQbyV(rotation, offset); + var worldPosition = Vec3.sum(origin, relativeOffset); + return worldPosition; +} +function getPropertyForEntity(entityID, propertyName) { + return Entities.getEntityProperties(entityID, [propertyName])[propertyName]; } -function remove() { - if (attachedEntity) { - Script.update.disconnect(update); - Entities.deleteEntity(attachedEntity); - attachedEntity = undefined; - } - attachedObj = undefined; -} +var VIVE_PUCK_MODEL = "http://content.highfidelity.com/seefo/production/puck-attach/vive_tracker_puck.obj"; +var VIVE_PUCK_SEARCH_DISTANCE = 1.5; // metres +var VIVE_PUCK_NAME = "Tracked Puck"; -function pad(num, size) { - var tempString = "000000000" + num; - return tempString.substr(tempString.length - size); -} +var trackedPucks = { }; +var lastPuck = { }; -function update() { - if (attachedEntity && attachedObj && Controller.Standard) { - var pose = Controller.getPoseValue(Controller.Standard[attachedObj.key]); - var avatarXform = new Xform(MyAvatar.orientation, MyAvatar.position); - var puckXform = new Xform(pose.rotation, pose.translation); - var finalXform = Xform.mul(avatarXform, Xform.mul(puckXform, attachedObj.localXform)); - if (pose && pose.valid) { - Entities.editEntity(attachedEntity, { - position: finalXform.pos, - rotation: finalXform.rot - }); - } else { - if (pose) { - print("PUCK-ATTACH: WARNING: invalid pose for " + attachedObj.key); - } else { - print("PUCK-ATTACH: WARNING: could not find key " + attachedObj.key); +function createPuck(puck) { + // create a puck entity and add it to our list of pucks + var spawnOffset = Vec3.multiply(Vec3.FRONT, 1.0); + var spawnPosition = getRelativePosition(MyAvatar.position, MyAvatar.orientation, spawnOffset); + + // should be an overlay + var puckEntityProperties = { + "name": "Tracked Puck", + "type": "Model", + "modelURL": VIVE_PUCK_MODEL, + "dimensions": { x: 0.0945, y: 0.0921, z: 0.0423 }, + "position": spawnPosition, + "userData": "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }" + }; + + var puckEntityID = Entities.addEntity(puckEntityProperties); + trackedPucks[puck.puckno] = { + "puckEntityID": puckEntityID, + "trackedEntityID": "" + }; + lastPuck = trackedPucks[puck.puckno]; +} +function finalizePuck() { + // find nearest entity and change its parent to the puck + var puckPosition = getPropertyForEntity(lastPuck.puckEntityID, "position"); + var foundEntities = Entities.findEntities(puckPosition, VIVE_PUCK_SEARCH_DISTANCE); + + var foundEntity; + var leastDistance = 999999; // this should be something like Integer.MAX_VALUE + + for (var i = 0; i < foundEntities.length; i++) { + var entity = foundEntities[i]; + + if (getPropertyForEntity(entity, "name") !== VIVE_PUCK_NAME) { + var entityPosition = getPropertyForEntity(entity, "position"); + var d = Vec3.distance(entityPosition, puckPosition); + + if (d < leastDistance) { + leastDistance = d; + foundEntity = entity; } } } + + if (foundEntity) { + lastPuck.trackedEntityID = foundEntity; + Entities.editEntity(lastPuck.trackedEntityID, { "parentID": lastPuck.puckEntityID }); + } +} +function updatePucks() { + // for each puck, update its position and orientation + for (var puck in trackedPucks) { + var action = indexToTrackedObjectName(puck); + var pose = Controller.getPoseValue(Controller.Standard[action]); + if (pose && pose.valid) { + if (trackedPucks[puck].trackedEntityID) { + var avatarXform = new Xform(MyAvatar.orientation, MyAvatar.position); + var puckXform = new Xform(pose.rotation, pose.translation); + var finalXform = Xform.mul(avatarXform, Xform.mul(puckXform, Vec3.ZERO)); + + Entities.editEntity(trackedPucks[puck].puckEntityID, { + position: finalXform.pos, + rotation: finalXform.rot + }); + } + } + } +} +function destroyPuck(puckName) { + // unparent entity and delete its parent + var puckEntityID = trackedPucks[puckName].puckEntityID; + var trackedEntityID = trackedPucks[puckName].trackedEntityID; + + Entities.editEntity(trackedEntityID, { "parentID": "{00000000-0000-0000-0000-000000000000}" }); + Entities.deleteEntity(puckEntityID); +} +function destroyPucks() { + // remove all pucks and unparent entities + for (var puck in trackedPucks) { + destroyPuck(puck); + } } function onWebEventReceived(msg) { var obj = {}; - try { + + try { obj = JSON.parse(msg); - } catch (err) { - return; + } catch (err) { + return; } - if (obj.cmd === "attach") { - remove(); - attach(obj); - } else if (obj.cmd === "detach") { - remove(); + + switch (obj.cmd) { + case "create": + createPuck(obj); + break; + case "finalize": + finalizePuck(); + break; } } +Script.update.connect(updatePucks); Script.scriptEnding.connect(function () { - remove(); tablet.removeButton(tabletButton); + destroyPucks(); if (shown) { tablet.webEventReceived.disconnect(onWebEventReceived); tablet.gotoHomeScreen(); } tablet.screenChanged.disconnect(onScreenChanged); }); - -}()); // END LOCAL_SCOPE +tabletButton.clicked.connect(function () { + if (shown) { + tablet.gotoHomeScreen(); + } else { + tablet.gotoWebScreen(TABLET_APP_URL); + } +}); +}()); // END LOCAL_SCOPE \ No newline at end of file From 961f748d8761332ba2939937b70cd6cac91d500b Mon Sep 17 00:00:00 2001 From: seefo Date: Wed, 2 Aug 2017 13:08:24 -0700 Subject: [PATCH 3/6] Fixed a potential bug with puck-attach parenting --- scripts/developer/tests/puck-attach.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/scripts/developer/tests/puck-attach.js b/scripts/developer/tests/puck-attach.js index 25aeee54eb..3a5d8736f8 100644 --- a/scripts/developer/tests/puck-attach.js +++ b/scripts/developer/tests/puck-attach.js @@ -140,18 +140,25 @@ function finalizePuck() { } function updatePucks() { // for each puck, update its position and orientation - for (var puck in trackedPucks) { - var action = indexToTrackedObjectName(puck); + for (var puckName in trackedPucks) { + var action = indexToTrackedObjectName(puckName); var pose = Controller.getPoseValue(Controller.Standard[action]); if (pose && pose.valid) { - if (trackedPucks[puck].trackedEntityID) { + var puck = trackedPucks[puckName]; + if (puck.trackedEntityID) { var avatarXform = new Xform(MyAvatar.orientation, MyAvatar.position); var puckXform = new Xform(pose.rotation, pose.translation); var finalXform = Xform.mul(avatarXform, Xform.mul(puckXform, Vec3.ZERO)); - Entities.editEntity(trackedPucks[puck].puckEntityID, { + Entities.editEntity(puck.puckEntityID, { position: finalXform.pos, - rotation: finalXform.rot + rotation: finalXform.rot, + }); + + // in case someone grabbed both entities and destroyed the + // child/parent relationship + Entities.editEntity(puck.trackedEntityID, { + parentID: puck.puckEntityID }); } } From 82654c7cda887b19bc673ecb51f9c07bcb8652e1 Mon Sep 17 00:00:00 2001 From: seefo Date: Wed, 2 Aug 2017 15:28:26 -0700 Subject: [PATCH 4/6] Made requested changed to puck-attach.js --- scripts/developer/tests/puck-attach.js | 39 +++++++++++++++++--------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/scripts/developer/tests/puck-attach.js b/scripts/developer/tests/puck-attach.js index 3a5d8736f8..65adf35d00 100644 --- a/scripts/developer/tests/puck-attach.js +++ b/scripts/developer/tests/puck-attach.js @@ -83,7 +83,9 @@ function getPropertyForEntity(entityID, propertyName) { } var VIVE_PUCK_MODEL = "http://content.highfidelity.com/seefo/production/puck-attach/vive_tracker_puck.obj"; +var VIVE_PUCK_DIMENSIONS = { x: 0.0945, y: 0.0921, z: 0.0423 }; // 1/1000th scale of model var VIVE_PUCK_SEARCH_DISTANCE = 1.5; // metres +var VIVE_PUCK_SPAWN_DISTANCE = 1.0; // metres var VIVE_PUCK_NAME = "Tracked Puck"; var trackedPucks = { }; @@ -91,23 +93,28 @@ var lastPuck = { }; function createPuck(puck) { // create a puck entity and add it to our list of pucks - var spawnOffset = Vec3.multiply(Vec3.FRONT, 1.0); + var spawnOffset = Vec3.multiply(Vec3.FRONT, VIVE_PUCK_SPAWN_DISTANCE); var spawnPosition = getRelativePosition(MyAvatar.position, MyAvatar.orientation, spawnOffset); // should be an overlay var puckEntityProperties = { - "name": "Tracked Puck", - "type": "Model", - "modelURL": VIVE_PUCK_MODEL, - "dimensions": { x: 0.0945, y: 0.0921, z: 0.0423 }, - "position": spawnPosition, - "userData": "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }" + name: "Tracked Puck", + type: "Model", + modelURL: VIVE_PUCK_MODEL, + dimensions: VIVE_PUCK_DIMENSIONS, + position: spawnPosition, + userData: '{ "grabbableKey": { "grabbable": true, "kinematic": false } }' }; var puckEntityID = Entities.addEntity(puckEntityProperties); + + if (trackedPucks.hasOwnProperty(puck.puckno)) { + destroyPuck(puck.puckno); + } + trackedPucks[puck.puckno] = { - "puckEntityID": puckEntityID, - "trackedEntityID": "" + puckEntityID: puckEntityID, + trackedEntityID: "" }; lastPuck = trackedPucks[puck.puckno]; } @@ -117,7 +124,7 @@ function finalizePuck() { var foundEntities = Entities.findEntities(puckPosition, VIVE_PUCK_SEARCH_DISTANCE); var foundEntity; - var leastDistance = 999999; // this should be something like Integer.MAX_VALUE + var leastDistance = Number.MAX_VALUE; for (var i = 0; i < foundEntities.length; i++) { var entity = foundEntities[i]; @@ -141,6 +148,9 @@ function finalizePuck() { function updatePucks() { // for each puck, update its position and orientation for (var puckName in trackedPucks) { + if (!trackedPucks.hasOwnProperty(puckName)) { + continue; + } var action = indexToTrackedObjectName(puckName); var pose = Controller.getPoseValue(Controller.Standard[action]); if (pose && pose.valid) { @@ -148,7 +158,7 @@ function updatePucks() { if (puck.trackedEntityID) { var avatarXform = new Xform(MyAvatar.orientation, MyAvatar.position); var puckXform = new Xform(pose.rotation, pose.translation); - var finalXform = Xform.mul(avatarXform, Xform.mul(puckXform, Vec3.ZERO)); + var finalXform = Xform.mul(avatarXform, puckXform); Entities.editEntity(puck.puckEntityID, { position: finalXform.pos, @@ -169,13 +179,16 @@ function destroyPuck(puckName) { var puckEntityID = trackedPucks[puckName].puckEntityID; var trackedEntityID = trackedPucks[puckName].trackedEntityID; + // remove the puck as a parent entity and then delete the puck Entities.editEntity(trackedEntityID, { "parentID": "{00000000-0000-0000-0000-000000000000}" }); Entities.deleteEntity(puckEntityID); } function destroyPucks() { // remove all pucks and unparent entities - for (var puck in trackedPucks) { - destroyPuck(puck); + for (var puckName in trackedPucks) { + if (trackedPucks.hasOwnProperty(puckName)) { + destroyPuck(puckName); + } } } From 498ac5d0ab65209aa40230435c10572ecde04f9d Mon Sep 17 00:00:00 2001 From: seefo Date: Thu, 3 Aug 2017 15:08:06 -0700 Subject: [PATCH 5/6] Updated version of puck-attach.js --- scripts/developer/tests/puck-attach.js | 173 +++++++++++++++++-------- 1 file changed, 121 insertions(+), 52 deletions(-) diff --git a/scripts/developer/tests/puck-attach.js b/scripts/developer/tests/puck-attach.js index 65adf35d00..823308e3d5 100644 --- a/scripts/developer/tests/puck-attach.js +++ b/scripts/developer/tests/puck-attach.js @@ -17,7 +17,7 @@ Script.include("/~/system/libraries/Xform.js"); (function() { // BEGIN LOCAL_SCOPE var TABLET_BUTTON_NAME = "PUCKTACH"; -var TABLET_APP_URL = "http://content.highfidelity.com/seefo/production/puck-attach/puck-attach.html"; +var TABLET_APP_URL = "https://hifi-content.s3.amazonaws.com/seefo/production/puck-attach/puck-attach.html"; var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var tabletButton = tablet.addButton({ @@ -33,12 +33,6 @@ function onScreenChanged(type, url) { if (!shown) { // hook up to event bridge tablet.webEventReceived.connect(onWebEventReceived); - - Script.setTimeout(function () { - // send available tracked objects to the html running in the tablet. - var availableTrackedObjects = getAvailableTrackedObjects(); - tablet.emitScriptEvent(JSON.stringify(availableTrackedObjects)); - }, 1000); // wait 1 sec before sending.. } shown = true; } else { @@ -72,6 +66,12 @@ function getAvailableTrackedObjects() { } return available; } +function sendAvailableTrackedObjects() { + tablet.emitScriptEvent(JSON.stringify({ + pucks: getAvailableTrackedObjects(), + selectedPuck: ((lastPuck === undefined) ? -1 : lastPuck.name) + })); +} function getRelativePosition(origin, rotation, offset) { var relativeOffset = Vec3.multiplyQbyV(rotation, offset); @@ -81,45 +81,74 @@ function getRelativePosition(origin, rotation, offset) { function getPropertyForEntity(entityID, propertyName) { return Entities.getEntityProperties(entityID, [propertyName])[propertyName]; } +function entityExists(entityID) { + return Object.keys(Entities.getEntityProperties(entityID)).length > 0; +} var VIVE_PUCK_MODEL = "http://content.highfidelity.com/seefo/production/puck-attach/vive_tracker_puck.obj"; var VIVE_PUCK_DIMENSIONS = { x: 0.0945, y: 0.0921, z: 0.0423 }; // 1/1000th scale of model var VIVE_PUCK_SEARCH_DISTANCE = 1.5; // metres -var VIVE_PUCK_SPAWN_DISTANCE = 1.0; // metres +var VIVE_PUCK_SPAWN_DISTANCE = 0.5; // metres +var VIVE_PUCK_TRACKED_OBJECT_MAX_DISTANCE = 10.0; // metres var VIVE_PUCK_NAME = "Tracked Puck"; var trackedPucks = { }; -var lastPuck = { }; +var lastPuck; function createPuck(puck) { // create a puck entity and add it to our list of pucks - var spawnOffset = Vec3.multiply(Vec3.FRONT, VIVE_PUCK_SPAWN_DISTANCE); - var spawnPosition = getRelativePosition(MyAvatar.position, MyAvatar.orientation, spawnOffset); - - // should be an overlay - var puckEntityProperties = { - name: "Tracked Puck", - type: "Model", - modelURL: VIVE_PUCK_MODEL, - dimensions: VIVE_PUCK_DIMENSIONS, - position: spawnPosition, - userData: '{ "grabbableKey": { "grabbable": true, "kinematic": false } }' - }; - - var puckEntityID = Entities.addEntity(puckEntityProperties); + var action = indexToTrackedObjectName(puck.puckno); + var pose = Controller.getPoseValue(Controller.Standard[action]); - if (trackedPucks.hasOwnProperty(puck.puckno)) { - destroyPuck(puck.puckno); + if (pose && pose.valid) { + var spawnOffset = Vec3.multiply(Vec3.FRONT, VIVE_PUCK_SPAWN_DISTANCE); + var spawnPosition = getRelativePosition(MyAvatar.position, MyAvatar.orientation, spawnOffset); + + // should be an overlay + var puckEntityProperties = { + name: "Tracked Puck", + type: "Model", + modelURL: VIVE_PUCK_MODEL, + dimensions: VIVE_PUCK_DIMENSIONS, + position: spawnPosition, + userData: '{ "grabbableKey": { "grabbable": true, "kinematic": false } }' + }; + + var puckEntityID = Entities.addEntity(puckEntityProperties); + + // if we've already created this puck, destroy it + if (trackedPucks.hasOwnProperty(puck.puckno)) { + destroyPuck(puck.puckno); + } + // if we had an unfinalized puck, destroy it + if (lastPuck !== undefined) { + destroyPuck(lastPuck.name); + } + // create our new unfinalized puck + trackedPucks[puck.puckno] = { + puckEntityID: puckEntityID, + trackedEntityID: "" + }; + lastPuck = trackedPucks[puck.puckno]; + lastPuck.name = Number(puck.puckno); } - - trackedPucks[puck.puckno] = { - puckEntityID: puckEntityID, - trackedEntityID: "" - }; - lastPuck = trackedPucks[puck.puckno]; } -function finalizePuck() { +function finalizePuck(puckName) { // find nearest entity and change its parent to the puck + + if (!trackedPucks.hasOwnProperty(puckName)) { + print('2'); + return; + } + if (lastPuck === undefined) { + print('3'); + return; + } + if (lastPuck.name !== Number(puckName)) { + print('1'); + return; + } + var puckPosition = getPropertyForEntity(lastPuck.puckEntityID, "position"); var foundEntities = Entities.findEntities(puckPosition, VIVE_PUCK_SEARCH_DISTANCE); @@ -142,7 +171,16 @@ function finalizePuck() { if (foundEntity) { lastPuck.trackedEntityID = foundEntity; - Entities.editEntity(lastPuck.trackedEntityID, { "parentID": lastPuck.puckEntityID }); + // remember the userdata for the tracked entity since we're about to + // remove it and make it ungrabbable + lastPuck.trackedEntityUserData = getPropertyForEntity(foundEntity, "userData"); + // update properties of the tracked entity + Entities.editEntity(lastPuck.trackedEntityID, { + "parentID": lastPuck.puckEntityID, + "userData": '{ "grabbableKey": { "grabbable": false } }' + }); + // remove reference to puck since it is now calibrated and finalized + lastPuck = undefined; } } function updatePucks() { @@ -156,32 +194,57 @@ function updatePucks() { if (pose && pose.valid) { var puck = trackedPucks[puckName]; if (puck.trackedEntityID) { - var avatarXform = new Xform(MyAvatar.orientation, MyAvatar.position); - var puckXform = new Xform(pose.rotation, pose.translation); - var finalXform = Xform.mul(avatarXform, puckXform); + if (entityExists(puck.trackedEntityID)) { + var avatarXform = new Xform(MyAvatar.orientation, MyAvatar.position); + var puckXform = new Xform(pose.rotation, pose.translation); + var finalXform = Xform.mul(avatarXform, puckXform); + + var d = Vec3.distance(MyAvatar.position, finalXform.pos); + if (d > VIVE_PUCK_TRACKED_OBJECT_MAX_DISTANCE) { + print('tried to move tracked object too far away: ' + d); + return; + } - Entities.editEntity(puck.puckEntityID, { - position: finalXform.pos, - rotation: finalXform.rot, - }); - - // in case someone grabbed both entities and destroyed the - // child/parent relationship - Entities.editEntity(puck.trackedEntityID, { - parentID: puck.puckEntityID - }); + Entities.editEntity(puck.puckEntityID, { + position: finalXform.pos, + rotation: finalXform.rot + }); + + // in case someone grabbed both entities and destroyed the + // child/parent relationship + Entities.editEntity(puck.trackedEntityID, { + parentID: puck.puckEntityID + }); + } else { + destroyPuck(puckName); + } } } } } function destroyPuck(puckName) { // unparent entity and delete its parent - var puckEntityID = trackedPucks[puckName].puckEntityID; - var trackedEntityID = trackedPucks[puckName].trackedEntityID; + if (!trackedPucks.hasOwnProperty(puckName)) { + return; + } + + var puck = trackedPucks[puckName]; + var puckEntityID = puck.puckEntityID; + var trackedEntityID = puck.trackedEntityID; - // remove the puck as a parent entity and then delete the puck - Entities.editEntity(trackedEntityID, { "parentID": "{00000000-0000-0000-0000-000000000000}" }); - Entities.deleteEntity(puckEntityID); + // remove the puck as a parent entity and restore the tracked entities + // former userdata + Entities.editEntity(trackedEntityID, { + "parentID": "{00000000-0000-0000-0000-000000000000}", + "userData": puck.trackedEntityUserData + }); + + delete trackedPucks[puckName]; + + Script.setTimeout(function() { + // delete the puck + Entities.deleteEntity(puckEntityID); + }, 100); } function destroyPucks() { // remove all pucks and unparent entities @@ -202,11 +265,17 @@ function onWebEventReceived(msg) { } switch (obj.cmd) { + case "ready": + sendAvailableTrackedObjects(); + break; case "create": createPuck(obj); break; case "finalize": - finalizePuck(); + finalizePuck(obj.puckno); + break; + case "destroy": + destroyPuck(obj.puckno); break; } } From 67b59210796bb2e10b08b9904b4e42a95d1b006f Mon Sep 17 00:00:00 2001 From: seefo Date: Thu, 3 Aug 2017 16:01:12 -0700 Subject: [PATCH 6/6] Changed puck-attach to make tracked entities collisionless --- scripts/developer/tests/puck-attach.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/scripts/developer/tests/puck-attach.js b/scripts/developer/tests/puck-attach.js index 823308e3d5..04d5db5710 100644 --- a/scripts/developer/tests/puck-attach.js +++ b/scripts/developer/tests/puck-attach.js @@ -171,17 +171,19 @@ function finalizePuck(puckName) { if (foundEntity) { lastPuck.trackedEntityID = foundEntity; - // remember the userdata for the tracked entity since we're about to - // remove it and make it ungrabbable + // remember the userdata and collisionless flag for the tracked entity since + // we're about to remove it and make it ungrabbable and collisionless lastPuck.trackedEntityUserData = getPropertyForEntity(foundEntity, "userData"); + lastPuck.trackedEntityCollisionFlag = getPropertyForEntity(foundEntity, "collisionless"); // update properties of the tracked entity Entities.editEntity(lastPuck.trackedEntityID, { "parentID": lastPuck.puckEntityID, - "userData": '{ "grabbableKey": { "grabbable": false } }' + "userData": '{ "grabbableKey": { "grabbable": false } }', + "collisionless": 1 }); // remove reference to puck since it is now calibrated and finalized lastPuck = undefined; - } + } } function updatePucks() { // for each puck, update its position and orientation @@ -233,14 +235,19 @@ function destroyPuck(puckName) { var trackedEntityID = puck.trackedEntityID; // remove the puck as a parent entity and restore the tracked entities - // former userdata + // former userdata and collision flag Entities.editEntity(trackedEntityID, { "parentID": "{00000000-0000-0000-0000-000000000000}", - "userData": puck.trackedEntityUserData + "userData": puck.trackedEntityUserData, + "collisionless": puck.trackedEntityCollisionFlag }); delete trackedPucks[puckName]; + // in some cases, the entity deletion may occur before the parent change + // has been processed, resulting in both the puck and the tracked entity + // to be deleted so we wait 100ms before deleting the puck, assuming + // that the parent change has occured Script.setTimeout(function() { // delete the puck Entities.deleteEntity(puckEntityID);