From 5c406a0e0663f05dad0e874e0ac3c0ec49812db9 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 23 Sep 2014 15:11:45 -0700 Subject: [PATCH 1/6] Add "Leap Motion on HMD" developer menu option --- interface/src/Menu.cpp | 3 +++ interface/src/Menu.h | 1 + 2 files changed, 4 insertions(+) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8f7b2be43b..d18b2b7d77 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -446,6 +446,9 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseMouseInput, 0, true); addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseLasers, 0, false); + QMenu* leapOptionsMenu = handOptionsMenu->addMenu("Leap Motion"); + addCheckableActionToQMenuAndActionHash(leapOptionsMenu, MenuOption::LeapMotionOnHMD, 0, false); + QMenu* networkMenu = developerMenu->addMenu("Network"); addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::DisableNackPackets, 0, false); addCheckableActionToQMenuAndActionHash(networkMenu, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index b267ab8b2c..38b16f9f6c 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -402,6 +402,7 @@ namespace MenuOption { const QString IncreaseAvatarSize = "Increase Avatar Size"; const QString IncreaseVoxelSize = "Increase Voxel Size"; const QString KeyboardMotorControl = "Enable Keyboard Motor Control"; + const QString LeapMotionOnHMD = "Leap Motion on HMD"; const QString LoadScript = "Open and Run Script File..."; const QString LoadScriptURL = "Open and Run Script from URL..."; const QString LodTools = "LOD Tools"; From 6375e42d886ddb38df695c77543215b73e070eb1 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 23 Sep 2014 15:13:01 -0700 Subject: [PATCH 2/6] Configure Leap controller per HMD option when controller is created --- interface/src/devices/Leapmotion.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/interface/src/devices/Leapmotion.cpp b/interface/src/devices/Leapmotion.cpp index 7060c5c5e9..a3794123ce 100644 --- a/interface/src/devices/Leapmotion.cpp +++ b/interface/src/devices/Leapmotion.cpp @@ -8,8 +8,9 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "SharedUtil.h" #include "Leapmotion.h" +#include "Menu.h" +#include "SharedUtil.h" const int PALMROOT_NUM_JOINTS = 3; const int FINGER_NUM_JOINTS = 4; @@ -101,6 +102,12 @@ Leapmotion::Leapmotion() : } } } + +#ifdef HAVE_LEAPMOTION + if (Menu::getInstance()->isOptionChecked(MenuOption::LeapMotionOnHMD)) { + _controller.setPolicyFlags(Leap::Controller::POLICY_OPTIMIZE_HMD); + } +#endif } Leapmotion::~Leapmotion() { From c02cd66dcbeb8d0a436e93d9af24a33794ff9920 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 23 Sep 2014 15:14:01 -0700 Subject: [PATCH 3/6] Don't calibrate avatar for Leap Motion if mounted on HMD --- examples/leapHands.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/examples/leapHands.js b/examples/leapHands.js index 95d3969a08..ba6ce432de 100644 --- a/examples/leapHands.js +++ b/examples/leapHands.js @@ -13,7 +13,8 @@ var leapHands = (function () { - var hands, + var isOnHMD, + hands, wrists, NUM_HANDS = 2, // 0 = left; 1 = right fingers, @@ -188,8 +189,6 @@ var leapHands = (function () { function setUp() { - calibrationStatus = UNCALIBRATED; - // TODO: Leap Motion controller joint naming doesn't match up with skeleton joint naming; numbers are out by 1. hands = [ @@ -265,6 +264,19 @@ var leapHands = (function () { { jointName: "RightHandPinky3", controller: Controller.createInputController("Spatial", "joint_R_pinky4") } ] ]; + + isOnHMD = Menu.isOptionChecked("Leap Motion on HMD"); + if (isOnHMD) { + print("Leap Motion is on HMD"); + + hands[0].zeroPosition = { x: 0.0, y: 0.0, z: 0.0 }; + hands[1].zeroPosition = { x: 0.0, y: 0.0, z: 0.0 }; + + calibrationStatus = CALIBRATED; + } else { + print("Leap Motion is on desk"); + calibrationStatus = UNCALIBRATED; + } } function moveHands() { From 1bffaa262d36f1f3a23a6081299e3b44f722fbae Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 29 Sep 2014 15:46:22 -0700 Subject: [PATCH 4/6] Reference camera object rather than copy it --- interface/src/Application.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0fd7ae96d1..57a0bb336d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -650,7 +650,7 @@ void Application::paintGL() { // Why have two cameras? Well, one reason is that because in the case of the renderViewFrustum() // code, we want to keep the state of "myCamera" intact, so we can render what the view frustum of // myCamera is. But we also want to do meaningful camera transforms on OpenGL for the offset camera - Camera whichCamera = _myCamera; + Camera* whichCamera = &_myCamera; if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum)) { @@ -664,7 +664,7 @@ void Application::paintGL() { _viewFrustumOffsetCamera.setDistance(viewFrustumOffset.distance); _viewFrustumOffsetCamera.initialize(); // force immediate snap to ideal position and orientation _viewFrustumOffsetCamera.update(1.f/_fps); - whichCamera = _viewFrustumOffsetCamera; + whichCamera = &_viewFrustumOffsetCamera; } if (Menu::getInstance()->getShadowsEnabled()) { @@ -677,15 +677,15 @@ void Application::paintGL() { glClear(GL_COLOR_BUFFER_BIT); //When in mirror mode, use camera rotation. Otherwise, use body rotation - if (whichCamera.getMode() == CAMERA_MODE_MIRROR) { - OculusManager::display(whichCamera.getRotation(), whichCamera.getPosition(), whichCamera); + if (whichCamera->getMode() == CAMERA_MODE_MIRROR) { + OculusManager::display(whichCamera->getRotation(), whichCamera->getPosition(), *whichCamera); } else { - OculusManager::display(_myAvatar->getWorldAlignedOrientation(), _myAvatar->getDefaultEyePosition(), whichCamera); + OculusManager::display(_myAvatar->getWorldAlignedOrientation(), _myAvatar->getDefaultEyePosition(), *whichCamera); } } else if (TV3DManager::isConnected()) { - TV3DManager::display(whichCamera); + TV3DManager::display(*whichCamera); } else { _glowEffect.prepare(); @@ -693,7 +693,7 @@ void Application::paintGL() { glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); - displaySide(whichCamera); + displaySide(*whichCamera); glPopMatrix(); if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { From 673afca11b4e527658ffe59b759524b26e8df11b Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 30 Sep 2014 10:05:59 -0700 Subject: [PATCH 5/6] Update camera object's position and orientation with actual Rift values --- interface/src/Application.cpp | 12 +++++++++--- interface/src/devices/OculusManager.cpp | 4 ++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 57a0bb336d..dc3b48ae85 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -609,8 +609,11 @@ void Application::paintGL() { if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { _myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay - _myCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition()); - _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation()); + if (!OculusManager::isConnected()) { + _myCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition()); + _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation()); + } + // OculusManager::display() updates camera position and rotation a bit further on. } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { //Note, the camera distance is set in Camera::setMode() so we dont have to do it here. @@ -640,7 +643,9 @@ void Application::paintGL() { } // Update camera position - _myCamera.update( 1.f/_fps ); + if (!OculusManager::isConnected()) { + _myCamera.update(1.f / _fps); + } // Note: whichCamera is used to pick between the normal camera myCamera for our // main camera, vs, an alternate camera. The alternate camera we support right now @@ -682,6 +687,7 @@ void Application::paintGL() { } else { OculusManager::display(_myAvatar->getWorldAlignedOrientation(), _myAvatar->getDefaultEyePosition(), *whichCamera); } + _myCamera.update(1.f / _fps); } else if (TV3DManager::isConnected()) { diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 27590d9a72..65518b839c 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -412,6 +412,10 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p glBindTexture(GL_TEXTURE_2D, 0); + // Update camera for use by rest of Interface. + whichCamera.setTargetPosition((_leftEyePosition + _rightEyePosition) / 2.f); + whichCamera.setTargetRotation(_camera->getTargetRotation()); + #endif } From 26cd76e07b08b02c1272535d4e25e12bc0808303 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 30 Sep 2014 10:08:50 -0700 Subject: [PATCH 6/6] Position and orient hands when using Leap on HMD --- examples/leapHands.js | 102 +++++++++++++++++++++++++++++++----------- 1 file changed, 77 insertions(+), 25 deletions(-) diff --git a/examples/leapHands.js b/examples/leapHands.js index ba6ce432de..cc50a328f8 100644 --- a/examples/leapHands.js +++ b/examples/leapHands.js @@ -14,6 +14,8 @@ var leapHands = (function () { var isOnHMD, + LEAP_OFFSET = 0.019, // Thickness of Leap Motion plus HMD clip + HMD_OFFSET = 0.100, // Eyeballs to front surface of Oculus DK2 TODO: Confirm and make depend on device and eye relief hands, wrists, NUM_HANDS = 2, // 0 = left; 1 = right @@ -269,8 +271,9 @@ var leapHands = (function () { if (isOnHMD) { print("Leap Motion is on HMD"); - hands[0].zeroPosition = { x: 0.0, y: 0.0, z: 0.0 }; - hands[1].zeroPosition = { x: 0.0, y: 0.0, z: 0.0 }; + // Offset of Leap Motion origin from physical eye position + hands[0].zeroPosition = { x: 0.0, y: 0.0, z: HMD_OFFSET + LEAP_OFFSET }; + hands[1].zeroPosition = { x: 0.0, y: 0.0, z: HMD_OFFSET + LEAP_OFFSET }; calibrationStatus = CALIBRATED; } else { @@ -290,7 +293,9 @@ var leapHands = (function () { handYaw, handRotation, wristAbsRotation, - locRotation; + locRotation, + cameraOrientation, + inverseAvatarOrientation; for (h = 0; h < NUM_HANDS; h += 1) { side = h === 0 ? -1.0 : 1.0; @@ -303,35 +308,82 @@ var leapHands = (function () { } // Hand position ... - handOffset = hands[h].controller.getAbsTranslation(); - handOffset = { - x: -handOffset.x, - y: hands[h].zeroPosition.y + handOffset.y, - z: hands[h].zeroPosition.z - handOffset.z - }; + if (isOnHMD) { - // TODO: 2.0* scale factor should not be necessary; Leap Motion controller code needs investigating. - handRoll = 2.0 * -hands[h].controller.getAbsRotation().z; - wristAbsRotation = wrists[h].controller.getAbsRotation(); - handPitch = 2.0 * -wristAbsRotation.x; - handYaw = 2.0 * wristAbsRotation.y; + // Hand offset in camera coordinates ... + handOffset = hands[h].controller.getAbsTranslation(); + handOffset = { + x: hands[h].zeroPosition.x - handOffset.x, + y: hands[h].zeroPosition.y - handOffset.z, + z: hands[h].zeroPosition.z + handOffset.y + }; + handOffset.z = -handOffset.z; - // TODO: Leap Motion controller's right-hand roll calculation only works if physical hand is upside down. - // Approximate fix is to add a fudge factor. - if (h === 1 && isWindows) { - handRoll = handRoll + 0.6 * PI; - } + // Hand offset in world coordinates ... + cameraOrientation = Camera.getOrientation(); + handOffset = Vec3.sum(Camera.getPosition(), Vec3.multiplyQbyV(cameraOrientation, handOffset)); - // Hand position and orientation ... - if (h === 0) { - handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }), - Quat.fromVec3Radians({ x: handRoll, y: handYaw, z: -handPitch })); + // Hand offset in avatar coordinates ... + inverseAvatarOrientation = Quat.inverse(MyAvatar.orientation); + handOffset = Vec3.subtract(handOffset, MyAvatar.position); + handOffset = Vec3.multiplyQbyV(inverseAvatarOrientation, handOffset); + handOffset.z = -handOffset.z; + handOffset.x = -handOffset.x; + // Hand rotation in camera coordinates ... + // TODO: 2.0* scale factors should not be necessary; Leap Motion controller code needs investigating. + handRoll = 2.0 * -hands[h].controller.getAbsRotation().z; + wristAbsRotation = wrists[h].controller.getAbsRotation(); + handPitch = 2.0 * wristAbsRotation.x - PI / 2.0; + handYaw = 2.0 * -wristAbsRotation.y; + // TODO: Roll values only work if hand is upside down; Leap Motion controller code needs investigating. + handRoll = PI + handRoll; + + if (h === 0) { + handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }), + Quat.fromVec3Radians({ x: handRoll, y: handYaw, z: -handPitch })); + } else { + handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 1, z: 0 }), + Quat.fromVec3Radians({ x: -handRoll, y: handYaw, z: handPitch })); + } + + // Hand rotation in avatar coordinates ... + cameraOrientation.x = -cameraOrientation.x; + cameraOrientation.z = -cameraOrientation.z; + handRotation = Quat.multiply(cameraOrientation, handRotation); + handRotation = Quat.multiply(inverseAvatarOrientation, handRotation); } else { - handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 1, z: 0 }), - Quat.fromVec3Radians({ x: -handRoll, y: handYaw, z: handPitch })); + + handOffset = hands[h].controller.getAbsTranslation(); + handOffset = { + x: -handOffset.x, + y: hands[h].zeroPosition.y + handOffset.y, + z: hands[h].zeroPosition.z - handOffset.z + }; + + // TODO: 2.0* scale factors should not be necessary; Leap Motion controller code needs investigating. + handRoll = 2.0 * -hands[h].controller.getAbsRotation().z; + wristAbsRotation = wrists[h].controller.getAbsRotation(); + handPitch = 2.0 * -wristAbsRotation.x; + handYaw = 2.0 * wristAbsRotation.y; + + // TODO: Leap Motion controller's right-hand roll calculation only works if physical hand is upside down. + // Approximate fix is to add a fudge factor. + if (h === 1 && isWindows) { + handRoll = handRoll + 0.6 * PI; + } + + // Hand position and orientation ... + if (h === 0) { + handRotation = Quat.multiply(Quat.angleAxis(-90.0, { x: 0, y: 1, z: 0 }), + Quat.fromVec3Radians({ x: handRoll, y: handYaw, z: -handPitch })); + } else { + handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 0, y: 1, z: 0 }), + Quat.fromVec3Radians({ x: -handRoll, y: handYaw, z: handPitch })); + } } + MyAvatar.setJointModelPositionAndOrientation(hands[h].jointName, handOffset, handRotation, true); // Finger joints ...