From cdc8f1e2748477d8e543503607a91bb737529be6 Mon Sep 17 00:00:00 2001 From: Daosheng Mu Date: Wed, 22 Apr 2020 09:11:25 -0700 Subject: [PATCH] WebXR gamepad module support. (#2521) * Making OculusVR support WebXR gamepad. * Making WaveVR support WebXR gamepad. * Making PicoVR support WebXR gamepad. * Add squeeze btn state for app usage. * Bump GV to 77.0.20200418094905. * Fix Pico G2 standing matrix * Fixes 3DOF controller positionEmulated. * Apply elbow transform for Pico G2 immersive mode * Prevent select and squeeze actions to be triggered when clicking on the WebXR interstitial * Bump GV to 77.0.20200422093542 Co-authored-by: Imanol Fernandez --- .../browser/engine/SessionUtils.java | 1 + app/src/main/cpp/BrowserWorld.cpp | 9 +- app/src/main/cpp/Controller.cpp | 15 ++++ app/src/main/cpp/Controller.h | 11 ++- app/src/main/cpp/ControllerContainer.cpp | 90 +++++++++++++++++++ app/src/main/cpp/ControllerContainer.h | 8 ++ app/src/main/cpp/ControllerDelegate.h | 23 +++-- app/src/main/cpp/Device.h | 26 ++++++ app/src/main/cpp/ExternalVR.cpp | 80 +++++++++++++++-- app/src/main/cpp/ExternalVR.h | 1 + app/src/main/cpp/moz_external_vr.h | 56 +++++++----- .../oculusvr/cpp/DeviceDelegateOculusVR.cpp | 82 +++++++++++++---- app/src/picovr/cpp/DeviceDelegatePicoVR.cpp | 83 +++++++++++------ app/src/wavevr/cpp/DeviceDelegateWaveVR.cpp | 64 ++++++++++--- versions.gradle | 2 +- 15 files changed, 454 insertions(+), 97 deletions(-) diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/SessionUtils.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/SessionUtils.java index d9913d941..475cf3e11 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/SessionUtils.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/engine/SessionUtils.java @@ -32,6 +32,7 @@ public static void vrPrefsWorkAround(Context aContext, Bundle aExtras) { try (FileOutputStream out = new FileOutputStream(prefFileName)) { out.write("pref(\"dom.vr.enabled\", true);\n".getBytes()); out.write("pref(\"dom.vr.external.enabled\", true);\n".getBytes()); + out.write("pref(\"dom.vr.webxr.enabled\", true);\n".getBytes()); out.write("pref(\"webgl.enable-surface-texture\", true);\n".getBytes()); // Enable MultiView draft extension out.write("pref(\"webgl.enable-draft-extensions\", true);\n".getBytes()); diff --git a/app/src/main/cpp/BrowserWorld.cpp b/app/src/main/cpp/BrowserWorld.cpp index cdb18964f..e808d1fe2 100644 --- a/app/src/main/cpp/BrowserWorld.cpp +++ b/app/src/main/cpp/BrowserWorld.cpp @@ -249,7 +249,7 @@ BrowserWorld::State::CheckBackButton() { VRBrowser::HandleBack(); webXRInterstialState = WebXRInterstialState::HIDDEN; } else if (webXRInterstialState == WebXRInterstialState::ALLOW_DISMISS - && controller.lastButtonState == 0 && controller.buttonState) { + && controller.lastButtonState && controller.buttonState == 0) { VRBrowser::OnDismissWebXRInterstitial(); webXRInterstialState = WebXRInterstialState::HIDDEN; } @@ -582,6 +582,10 @@ BrowserWorld::State::ClearWebXRControllerData() { }; controller.immersiveTouchedState = 0; controller.immersivePressedState = 0; + controller.selectActionStartFrameId = 0; + controller.selectActionStopFrameId = 0; + controller.squeezeActionStartFrameId = 0; + controller.squeezeActionStopFrameId = 0; for (int i = 0; i < controller.numAxes; ++i) { controller.immersiveAxes[i] = 0; } @@ -949,6 +953,9 @@ BrowserWorld::StartFrame() { m.context->Update(); m.externalVR->PullBrowserState(); m.externalVR->SetHapticState(m.controllers); + + const uint64_t frameId = m.externalVR->GetFrameId(); + m.controllers->SetFrameId(frameId); m.CheckExitImmersive(); if (m.splashAnimation) { diff --git a/app/src/main/cpp/Controller.cpp b/app/src/main/cpp/Controller.cpp index a5fb2dff7..9605014e4 100644 --- a/app/src/main/cpp/Controller.cpp +++ b/app/src/main/cpp/Controller.cpp @@ -51,6 +51,7 @@ Controller::operator=(const Controller& aController) { pointer = aController.pointer; transformMatrix = aController.transformMatrix; beamTransformMatrix = aController.beamTransformMatrix; + immersiveBeamTransform = aController.immersiveBeamTransform; immersiveName = aController.immersiveName; immersivePressedState = aController.immersivePressedState; immersiveTouchedState = aController.immersiveTouchedState; @@ -65,6 +66,13 @@ Controller::operator=(const Controller& aController) { leftHanded = aController.leftHanded; inDeadZone = aController.inDeadZone; lastHoverEvent = aController.lastHoverEvent; + profile = aController.profile; + type = aController.type; + targetRayMode = aController.targetRayMode; + selectActionStartFrameId = aController.selectActionStartFrameId; + selectActionStopFrameId = aController.selectActionStopFrameId; + squeezeActionStartFrameId = aController.squeezeActionStartFrameId; + squeezeActionStopFrameId = aController.squeezeActionStopFrameId; return *this; } @@ -88,6 +96,7 @@ Controller::Reset() { pointer = nullptr; transformMatrix = Matrix::Identity(); beamTransformMatrix = Matrix::Identity(); + immersiveBeamTransform = Matrix::Identity(); immersiveName.clear(); immersivePressedState = 0; immersiveTouchedState = 0; @@ -102,6 +111,12 @@ Controller::Reset() { leftHanded = false; inDeadZone = true; lastHoverEvent = 0.0; + type = device::UnknownType; + targetRayMode = device::TargetRayMode::TrackedPointer; + selectActionStartFrameId = 0; + selectActionStopFrameId = 0; + squeezeActionStartFrameId = 0; + squeezeActionStopFrameId = 0; } vrb::Vector Controller::StartPoint() const { diff --git a/app/src/main/cpp/Controller.h b/app/src/main/cpp/Controller.h index c311fa333..37d869fb2 100644 --- a/app/src/main/cpp/Controller.h +++ b/app/src/main/cpp/Controller.h @@ -16,7 +16,7 @@ namespace crow { class Pointer; typedef std::shared_ptr PointerPtr; -static const int kControllerMaxButtonCount = 6; +static const int kControllerMaxButtonCount = 7; static const int kControllerMaxAxes = 6; struct Controller { @@ -44,6 +44,7 @@ struct Controller { PointerPtr pointer; vrb::Matrix transformMatrix; vrb::Matrix beamTransformMatrix; + vrb::Matrix immersiveBeamTransform; std::string immersiveName; uint64_t immersivePressedState; uint64_t immersiveTouchedState; @@ -52,6 +53,8 @@ struct Controller { float immersiveAxes[kControllerMaxAxes]; uint32_t numAxes; uint32_t numHaptics; + device::DeviceType type; + device::TargetRayMode targetRayMode; float inputFrameID; float pulseDuration; float pulseIntensity; @@ -61,6 +64,12 @@ struct Controller { double lastHoverEvent; device::CapabilityFlags deviceCapabilities; + std::string profile; + uint64_t selectActionStartFrameId; + uint64_t selectActionStopFrameId; + uint64_t squeezeActionStartFrameId; + uint64_t squeezeActionStopFrameId; + vrb::Vector StartPoint() const; vrb::Vector Direction() const; diff --git a/app/src/main/cpp/ControllerContainer.cpp b/app/src/main/cpp/ControllerContainer.cpp index 216e1dc2e..037143def 100644 --- a/app/src/main/cpp/ControllerContainer.cpp +++ b/app/src/main/cpp/ControllerContainer.cpp @@ -36,12 +36,16 @@ struct ControllerContainer::State { bool visible = false; vrb::Color pointerColor; int gazeIndex = -1; + uint64_t immersiveFrameId; + uint64_t lastImmersiveFrameId; void Initialize(vrb::CreationContextPtr& aContext) { context = aContext; root = Toggle::Create(aContext); visible = true; pointerColor = vrb::Color(1.0f, 1.0f, 1.0f, 1.0f); + immersiveFrameId = 0; + lastImmersiveFrameId = 0; } bool Contains(const int32_t aControllerIndex) { @@ -194,6 +198,7 @@ ControllerContainer::CreateController(const int32_t aControllerIndex, const int3 controller.index = aControllerIndex; controller.immersiveName = aImmersiveName; controller.beamTransformMatrix = aBeamTransform; + controller.immersiveBeamTransform = aBeamTransform; if (aModelIndex < 0) { return; } @@ -234,6 +239,15 @@ ControllerContainer::CreateController(const int32_t aControllerIndex, const int3 m.updatePointerColor(controller); } +void +ControllerContainer::SetImmersiveBeamTransform(const int32_t aControllerIndex, + const vrb::Matrix& aImmersiveBeamTransform) { + if (!m.Contains(aControllerIndex)) { + return; + } + m.list[aControllerIndex].immersiveBeamTransform = aImmersiveBeamTransform; +} + void ControllerContainer::SetFocused(const int32_t aControllerIndex) { if (!m.Contains(aControllerIndex)) { @@ -287,6 +301,24 @@ ControllerContainer::SetVisible(const int32_t aControllerIndex, const bool aVisi } } +void +ControllerContainer::SetControllerType(const int32_t aControllerIndex, device::DeviceType aType) { + if (!m.Contains(aControllerIndex)) { + return; + } + Controller& controller = m.list[aControllerIndex]; + controller.type = aType; +} + +void +ControllerContainer::SetTargetRayMode(const int32_t aControllerIndex, device::TargetRayMode aMode) { + if (!m.Contains(aControllerIndex)) { + return; + } + Controller& controller = m.list[aControllerIndex]; + controller.targetRayMode = aMode; +} + void ControllerContainer::SetTransform(const int32_t aControllerIndex, const vrb::Matrix& aTransform) { if (!m.Contains(aControllerIndex)) { @@ -399,6 +431,54 @@ ControllerContainer::GetHapticFeedback(const int32_t aControllerIndex, uint64_t aPulseIntensity = m.list[aControllerIndex].pulseIntensity; } +void +ControllerContainer::SetSelectActionStart(const int32_t aControllerIndex) { + if (!m.Contains(aControllerIndex) || !m.immersiveFrameId) { + return; + } + + if (m.list[aControllerIndex].selectActionStopFrameId >= + m.list[aControllerIndex].selectActionStartFrameId) { + m.list[aControllerIndex].selectActionStartFrameId = m.immersiveFrameId; + } +} + +void +ControllerContainer::SetSelectActionStop(const int32_t aControllerIndex) { + if (!m.Contains(aControllerIndex) || !m.lastImmersiveFrameId) { + return; + } + + if (m.list[aControllerIndex].selectActionStartFrameId > + m.list[aControllerIndex].selectActionStopFrameId) { + m.list[aControllerIndex].selectActionStopFrameId = m.lastImmersiveFrameId; + } +} + +void +ControllerContainer::SetSqueezeActionStart(const int32_t aControllerIndex) { + if (!m.Contains(aControllerIndex) || !m.immersiveFrameId) { + return; + } + + if (m.list[aControllerIndex].squeezeActionStopFrameId >= + m.list[aControllerIndex].squeezeActionStartFrameId) { + m.list[aControllerIndex].squeezeActionStartFrameId = m.immersiveFrameId; + } +} + +void +ControllerContainer::SetSqueezeActionStop(const int32_t aControllerIndex) { + if (!m.Contains(aControllerIndex) || !m.lastImmersiveFrameId) { + return; + } + + if (m.list[aControllerIndex].squeezeActionStartFrameId > + m.list[aControllerIndex].squeezeActionStopFrameId) { + m.list[aControllerIndex].squeezeActionStopFrameId = m.lastImmersiveFrameId; + } +} + void ControllerContainer::SetLeftHanded(const int32_t aControllerIndex, const bool aLeftHanded) { if (!m.Contains(aControllerIndex)) { @@ -466,6 +546,16 @@ void ControllerContainer::SetGazeModeIndex(const int32_t aControllerIndex) { m.gazeIndex = aControllerIndex; } +void +ControllerContainer::SetFrameId(const uint64_t aFrameId) { + if (m.immersiveFrameId) { + m.lastImmersiveFrameId = aFrameId ? aFrameId : m.immersiveFrameId; + } else { + m.lastImmersiveFrameId = 0; + } + m.immersiveFrameId = aFrameId; +} + ControllerContainer::ControllerContainer(State& aState, vrb::CreationContextPtr& aContext) : m(aState) { m.Initialize(aContext); } diff --git a/app/src/main/cpp/ControllerContainer.h b/app/src/main/cpp/ControllerContainer.h index 35f4b7141..f36ed7bf2 100644 --- a/app/src/main/cpp/ControllerContainer.h +++ b/app/src/main/cpp/ControllerContainer.h @@ -35,11 +35,14 @@ class ControllerContainer : public crow::ControllerDelegate { uint32_t GetControllerCount() override; void CreateController(const int32_t aControllerIndex, const int32_t aModelIndex, const std::string& aImmersiveName) override; void CreateController(const int32_t aControllerIndex, const int32_t aModelIndex, const std::string& aImmersiveName, const vrb::Matrix& aBeamTransform) override; + void SetImmersiveBeamTransform(const int32_t aControllerIndex, const vrb::Matrix& aImmersiveBeamTransform) override; void SetFocused(const int32_t aControllerIndex) override; void DestroyController(const int32_t aControllerIndex) override; void SetCapabilityFlags(const int32_t aControllerIndex, const device::CapabilityFlags aFlags) override; void SetEnabled(const int32_t aControllerIndex, const bool aEnabled) override; void SetVisible(const int32_t aControllerIndex, const bool aVisible) override; + void SetControllerType(const int32_t aControllerIndex, device::DeviceType aType) override; + void SetTargetRayMode(const int32_t aControllerIndex, device::TargetRayMode aMode) override; void SetTransform(const int32_t aControllerIndex, const vrb::Matrix& aTransform) override; void SetButtonCount(const int32_t aControllerIndex, const uint32_t aNumButtons) override; void SetButtonState(const int32_t aControllerIndex, const Button aWhichButton, const int32_t aImmersiveIndex, const bool aPressed, const bool aTouched, const float aImmersiveTrigger = -1.0f) override; @@ -48,6 +51,10 @@ class ControllerContainer : public crow::ControllerDelegate { uint32_t GetHapticCount(const int32_t aControllerIndex) override; void SetHapticFeedback(const int32_t aControllerIndex, const uint64_t aInputFrameID, const float aPulseDuration, const float aPulseIntensity) override; void GetHapticFeedback(const int32_t aControllerIndex, uint64_t &aInputFrameID, float& aPulseDuration, float& aPulseIntensity) override; + void SetSelectActionStart(const int32_t aControllerIndex) override; + void SetSelectActionStop(const int32_t aControllerIndex) override; + void SetSqueezeActionStart(const int32_t aControllerIndex) override; + void SetSqueezeActionStop(const int32_t aControllerIndex) override; void SetLeftHanded(const int32_t aControllerIndex, const bool aLeftHanded) override; void SetTouchPosition(const int32_t aControllerIndex, const float aTouchX, const float aTouchY) override; void EndTouch(const int32_t aControllerIndex) override; @@ -55,6 +62,7 @@ class ControllerContainer : public crow::ControllerDelegate { void SetPointerColor(const vrb::Color& color) const; void SetVisible(const bool aVisible); void SetGazeModeIndex(const int32_t aControllerIndex) override; + void SetFrameId(const uint64_t aFrameId); protected: struct State; ControllerContainer(State& aState, vrb::CreationContextPtr& aContext); diff --git a/app/src/main/cpp/ControllerDelegate.h b/app/src/main/cpp/ControllerDelegate.h index 6000d8f68..06cdc05c2 100644 --- a/app/src/main/cpp/ControllerDelegate.h +++ b/app/src/main/cpp/ControllerDelegate.h @@ -12,6 +12,7 @@ #include "GestureDelegate.h" #include +#include namespace crow { @@ -22,23 +23,27 @@ class ControllerDelegate { public: enum Button { BUTTON_TRIGGER = 1u << 0u, - BUTTON_TOUCHPAD = 1u << 1u, - BUTTON_APP = 1u << 2u, - BUTTON_A = 1u << 3u, - BUTTON_B = 1u << 4u, - BUTTON_X = 1u << 5u, - BUTTON_Y = 1u << 6u, - BUTTON_OTHERS = 1u << 7u, // Other buttons only for the immersive mode. + BUTTON_SQUEEZE = 1u << 1u, + BUTTON_TOUCHPAD = 1u << 2u, + BUTTON_APP = 1u << 3u, + BUTTON_A = 1u << 4u, + BUTTON_B = 1u << 5u, + BUTTON_X = 1u << 6u, + BUTTON_Y = 1u << 7u, + BUTTON_OTHERS = 1u << 8u, // Other buttons only for the immersive mode. }; virtual void CreateController(const int32_t aControllerIndex, const int32_t aModelIndex, const std::string& aImmersiveName) = 0; virtual void CreateController(const int32_t aControllerIndex, const int32_t aModelIndex, const std::string& aImmersiveName, const vrb::Matrix& aBeamTransform) = 0; + virtual void SetImmersiveBeamTransform(const int32_t aControllerIndex, const vrb::Matrix& aImmersiveBeamTransform) = 0; virtual void SetFocused(const int32_t aControllerIndex) = 0; virtual void DestroyController(const int32_t aControllerIndex) = 0; virtual uint32_t GetControllerCount() = 0; virtual void SetCapabilityFlags(const int32_t aControllerIndex, const device::CapabilityFlags aFlags) = 0; virtual void SetEnabled(const int32_t aControllerIndex, const bool aEnabled) = 0; virtual void SetVisible(const int32_t aControllerIndex, const bool aVisible) = 0; + virtual void SetControllerType(const int32_t aControllerIndex, device::DeviceType aType) = 0; + virtual void SetTargetRayMode(const int32_t aControllerIndex, device::TargetRayMode aMode) = 0; virtual void SetTransform(const int32_t aControllerIndex, const vrb::Matrix& aTransform) = 0; virtual void SetButtonCount(const int32_t aControllerIndex, const uint32_t aNumButtons) = 0; virtual void SetButtonState(const int32_t aControllerIndex, const Button aWhichButton, const int32_t aImmersiveIndex, const bool aPressed, const bool aTouched, const float aImmersiveTrigger = -1.0f) = 0; @@ -47,6 +52,10 @@ class ControllerDelegate { virtual uint32_t GetHapticCount(const int32_t aControllerIndex) = 0; virtual void SetHapticFeedback(const int32_t aControllerIndex, const uint64_t aInputFrameID, const float aPulseDuration, const float aPulseIntensity) = 0; virtual void GetHapticFeedback(const int32_t aControllerIndex, uint64_t & aInputFrameID, float& aPulseDuration, float& aPulseIntensity) = 0; + virtual void SetSelectActionStart(const int32_t aControllerIndex) = 0; + virtual void SetSelectActionStop(const int32_t aControllerIndex) = 0; + virtual void SetSqueezeActionStart(const int32_t aControllerIndex) = 0; + virtual void SetSqueezeActionStop(const int32_t aControllerIndex) = 0; virtual void SetLeftHanded(const int32_t aControllerIndex, const bool aLeftHanded) = 0; virtual void SetTouchPosition(const int32_t aControllerIndex, const float aTouchX, const float aTouchY) = 0; virtual void EndTouch(const int32_t aControllerIndex) = 0; diff --git a/app/src/main/cpp/Device.h b/app/src/main/cpp/Device.h index b02d84b89..ed0ce44c8 100644 --- a/app/src/main/cpp/Device.h +++ b/app/src/main/cpp/Device.h @@ -22,6 +22,7 @@ const CapabilityFlags PositionEmulated = 1u << 9u; const CapabilityFlags InlineSession = 1u << 10u; const CapabilityFlags ImmersiveVRSession = 1u << 11u; const CapabilityFlags ImmersiveARSession = 1u << 12u; +const CapabilityFlags GripSpacePosition = 1u << 13u; enum class Eye { Left, Right }; enum class RenderMode { StandAlone, Immersive }; enum class CPULevel { Normal = 0, High }; @@ -32,6 +33,31 @@ typedef int32_t DeviceType; const DeviceType UnknownType = 0; const DeviceType OculusGo = 1; const DeviceType OculusQuest = 2; +const DeviceType ViveFocus = 3; +const DeviceType ViveFocusPlus = 4; +const DeviceType PicoGaze = 5; +const DeviceType PicoNeo2 = 6; +const DeviceType PicoG2 = 7; + +enum class TargetRayMode : uint8_t { Gaze, TrackedPointer, Screen }; + +// Placeholder buttons for WebXR +// https://www.w3.org/TR/webxr-gamepads-module-1/#xr-standard-gamepad-mapping +const uint8_t kImmersiveButtonTrigger = 0; +const uint8_t kImmersiveButtonSqueeze = 1; +const uint8_t kImmersiveButtonTouchpad = 2; +const uint8_t kImmersiveButtonThumbstick = 3; +const uint8_t kImmersiveButtonA = 4; +const uint8_t kImmersiveButtonB = 5; +const uint8_t kImmersiveButtonThumbrest = 6; + +// Placeholder axes for WebXR +// https://www.w3.org/TR/webxr-gamepads-module-1/#xr-standard-gamepad-mapping +const uint8_t kImmersiveAxisTouchpadX = 0; +const uint8_t kImmersiveAxisTouchpadY = 1; +const uint8_t kImmersiveAxisThumbstickX = 2; +const uint8_t kImmersiveAxisThumbstickY = 3; + struct EyeRect { float mX, mY; float mWidth, mHeight; diff --git a/app/src/main/cpp/ExternalVR.cpp b/app/src/main/cpp/ExternalVR.cpp index 8dbedd8a4..a72f7e2d0 100644 --- a/app/src/main/cpp/ExternalVR.cpp +++ b/app/src/main/cpp/ExternalVR.cpp @@ -207,6 +207,40 @@ struct ExternalVR::State { ExternalVR::State * ExternalVR::State::sState = nullptr; +mozilla::gfx::VRControllerType GetVRControllerTypeByDevice(device::DeviceType aType) { + mozilla::gfx::VRControllerType result = mozilla::gfx::VRControllerType::_empty; + + switch (aType) { + case device::OculusGo: + result = mozilla::gfx::VRControllerType::OculusGo; + break; + case device::OculusQuest: + result = mozilla::gfx::VRControllerType::OculusTouch2; + break; + case device::ViveFocus: + result = mozilla::gfx::VRControllerType::HTCViveFocus; + break; + case device::ViveFocusPlus: + result = mozilla::gfx::VRControllerType::HTCViveFocusPlus; + break; + case device::PicoGaze: + result = mozilla::gfx::VRControllerType::PicoGaze; + break; + case device::PicoNeo2: + result = mozilla::gfx::VRControllerType::PicoNeo2; + break; + case device::PicoG2: + result = mozilla::gfx::VRControllerType::PicoG2; + break; + case device::UnknownType: + default: + result = mozilla::gfx::VRControllerType::_empty; + VRB_LOG("Unknown controller type."); + break; + } + return result; +} + ExternalVRPtr ExternalVR::Create() { return std::make_shared(); @@ -332,6 +366,11 @@ ExternalVR::SetSourceBrowser(VRBrowserType aBrowser) { m.SetSourceBrowser(aBrowser); } +uint64_t +ExternalVR::GetFrameId() const { + return m.lastFrameId; +} + void ExternalVR::SetCompositorEnabled(bool aEnabled) { if (aEnabled == m.compositorEnabled) { @@ -372,6 +411,12 @@ ExternalVR::GetControllerCapabilityFlags(device::CapabilityFlags aFlags) { if (device::LinearAcceleration & aFlags) { result |= static_cast(mozilla::gfx::ControllerCapabilityFlags::Cap_LinearAcceleration); } + if (device::PositionEmulated & aFlags) { + result |= static_cast(mozilla::gfx::ControllerCapabilityFlags::Cap_PositionEmulated); + } + if (device::GripSpacePosition & aFlags) { + result |= static_cast(mozilla::gfx::ControllerCapabilityFlags::Cap_GripSpacePosition); + } return result; } @@ -429,23 +474,44 @@ ExternalVR::PushFramePoses(const vrb::Matrix& aHeadTransform, const std::vector< } immersiveController.numHaptics = controller.numHaptics; immersiveController.hand = controller.leftHanded ? mozilla::gfx::ControllerHand::Left : mozilla::gfx::ControllerHand::Right; + immersiveController.type = GetVRControllerTypeByDevice(controller.type); const uint16_t flags = GetControllerCapabilityFlags(controller.deviceCapabilities); immersiveController.flags = static_cast(flags); - + const vrb::Matrix beamTransform = controller.transformMatrix.PostMultiply(controller.immersiveBeamTransform); if (flags & static_cast(mozilla::gfx::ControllerCapabilityFlags::Cap_Orientation)) { immersiveController.isOrientationValid = true; - vrb::Quaternion quaternion(controller.transformMatrix); - quaternion = quaternion.Inverse(); - memcpy(&(immersiveController.pose.orientation), quaternion.Data(), sizeof(immersiveController.pose.orientation)); + vrb::Quaternion rotate; + if (flags & static_cast(mozilla::gfx::ControllerCapabilityFlags::Cap_GripSpacePosition)) { + rotate = controller.transformMatrix; + rotate = rotate.Inverse(); + memcpy(&(immersiveController.pose.orientation), rotate.Data(), sizeof(immersiveController.pose.orientation)); + } + rotate.SetFromRotationMatrix(beamTransform); + rotate = rotate.Inverse(); + memcpy(&(immersiveController.targetRayPose.orientation), rotate.Data(), sizeof(immersiveController.targetRayPose.orientation)); } - if (flags & static_cast(mozilla::gfx::ControllerCapabilityFlags::Cap_Position)) { + if (flags & static_cast(mozilla::gfx::ControllerCapabilityFlags::Cap_Position) || + flags & static_cast(mozilla::gfx::ControllerCapabilityFlags::Cap_PositionEmulated)) { immersiveController.isPositionValid = true; - vrb::Vector position(controller.transformMatrix.GetTranslation()); - memcpy(&(immersiveController.pose.position), position.Data(), sizeof(immersiveController.pose.position)); + vrb::Vector position; + if (flags & static_cast(mozilla::gfx::ControllerCapabilityFlags::Cap_GripSpacePosition)) { + position = controller.transformMatrix.GetTranslation(); + memcpy(&(immersiveController.pose.position), position.Data(), sizeof(immersiveController.pose.position)); + } + position = beamTransform.GetTranslation(); + memcpy(&(immersiveController.targetRayPose.position), position.Data(), sizeof(immersiveController.targetRayPose.position)); } + // TODO:: We should add TargetRayMode::_end in moz_external_vr.h to help this check. + assert((uint8_t)mozilla::gfx::TargetRayMode::Screen == (uint8_t)device::TargetRayMode::Screen); + immersiveController.targetRayMode = (mozilla::gfx::TargetRayMode)controller.targetRayMode; + immersiveController.mappingType = mozilla::gfx::GamepadMappingType::XRStandard; + immersiveController.selectActionStartFrameId = controller.selectActionStartFrameId; + immersiveController.selectActionStopFrameId = controller.selectActionStopFrameId; + immersiveController.squeezeActionStartFrameId = controller.squeezeActionStartFrameId; + immersiveController.squeezeActionStopFrameId = controller.squeezeActionStopFrameId; } m.system.sensorState.timestamp = aTimestamp; diff --git a/app/src/main/cpp/ExternalVR.h b/app/src/main/cpp/ExternalVR.h index 8f1cf7301..78d82dee5 100644 --- a/app/src/main/cpp/ExternalVR.h +++ b/app/src/main/cpp/ExternalVR.h @@ -66,6 +66,7 @@ class ExternalVR : public ImmersiveDisplay { void SetSourceBrowser(VRBrowserType aBrowser); void OnPause(); void OnResume(); + uint64_t GetFrameId() const; ExternalVR(); ~ExternalVR() = default; protected: diff --git a/app/src/main/cpp/moz_external_vr.h b/app/src/main/cpp/moz_external_vr.h index 6096ee538..a86a5c8f6 100644 --- a/app/src/main/cpp/moz_external_vr.h +++ b/app/src/main/cpp/moz_external_vr.h @@ -47,8 +47,8 @@ namespace gfx { // and mapped files if we have both release and nightlies // running at the same time? Or...what if we have multiple // release builds running on same machine? (Bug 1563232) -#define SHMEM_VERSION "0.0.8" -static const int32_t kVRExternalVersion = 15; +#define SHMEM_VERSION "0.0.10" +static const int32_t kVRExternalVersion = 17; // We assign VR presentations to groups with a bitmask. // Currently, we will only display either content or chrome. @@ -63,7 +63,6 @@ static const uint32_t kVRGroupAll = 0xffffffff; static const int kVRDisplayNameMaxLen = 256; static const int kVRControllerNameMaxLen = 256; -static const int kProfileNameListMaxLen = 256; static const int kVRControllerMaxCount = 16; static const int kVRControllerMaxButtons = 64; static const int kVRControllerMaxAxis = 16; @@ -120,24 +119,37 @@ enum class ControllerCapabilityFlags : uint16_t { */ Cap_LinearAcceleration = 1 << 4, /** - * Cap_GripSpacePosition is set if the Gamepad has a grip space position. + * Cap_TargetRaySpacePosition is set if the Gamepad has a grip space position. */ Cap_GripSpacePosition = 1 << 5, + /** + * Cap_PositionEmulated is set if the XRInputSoruce is capable of setting a + * emulated position (e.g. neck model) even if still doesn't support 6DOF + * tracking. + */ + Cap_PositionEmulated = 1 << 6, /** * Cap_All used for validity checking during IPC serialization */ - Cap_All = (1 << 6) - 1 + Cap_All = (1 << 7) - 1 }; #endif // ifndef MOZILLA_INTERNAL_API enum class VRControllerType : uint8_t { _empty, - Vive, - WMR, - Knuckles, - Cosmos, + HTCVive, + HTCViveCosmos, + HTCViveFocus, + HTCViveFocusPlus, + MSMR, + ValveIndex, + OculusGo, OculusTouch, + OculusTouch2, + PicoGaze, + PicoG2, + PicoNeo2, _end }; @@ -217,10 +229,17 @@ enum class VRDisplayCapabilityFlags : uint16_t { * the user's environment. */ Cap_ImmersiveAR = 1 << 12, + /** + * Cap_UseDepthValues is set if the device will use the depth values of the + * submitted frames if provided. How the depth values are used is determined + * by the VR runtime. Often the depth is used for occlusion of system UI + * or to enable more effective asynchronous reprojection of frames. + */ + Cap_UseDepthValues = 1 << 13, /** * Cap_All used for validity checking during IPC serialization */ - Cap_All = (1 << 13) - 1 + Cap_All = (1 << 14) - 1 }; #ifdef MOZILLA_INTERNAL_API @@ -357,11 +376,6 @@ struct VRControllerState { // https://immersive-web.github.io/webxr/#enumdef-xrtargetraymode TargetRayMode targetRayMode; - // Space-delimited list of input profile names, in decending order - // of specificity. - // https://immersive-web.github.io/webxr/#dom-xrinputsource-profiles - char profiles[kProfileNameListMaxLen]; - // https://immersive-web.github.io/webxr-gamepads-module/#enumdef-gamepadmappingtype GamepadMappingType mappingType; @@ -402,14 +416,14 @@ struct VRControllerState { #endif // When Cap_Position is set in flags, pose corresponds - // to the controllers' pose in target ray space: - // https://immersive-web.github.io/webxr/#dom-xrinputsource-targetrayspace - VRPose pose; - - // When Cap_GripSpacePosition is set in flags, gripPose corresponds // to the controllers' pose in grip space: // https://immersive-web.github.io/webxr/#dom-xrinputsource-gripspace - VRPose gripPose; + VRPose pose; + + // When Cap_TargetRaySpacePosition is set in flags, targetRayPose corresponds + // to the controllers' pose in target ray space: + // https://immersive-web.github.io/webxr/#dom-xrinputsource-targetrayspace + VRPose targetRayPose; bool isPositionValid; bool isOrientationValid; diff --git a/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp b/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp index 46dd0f151..156ba4ff3 100644 --- a/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp +++ b/app/src/oculusvr/cpp/DeviceDelegateOculusVR.cpp @@ -379,15 +379,26 @@ struct DeviceDelegateOculusVR::State { } controller->CreateController(controllerState.index, int32_t(controllerState.hand), controllerName, beamTransform); - controller->SetButtonCount(controllerState.index, 6); + controller->SetButtonCount(controllerState.index, 7); controller->SetHapticCount(controllerState.index, 1); + controller->SetControllerType(controllerState.index, device::OculusQuest); + + const vrb::Matrix trans = vrb::Matrix::Position(vrb::Vector(0.0f, 0.02f, -0.03f)); + vrb::Matrix transform = vrb::Matrix::Rotation(vrb::Vector(1.0f, 0.0f, 0.0f), -0.77f); + transform = transform.PostMultiply(trans); + + controller->SetImmersiveBeamTransform(controllerState.index, beamTransform.PostMultiply(transform)); } else { // Oculus Go only has one kind of controller model. controller->CreateController(controllerState.index, 0, "Oculus Go Controller"); - controller->SetButtonCount(controllerState.index, 2); + // Although Go only has two buttons, in order to match WebXR input profile (squeeze placeholder), + // we make Go has three buttons. + controller->SetButtonCount(controllerState.index, 3); // Oculus Go has no haptic feedback. controller->SetHapticCount(controllerState.index, 0); + controller->SetControllerType(controllerState.index, device::OculusGo); } + controller->SetTargetRayMode(controllerState.index, device::TargetRayMode::TrackedPointer); controllerState.created = true; } } @@ -437,19 +448,28 @@ struct DeviceDelegateOculusVR::State { flags |= device::Position; } else { controllerState.transform = elbow->GetTransform(controllerState.hand, head, controllerState.transform); + flags |= device::PositionEmulated; } + flags |= device::GripSpacePosition; controller->SetCapabilityFlags(controllerState.index, flags); + if (renderMode == device::RenderMode::Immersive && controllerState.Is6DOF()) { + static vrb::Matrix transform(vrb::Matrix::Identity()); + if (transform.IsIdentity()) { + transform = vrb::Matrix::Rotation(vrb::Vector(1.0f, 0.0f, 0.0f), 0.77f); + const vrb::Matrix trans = vrb::Matrix::Position(vrb::Vector(0.0f, 0.0f, 0.025f)); + transform = transform.PostMultiply(trans); + } + controllerState.transform = controllerState.transform.PostMultiply(transform); + } controller->SetTransform(controllerState.index, controllerState.transform); controllerState.inputState.Header.ControllerType = ovrControllerType_TrackedRemote; vrapi_GetCurrentInputState(ovr, controllerState.deviceId, &controllerState.inputState.Header); reorientCount = controllerState.inputState.RecenterCount; - const int32_t kNumAxes = 2; bool triggerPressed = false, triggerTouched = false; bool trackpadPressed = false, trackpadTouched = false; - float axes[kNumAxes]; float trackpadX = 0.0f, trackpadY = 0.0f; if (controllerState.Is6DOF()) { triggerPressed = (controllerState.inputState.Buttons & ovrButton_Trigger) != 0; @@ -458,13 +478,16 @@ struct DeviceDelegateOculusVR::State { trackpadTouched = (controllerState.inputState.Touches & ovrTouch_Joystick) != 0; trackpadX = controllerState.inputState.Joystick.x; trackpadY = controllerState.inputState.Joystick.y; - axes[0] = trackpadX; - axes[1] = -trackpadY; // We did y axis intentionally inverted in FF desktop as well. + const int32_t kNumAxes = 4; + float axes[kNumAxes]; + axes[device::kImmersiveAxisTouchpadX] = axes[device::kImmersiveAxisTouchpadY] = 0.0f; + axes[device::kImmersiveAxisThumbstickX] = trackpadX; + axes[device::kImmersiveAxisThumbstickY] = -trackpadY; // We did y axis intentionally inverted in FF desktop as well. controller->SetScrolledDelta(controllerState.index, -trackpadX, trackpadY); const bool gripPressed = (controllerState.inputState.Buttons & ovrButton_GripTrigger) != 0; - controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_OTHERS, 2, gripPressed, gripPressed, - controllerState.inputState.GripTrigger); + controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_SQUEEZE, device::kImmersiveButtonSqueeze, + gripPressed, gripPressed, controllerState.inputState.GripTrigger); if (controllerState.hand == ElbowModel::HandEnum::Left) { const bool xPressed = (controllerState.inputState.Buttons & ovrButton_X) != 0; const bool xTouched = (controllerState.inputState.Touches & ovrTouch_X) != 0; @@ -472,8 +495,8 @@ struct DeviceDelegateOculusVR::State { const bool yTouched = (controllerState.inputState.Touches & ovrTouch_Y) != 0; const bool menuPressed = (controllerState.inputState.Buttons & ovrButton_Enter) != 0; - controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_X, 3, xPressed, xTouched); - controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_Y, 4, yPressed, yTouched); + controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_X, device::kImmersiveButtonA, xPressed, xTouched); + controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_Y, device::kImmersiveButtonB, yPressed, yTouched); if (renderMode != device::RenderMode::Immersive) { controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_APP, -1, yPressed, yTouched); @@ -486,8 +509,8 @@ struct DeviceDelegateOculusVR::State { const bool bPressed = (controllerState.inputState.Buttons & ovrButton_B) != 0; const bool bTouched = (controllerState.inputState.Touches & ovrTouch_B) != 0; - controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_A, 3, aPressed, aTouched); - controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_B, 4, bPressed, bTouched); + controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_A, device::kImmersiveButtonA, aPressed, aTouched); + controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_B, device::kImmersiveButtonB, bPressed, bTouched); if (renderMode != device::RenderMode::Immersive) { controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_APP, -1, bPressed, bTouched); @@ -495,6 +518,18 @@ struct DeviceDelegateOculusVR::State { } else { VRB_WARN("Undefined hand type in DeviceDelegateOculusVR."); } + controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_TOUCHPAD, + device::kImmersiveButtonThumbstick, trackpadPressed, trackpadTouched); + // This is always false in Oculus Browser. + const bool thumbRest = false; + controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_OTHERS, device::kImmersiveButtonThumbrest, thumbRest, thumbRest); + + if (gripPressed && renderMode == device::RenderMode::Immersive) { + controller->SetSqueezeActionStart(controllerState.index); + } else { + controller->SetSqueezeActionStop(controllerState.index); + } + controller->SetAxes(controllerState.index, axes, kNumAxes); } else { triggerPressed = (controllerState.inputState.Buttons & ovrButton_A) != 0; triggerTouched = triggerPressed; @@ -510,20 +545,29 @@ struct DeviceDelegateOculusVR::State { trackpadX = controllerState.inputState.TrackpadPosition.x / (float)controllerState.capabilities.TrackpadMaxX; trackpadY = controllerState.inputState.TrackpadPosition.y / (float)controllerState.capabilities.TrackpadMaxY; + controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_TOUCHPAD, + device::kImmersiveButtonTouchpad, trackpadPressed, trackpadTouched); if (trackpadTouched && !trackpadPressed) { controller->SetTouchPosition(controllerState.index, trackpadX, trackpadY); } else { controller->SetTouchPosition(controllerState.index, trackpadX, trackpadY); controller->EndTouch(controllerState.index); } - axes[0] = trackpadTouched ? trackpadX * 2.0f - 1.0f : 0.0f; - axes[1] = trackpadTouched ? trackpadY * 2.0f - 1.0f : 0.0f; + const int32_t kNumAxes = 2; + float axes[kNumAxes]; + axes[device::kImmersiveAxisTouchpadX] = trackpadTouched ? trackpadX * 2.0f - 1.0f : 0.0f; + axes[device::kImmersiveAxisTouchpadY] = trackpadTouched ? trackpadY * 2.0f - 1.0f : 0.0f; + controller->SetAxes(controllerState.index, axes, kNumAxes); } - controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_TRIGGER, 1, triggerPressed, triggerTouched, + controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_TRIGGER, + device::kImmersiveButtonTrigger, triggerPressed, triggerTouched, controllerState.inputState.IndexTrigger); - controller->SetButtonState(controllerState.index, ControllerDelegate::BUTTON_TOUCHPAD, 0, trackpadPressed, trackpadTouched); - controller->SetAxes(controllerState.index, axes, kNumAxes); + if (triggerPressed && renderMode == device::RenderMode::Immersive) { + controller->SetSelectActionStart(controllerState.index); + } else { + controller->SetSelectActionStop(controllerState.index); + } if (controller->GetHapticCount(controllerState.index)) { UpdateHaptics(controllerState); } @@ -921,10 +965,10 @@ DeviceDelegateOculusVR::StartFrame(const FramePrediction aPrediction) { if (m.immersiveDisplay) { m.immersiveDisplay->SetEyeOffset(device::Eye::Left, -ipd * 0.5f, 0.f, 0.f); m.immersiveDisplay->SetEyeOffset(device::Eye::Right, ipd * 0.5f, 0.f, 0.f); - device::CapabilityFlags caps = device::Orientation | device::Present | device::StageParameters | + device::CapabilityFlags caps = device::Orientation | device::Present | device::InlineSession | device::ImmersiveVRSession; if (m.predictedTracking.Status & VRAPI_TRACKING_STATUS_POSITION_TRACKED) { - caps |= device::Position; + caps |= device::Position | device::StageParameters; auto standing = vrapi_LocateTrackingSpace(m.ovr, VRAPI_TRACKING_SPACE_LOCAL_FLOOR); vrb::Vector translation(-standing.Position.x, -standing.Position.y, -standing.Position.z); m.immersiveDisplay->SetSittingToStandingTransform(vrb::Matrix::Translation(translation)); diff --git a/app/src/picovr/cpp/DeviceDelegatePicoVR.cpp b/app/src/picovr/cpp/DeviceDelegatePicoVR.cpp index dc8db40b6..108beecf1 100644 --- a/app/src/picovr/cpp/DeviceDelegatePicoVR.cpp +++ b/app/src/picovr/cpp/DeviceDelegatePicoVR.cpp @@ -32,10 +32,9 @@ static const vrb::Vector kAverageHeight(0.0f, 1.7f, 0.0f); static const vrb::Vector kAverageSittingToStanding(0.0f, 1.2f, 0.0f); // TODO: support different controllers & buttons static const int32_t kMaxControllerCount = 3; -static const int32_t kNumButtons = 6; -static const int32_t kNumG2Buttons = 2; -static const int32_t kNumGazeButtons = 2; -static const int32_t kNumAxes = 2; +static const int32_t kNumButtons = 7; +static const int32_t kNumG2Buttons = 3; +static const int32_t kNumGazeButtons = 1; static const int32_t k6DofHeadSet = 1; static const int32_t kButtonApp = 1; static const int32_t kButtonTrigger = 1 << 1; @@ -171,7 +170,10 @@ struct DeviceDelegatePicoVR::State { device::CapabilityFlags flags = device::Orientation; if (controller.is6DoF) { flags |= device::Position; + } else { + flags |= device::PositionEmulated; } + flags |= device::GripSpacePosition; controllerDelegate->SetCapabilityFlags(i, flags); const bool appPressed = (controller.buttonsState & kButtonApp) > 0; const bool triggerPressed = (controller.buttonsState & kButtonTrigger) > 0; @@ -182,33 +184,48 @@ struct DeviceDelegatePicoVR::State { controllerDelegate->SetButtonState(i, ControllerDelegate::BUTTON_APP, -1, appPressed, appPressed); - controllerDelegate->SetButtonState(i, ControllerDelegate::BUTTON_TOUCHPAD, 0, touchPadPressed, - touchPadPressed); - controllerDelegate->SetButtonState(i, ControllerDelegate::BUTTON_TRIGGER, 1, triggerPressed, + controllerDelegate->SetButtonState(i, ControllerDelegate::BUTTON_TOUCHPAD, type == k6DofHeadSet ? + device::kImmersiveButtonThumbstick : device::kImmersiveButtonTouchpad, touchPadPressed, touchPadPressed); + controllerDelegate->SetButtonState(i, ControllerDelegate::BUTTON_TRIGGER, device::kImmersiveButtonTrigger, triggerPressed, triggerPressed); + if (triggerPressed && renderMode == device::RenderMode::Immersive) { + controllerDelegate->SetSelectActionStart(i); + } else { + controllerDelegate->SetSelectActionStop(i); + } if (type == k6DofHeadSet) { - controllerDelegate->SetButtonState(i, ControllerDelegate::BUTTON_OTHERS, 2, gripPressed, + controllerDelegate->SetButtonState(i, ControllerDelegate::BUTTON_SQUEEZE, device::kImmersiveButtonSqueeze, gripPressed, gripPressed, gripPressed ? 20.0f : 0.0f); + if (gripPressed && renderMode == device::RenderMode::Immersive) { + controllerDelegate->SetSqueezeActionStart(i); + } else { + controllerDelegate->SetSqueezeActionStop(i); + } controllerDelegate->SetButtonState(i, (controller.IsRightHand() ? ControllerDelegate::BUTTON_A : ControllerDelegate::BUTTON_X), - 3, axPressed, axPressed); + device::kImmersiveButtonA, axPressed, axPressed); controllerDelegate->SetButtonState(i, (controller.IsRightHand() ? ControllerDelegate::BUTTON_B : ControllerDelegate::BUTTON_Y), - 4, byPressed, byPressed); - controllerDelegate->SetButtonState(i, ControllerDelegate::BUTTON_OTHERS, 5, false, false); - } - - float axes[kNumAxes] = { controller.axisX , -controller.axisY }; - controllerDelegate->SetAxes(i, axes, kNumAxes); + device::kImmersiveButtonB, byPressed, byPressed); + controllerDelegate->SetButtonState(i, ControllerDelegate::BUTTON_OTHERS, device::kImmersiveButtonThumbrest, false, false); + const int32_t kNumAxes = 4; + float axes[kNumAxes]; + axes[device::kImmersiveAxisTouchpadX] = axes[device::kImmersiveAxisTouchpadY] = 0.0f; + axes[device::kImmersiveAxisThumbstickX] = controller.axisX; + axes[device::kImmersiveAxisThumbstickY] = -controller.axisY; + controllerDelegate->SetAxes(i, axes, controller.index != GazeModeIndex() ? kNumAxes : 0); - if (type == k6DofHeadSet) { if (!triggerPressed) { controllerDelegate->SetScrolledDelta(i, -controller.axisX, controller.axisY); } } else { + const int32_t kNumAxes = 2; + float axes[kNumAxes] = { controller.axisX , -controller.axisY }; + controllerDelegate->SetAxes(i, axes, controller.index != GazeModeIndex() ? kNumAxes : 0); + if (controller.touched) { controllerDelegate->SetTouchPosition(i, controller.axisX, controller.axisY); } else { @@ -217,14 +234,20 @@ struct DeviceDelegatePicoVR::State { } vrb::Matrix transform = controller.transform; - if ((renderMode == device::RenderMode::StandAlone) && (i != gazeIndex)) { - if (type == k6DofHeadSet) { - transform.TranslateInPlace(headOffset); - } else { - vrb::Matrix head = vrb::Matrix::Rotation(orientation); - head.PreMultiplyInPlace(vrb::Matrix::Position(headOffset)); - transform = elbow->GetTransform(controller.hand, head, transform); - } + if (i != gazeIndex) { + if (renderMode == device::RenderMode::StandAlone) { + if (type == k6DofHeadSet) { + transform.TranslateInPlace(headOffset); + } else { + vrb::Matrix head = vrb::Matrix::Rotation(orientation); + head.PreMultiplyInPlace(vrb::Matrix::Position(headOffset)); + transform = elbow->GetTransform(controller.hand, head, transform); + } + } + else if (type != k6DofHeadSet) { + vrb::Matrix head = vrb::Matrix::Rotation(orientation); + transform = elbow->GetTransform(controller.hand, head, transform); + } } controllerDelegate->SetTransform(i, transform); @@ -279,8 +302,11 @@ DeviceDelegatePicoVR::RegisterImmersiveDisplay(ImmersiveDisplayPtr aDisplay) { device::ImmersiveVRSession | device::InlineSession; if (m.type == k6DofHeadSet) { flags |= device::Position | device::StageParameters; + m.immersiveDisplay->SetSittingToStandingTransform(vrb::Matrix::Translation(kAverageSittingToStanding)); + } else { + flags |= device::PositionEmulated; + m.immersiveDisplay->SetSittingToStandingTransform(vrb::Matrix::Translation(kAverageHeight)); } - m.immersiveDisplay->SetSittingToStandingTransform(vrb::Matrix::Translation(kAverageSittingToStanding)); m.immersiveDisplay->SetCapabilityFlags(flags); m.immersiveDisplay->SetEyeResolution(m.renderWidth / 2, m.renderHeight / 2); m.immersiveDisplay->CompleteEnumeration(); @@ -331,7 +357,8 @@ DeviceDelegatePicoVR::SetControllerDelegate(ControllerDelegatePtr& aController) m.controllerDelegate->CreateController(index, 0, "Pico Gaze Controller", beam); m.controllerDelegate->SetButtonCount(index, kNumGazeButtons); m.controllerDelegate->SetHapticCount(index, 0); - + m.controllerDelegate->SetControllerType(index, device::PicoGaze); + m.controllerDelegate->SetTargetRayMode(index, device::TargetRayMode::Gaze); } else { if (m.type == k6DofHeadSet) { vrb::Matrix beam = vrb::Matrix::Rotation(vrb::Vector(1.0f, 0.0f, 0.0f), -vrb::PI_FLOAT / 11.5f); @@ -339,11 +366,15 @@ DeviceDelegatePicoVR::SetControllerDelegate(ControllerDelegatePtr& aController) m.controllerDelegate->CreateController(index, int32_t(controller.hand), controller.IsRightHand() ? "Pico Neo 2 (Right)" : "Pico Neo 2 (LEFT)", beam); m.controllerDelegate->SetButtonCount(index, kNumButtons); m.controllerDelegate->SetHapticCount(index, 1); + m.controllerDelegate->SetControllerType(index, device::PicoNeo2); + m.controllerDelegate->SetTargetRayMode(index, device::TargetRayMode::TrackedPointer); } else { vrb::Matrix beam = vrb::Matrix::Rotation(vrb::Vector(1.0f, 0.0f, 0.0f), -vrb::PI_FLOAT / 11.5f); m.controllerDelegate->CreateController(index, 0, "Pico G2 Controller", beam); m.controllerDelegate->SetButtonCount(index, kNumG2Buttons); m.controllerDelegate->SetHapticCount(index, 0); + m.controllerDelegate->SetControllerType(index, device::PicoG2); + m.controllerDelegate->SetTargetRayMode(index, device::TargetRayMode::TrackedPointer); } } controller.created = true; diff --git a/app/src/wavevr/cpp/DeviceDelegateWaveVR.cpp b/app/src/wavevr/cpp/DeviceDelegateWaveVR.cpp index 3c54b11f4..d7ef518a8 100644 --- a/app/src/wavevr/cpp/DeviceDelegateWaveVR.cpp +++ b/app/src/wavevr/cpp/DeviceDelegateWaveVR.cpp @@ -245,13 +245,26 @@ struct DeviceDelegateWaveVR::State { VRB_ERROR("Failed to create controller. No ControllerDelegate has been set."); return; } - vrb::Matrix transform(vrb::Matrix::Identity()); + vrb::Matrix beamTransform(vrb::Matrix::Identity()); if (aController.is6DoF) { - transform.TranslateInPlace(vrb::Vector(0.0f, 0.01f, -0.05f)); + beamTransform.TranslateInPlace(vrb::Vector(0.0f, 0.01f, -0.05f)); } - delegate->CreateController(aController.index, aController.is6DoF ? 1 : 0, aController.is6DoF ? "HTC Vive Focus Plus Controller" : "HTC Vive Focus Controller", transform); + delegate->CreateController(aController.index, aController.is6DoF ? 1 : 0, + aController.is6DoF ? "HTC Vive Focus Plus Controller" : "HTC Vive Focus Controller", + beamTransform); delegate->SetLeftHanded(aController.index, aController.hand == ElbowModel::HandEnum::Left); delegate->SetHapticCount(aController.index, 1); + delegate->SetControllerType(aController.index, aController.is6DoF ? device::ViveFocusPlus : + device::ViveFocus); + delegate->SetTargetRayMode(aController.index, device::TargetRayMode::TrackedPointer); + + if (aController.is6DoF) { + const vrb::Matrix trans = vrb::Matrix::Position(vrb::Vector(0.0f, -0.021f, -0.03f)); + vrb::Matrix transform = vrb::Matrix::Rotation(vrb::Vector(1.0f, 0.0f, 0.0f), -0.70f); + transform = transform.PostMultiply(trans); + + delegate->SetImmersiveBeamTransform(aController.index, beamTransform.PostMultiply(transform)); + } aController.created = true; aController.enabled = false; } @@ -284,9 +297,11 @@ struct DeviceDelegateWaveVR::State { } continue; } else if (!controller.enabled) { - device::CapabilityFlags flags = device::Orientation; + device::CapabilityFlags flags = device::Orientation | device::GripSpacePosition; if (controller.is6DoF) { flags |= device::Position; + } else { + flags |= device::PositionEmulated; } controller.enabled = true; delegate->SetEnabled(controller.index, true); @@ -296,15 +311,17 @@ struct DeviceDelegateWaveVR::State { delegate->SetVisible(controller.index, !WVR_IsInputFocusCapturedBySystem()); - const bool bumperPressed = (controller.is6DoF) ? WVR_GetInputButtonState(controller.type, WVR_InputId_Alias1_Trigger) + const bool bumperPressed = (controller.is6DoF) ? WVR_GetInputButtonState(controller.type, WVR_InputId_Alias1_Trigger) : WVR_GetInputButtonState(controller.type, WVR_InputId_Alias1_Digital_Trigger); const bool touchpadPressed = WVR_GetInputButtonState(controller.type, WVR_InputId_Alias1_Touchpad); const bool touchpadTouched = WVR_GetInputTouchState(controller.type, WVR_InputId_Alias1_Touchpad); const bool menuPressed = WVR_GetInputButtonState(controller.type, WVR_InputId_Alias1_Menu); - delegate->SetButtonCount(controller.index, controller.is6DoF ? 3 : 2); // For immersive mode - delegate->SetButtonState(controller.index, ControllerDelegate::BUTTON_TOUCHPAD, 0, touchpadPressed, touchpadTouched); - delegate->SetButtonState(controller.index, ControllerDelegate::BUTTON_TRIGGER, 1, bumperPressed, bumperPressed); + // Although Focus only has two buttons, in order to match WebXR input profile (squeeze placeholder), + // we make Focus has three buttons. + delegate->SetButtonCount(controller.index, 3); + delegate->SetButtonState(controller.index, ControllerDelegate::BUTTON_TOUCHPAD, device::kImmersiveButtonTouchpad, touchpadPressed, touchpadTouched); + delegate->SetButtonState(controller.index, ControllerDelegate::BUTTON_TRIGGER, device::kImmersiveButtonTrigger, bumperPressed, bumperPressed); if (controller.is6DoF) { const bool gripPressed = WVR_GetInputButtonState(controller.type, WVR_InputId_Alias1_Grip); if (renderMode == device::RenderMode::StandAlone) { @@ -320,12 +337,22 @@ struct DeviceDelegateWaveVR::State { controller.gripPressedCount = -1; } } else { - delegate->SetButtonState(controller.index, ControllerDelegate::BUTTON_OTHERS, 2, gripPressed, - gripPressed); + delegate->SetButtonState(controller.index, ControllerDelegate::BUTTON_SQUEEZE, device::kImmersiveButtonSqueeze, + gripPressed, gripPressed); controller.gripPressedCount = 0; } + if (gripPressed && renderMode == device::RenderMode::Immersive) { + delegate->SetSqueezeActionStart(controller.index); + } else { + delegate->SetSqueezeActionStop(controller.index); + } } + if (bumperPressed && renderMode == device::RenderMode::Immersive) { + delegate->SetSelectActionStart(controller.index); + } else { + delegate->SetSelectActionStop(controller.index); + } delegate->SetButtonState(controller.index, ControllerDelegate::BUTTON_APP, -1, menuPressed, menuPressed); const int32_t kNumAxes = 2; @@ -335,8 +362,8 @@ struct DeviceDelegateWaveVR::State { WVR_Axis_t axis = WVR_GetInputAnalogAxis(controller.type, WVR_InputId_Alias1_Touchpad); // We are matching touch pad range from {-1, 1} to the Oculus {0, 1}. delegate->SetTouchPosition(controller.index, (axis.x + 1) * 0.5, (-axis.y + 1) * 0.5); - immersiveAxes[0] = axis.x; - immersiveAxes[1] = -axis.y; + immersiveAxes[device::kImmersiveAxisTouchpadX] = axis.x; + immersiveAxes[device::kImmersiveAxisTouchpadY] = -axis.y; controller.touched = true; } else if (controller.touched) { controller.touched = false; @@ -463,11 +490,11 @@ DeviceDelegateWaveVR::RegisterImmersiveDisplay(ImmersiveDisplayPtr aDisplay) { } m.immersiveDisplay->SetDeviceName("Wave"); - device::CapabilityFlags flags = device::Orientation | device::Present | device::StageParameters | + device::CapabilityFlags flags = device::Orientation | device::Present | device::InlineSession | device::ImmersiveVRSession; if (WVR_GetDegreeOfFreedom(WVR_DeviceType_HMD) == WVR_NumDoF_6DoF) { - flags |= device::Position; + flags |= device::Position | device::StageParameters; } else { flags |= device::PositionEmulated; } @@ -778,6 +805,15 @@ DeviceDelegateWaveVR::StartFrame(const FramePrediction aPrediction) { } else if (m.renderMode == device::RenderMode::StandAlone) { controller.transform.TranslateInPlace(kAverageHeight); } + if (m.renderMode == device::RenderMode::Immersive && pose.is6DoFPose) { + static vrb::Matrix transform(vrb::Matrix::Identity()); + if (transform.IsIdentity()) { + transform = vrb::Matrix::Rotation(vrb::Vector(1.0f, 0.0f, 0.0f), 0.70f); + const vrb::Matrix trans = vrb::Matrix::Position(vrb::Vector(0.0f, 0.0f, -0.01f)); + transform = transform.PostMultiply(trans); + } + controller.transform = controller.transform.PostMultiply(transform); + } m.delegate->SetTransform(controller.index, controller.transform); } diff --git a/versions.gradle b/versions.gradle index 46e9573bc..11421af31 100644 --- a/versions.gradle +++ b/versions.gradle @@ -24,7 +24,7 @@ ext.deps = [:] def versions = [:] // GeckoView versions can be found here: // https://maven.mozilla.org/?prefix=maven2/org/mozilla/geckoview/ -versions.gecko_view = "76.0.20200330094747" +versions.gecko_view = "77.0.20200422093542" versions.android_components = "28.0.1" // Note that android-components also depends on application-services, // and in fact is our main source of appservices-related functionality.