From eff5a4c395958027b5d686337a9cf0cc4d7db8f4 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 6 Oct 2015 22:56:48 -0700 Subject: [PATCH] Picking fixes in the HMD --- examples/example/hmd/pickerTest.js | 103 ++++++++++++++++++ interface/src/Application.cpp | 9 +- interface/src/ui/ApplicationCompositor.cpp | 32 +++--- .../render-utils/src/OffscreenQmlSurface.cpp | 4 +- 4 files changed, 122 insertions(+), 26 deletions(-) create mode 100644 examples/example/hmd/pickerTest.js diff --git a/examples/example/hmd/pickerTest.js b/examples/example/hmd/pickerTest.js new file mode 100644 index 0000000000..96ffc6d21d --- /dev/null +++ b/examples/example/hmd/pickerTest.js @@ -0,0 +1,103 @@ +Script.include("../../libraries/utils.js"); + + +PickerTest = function() { + // Switch every 5 seconds between normal IPD and 0 IPD (in seconds) + this.UPDATE_INTERVAL = 10.0; + this.lastUpdateInterval = 0; + + this.ballId = Overlays.addOverlay("sphere", { + position: { x: 0, y: 0, z: 0 }, + color: { red: 0, green: 255, blue: 0 }, + size: 0.1, + solid: true, + alpha: 1.0, + visible: true, + }); + + this.ballId2 = Overlays.addOverlay("sphere", { + position: { x: 0, y: 0, z: 0 }, + color: { red: 255, green: 0, blue: 0 }, + size: 0.05, + solid: true, + alpha: 1.0, + visible: true, + }); + + var that = this; + Script.scriptEnding.connect(function() { + that.onCleanup(); + }); + + Script.update.connect(function(deltaTime) { + that.lastUpdateInterval += deltaTime; + if (that.lastUpdateInterval >= that.UPDATE_INTERVAL) { + that.onUpdate(that.lastUpdateInterval); + that.lastUpdateInterval = 0; + } + }); + + Controller.mousePressEvent.connect(function(event) { + that.onMousePress(event); + }); + + Controller.mouseMoveEvent.connect(function(event) { + that.onMouseMove(event); + }); + + Controller.mouseReleaseEvent.connect(function(event) { + that.onMouseRelease(event); + }); +}; + +PickerTest.prototype.onCleanup = function() { + Overlays.deleteOverlay(this.ballId) + Overlays.deleteOverlay(this.ballId2) +} + +PickerTest.prototype.updateOverlays = function() { + var pickRay = Camera.computePickRay(this.x, this.y); + var origin = pickRay.origin; + var direction = pickRay.direction; + var position = Vec3.sum(origin, direction) + Overlays.editOverlay(this.ballId, { + position: position + }); + + Overlays.editOverlay(this.ballId2, { + position: origin + }); +} + +PickerTest.prototype.onUpdate = function(deltaTime) { + if (this.clicked) { + this.updateOverlays(); + } +} + +PickerTest.prototype.onMousePress = function(event) { + if (event.button !== "LEFT") { + return + } + this.clicked = true; + this.x = event.x; + this.y = event.y; + this.updateOverlays(); +} + +PickerTest.prototype.onMouseRelease = function(event) { + if (event.button !== "LEFT") { + return + } + this.clicked = false; +} + +PickerTest.prototype.onMouseMove = function(event) { + if (this.clicked) { + this.x = event.x; + this.y = event.y; + this.updateOverlays(); + } +} + +var PickerTest = new PickerTest(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b44ac6804d..72945d63fe 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3175,14 +3175,13 @@ int Application::getBoundaryLevelAdjust() const { } PickRay Application::computePickRay(float x, float y) const { - glm::vec2 size = getCanvasSize(); - x /= size.x; - y /= size.y; + vec2 pickPoint{ x, y }; PickRay result; if (isHMDMode()) { - getApplicationCompositor().computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction); + getApplicationCompositor().computeHmdPickRay(pickPoint, result.origin, result.direction); } else { - getViewFrustum()->computePickRay(x, y, result.origin, result.direction); + pickPoint /= getCanvasSize(); + getViewFrustum()->computePickRay(pickPoint.x, pickPoint.y, result.origin, result.direction); } return result; } diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index cb4ae9990c..86add90283 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -346,31 +346,28 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int void ApplicationCompositor::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const { - cursorPos *= qApp->getCanvasSize(); - const glm::vec2 projection = screenToSpherical(cursorPos); + const glm::vec2 projection = overlayToSpherical(cursorPos); // The overlay space orientation of the mouse coordinates - const glm::quat orientation(glm::vec3(-projection.y, projection.x, 0.0f)); - // FIXME We now have the direction of the ray FROM THE DEFAULT HEAD POSE. - // Now we need to account for the actual camera position relative to the overlay - glm::vec3 overlaySpaceDirection = glm::normalize(orientation * IDENTITY_FRONT); + const glm::quat cursorOrientation(glm::vec3(-projection.y, projection.x, 0.0f)); + // The orientation and position of the HEAD, not the overlay + glm::vec3 worldSpaceHeadPosition = qApp->getCamera()->getPosition(); + glm::quat worldSpaceOrientation = qApp->getCamera()->getOrientation(); - // We need the RAW camera orientation and position, because this is what the overlay is - // rendered relative to - glm::vec3 overlayPosition = qApp->getCamera()->getPosition(); - glm::quat overlayOrientation = qApp->getCamera()->getRotation(); + auto headPose = qApp->getHMDSensorPose(); + auto headOrientation = glm::quat_cast(headPose); + auto headTranslation = extractTranslation(headPose); + auto overlayOrientation = worldSpaceOrientation * glm::inverse(headOrientation); + auto overlayPosition = worldSpaceHeadPosition - (overlayOrientation * headTranslation); if (Menu::getInstance()->isOptionChecked(MenuOption::StandingHMDSensorMode)) { overlayPosition = _modelTransform.getTranslation(); overlayOrientation = _modelTransform.getRotation(); } - // Intersection UI overlay space - glm::vec3 worldSpaceDirection = overlayOrientation * overlaySpaceDirection; - glm::vec3 worldSpaceIntersection = (glm::normalize(worldSpaceDirection) * _oculusUIRadius) + overlayPosition; - glm::vec3 worldSpaceHeadPosition = (overlayOrientation * extractTranslation(qApp->getHMDSensorPose())) + overlayPosition; - // Intersection in world space + glm::vec3 worldSpaceIntersection = ((overlayOrientation * (cursorOrientation * Vectors::FRONT)) * _oculusUIRadius) + overlayPosition; + origin = worldSpaceHeadPosition; direction = glm::normalize(worldSpaceIntersection - worldSpaceHeadPosition); } @@ -682,7 +679,6 @@ glm::vec2 ApplicationCompositor::screenToSpherical(const glm::vec2& screenPos) { result.y = (screenPos.y / screenSize.y - 0.5f); result.x *= MOUSE_YAW_RANGE; result.y *= MOUSE_PITCH_RANGE; - return result; } @@ -701,13 +697,13 @@ glm::vec2 ApplicationCompositor::sphericalToOverlay(const glm::vec2& sphericalP result /= _textureFov; result.x /= _textureAspectRatio; result += 0.5f; - result *= qApp->getCanvasSize(); + result *= qApp->getUiSize(); return result; } glm::vec2 ApplicationCompositor::overlayToSpherical(const glm::vec2& overlayPos) const { glm::vec2 result = overlayPos; - result /= qApp->getCanvasSize(); + result /= qApp->getUiSize(); result -= 0.5f; result *= _textureFov; result.x *= _textureAspectRatio; diff --git a/libraries/render-utils/src/OffscreenQmlSurface.cpp b/libraries/render-utils/src/OffscreenQmlSurface.cpp index 3f940d8569..6c68b60f42 100644 --- a/libraries/render-utils/src/OffscreenQmlSurface.cpp +++ b/libraries/render-utils/src/OffscreenQmlSurface.cpp @@ -497,9 +497,7 @@ QPointF OffscreenQmlSurface::mapWindowToUi(const QPointF& sourcePosition, QObjec } QPointF OffscreenQmlSurface::mapToVirtualScreen(const QPointF& originalPoint, QObject* originalWidget) { - QPointF transformedPos = _mouseTranslator(originalPoint); - transformedPos = mapWindowToUi(transformedPos, originalWidget); - return transformedPos; + return _mouseTranslator(originalPoint); }