Keep positioning active even when cursor is not on panel.

This commit is contained in:
amwatson 2024-03-20 23:10:57 -05:00
parent cff2dc7ffc
commit e486b927b2
2 changed files with 55 additions and 36 deletions

View file

@ -30,8 +30,8 @@ License : Licensed under GPLv3 or any later version.
namespace {
constexpr float kSuperImmersiveRadius = 0.5f;
constexpr float kSuperImmersiveRadius = 0.5f;
constexpr float kDistanceBetweenPanelsInMeters = 0.75f;
//-----------------------------------------------------------------------------
// Local sysprops
@ -124,7 +124,7 @@ Panel CreateTopPanel(const XrVector3f& position, const float surfaceWidth,
Panel CreateLowerPanelFromTopPanel(const Panel& topPanel, const float resolutionFactor) {
// Note: the fact that two constants are 0.75 is purely coincidental.
constexpr float kDefaultLowerPanelScaleFactor = 0.75f * 0.75f;
constexpr float kLowerPanelYOffsetInMeters = -0.75f;
constexpr float kLowerPanelYOffsetInMeters = -kDistanceBetweenPanelsInMeters;
constexpr float kLowerPanelZOffsetInMeters = -1.5f;
// Pitch the lower panel away from the viewer 45 degrees
constexpr float kLowerPanelPitchInRadians = -MATH_FLOAT_PI / 4.0f;
@ -420,8 +420,8 @@ bool GameSurfaceLayer::GetRayIntersectionWithPanel(const XrVector3f& start,
void GameSurfaceLayer::SetTopPanelFromController(const XrVector3f& controllerPosition) {
static constexpr XrVector3f viewerPosition{0, 0, 0}; // Set viewer position
const float sphereRadius = XrMath::Vector3f::Length(
mTopPanel.mPanelFromWorld.position - viewerPosition); // Set the initial distance of the
const float sphereRadius = XrMath::Vector3f::Length(
mTopPanel.mPanelFromWorld.position - viewerPosition); // Set the initial distance of the
// window from the viewer
static constexpr XrVector3f windowUpDirection{0, 1, 0}; // Y is up
@ -430,17 +430,21 @@ void GameSurfaceLayer::SetTopPanelFromController(const XrVector3f& controllerPos
CalculatePanelPosition(viewerPosition, controllerPosition, sphereRadius);
const XrQuaternionf windowRotation =
CalculatePanelRotation(windowPosition, viewerPosition, windowUpDirection);
if (windowPosition.y < 0) { return; }
if (windowPosition.y <
(mLowerPanel.mPanelFromWorld.position.y + kDistanceBetweenPanelsInMeters)) {
return;
}
if (XrMath::Quatf::GetYawInRadians(windowRotation) > MATH_FLOAT_PI / 3.0f) { return; }
mTopPanel.mPanelFromWorld = XrPosef{windowRotation, windowPosition};
}
void GameSurfaceLayer::SetTopPanelFromThumbstick(const float thumbstickY) {
static constexpr float kDepthSpeed = 0.05f;
static constexpr float kMaxDepth = -10.0f;
static constexpr float kThumbstickSpeed = 0.05f;
mTopPanel.mPanelFromWorld.position.z -= (thumbstickY * kDepthSpeed);
void GameSurfaceLayer::SetTopPanelFromThumbstick(const float thumbstickY) {
static constexpr float kMaxDepth = -10.0f;
mTopPanel.mPanelFromWorld.position.z -= (thumbstickY * kThumbstickSpeed);
mTopPanel.mPanelFromWorld.position.z =
std::min(mTopPanel.mPanelFromWorld.position.z, mLowerPanel.mPanelFromWorld.position.z);
mTopPanel.mPanelFromWorld.position.z =
@ -448,14 +452,14 @@ void GameSurfaceLayer::SetTopPanelFromThumbstick(const float thumbstickY) {
}
XrPosef GameSurfaceLayer::SetLowerPanelFromThumbstick(const float thumbstickY) {
static constexpr float kDepthSpeed = 0.05f;
static constexpr float kMaxDepth = -10.0f;
static constexpr float kMinY = -3.0f;
mLowerPanel.mPanelFromWorld.position.y += (thumbstickY * kDepthSpeed);
mLowerPanel.mPanelFromWorld.position.y += (thumbstickY * kThumbstickSpeed);
mLowerPanel.mPanelFromWorld.position.y =
std::min(mLowerPanel.mPanelFromWorld.position.y, mTopPanel.mPanelFromWorld.position.y);
std::min(mLowerPanel.mPanelFromWorld.position.y,
mTopPanel.mPanelFromWorld.position.y - kDistanceBetweenPanelsInMeters);
mLowerPanel.mPanelFromWorld.position.y =
std::max(mLowerPanel.mPanelFromWorld.position.y, kMaxDepth);
std::max(mLowerPanel.mPanelFromWorld.position.y, kMinY);
return mLowerPanel.mPanelFromWorld;
}

View file

@ -650,7 +650,10 @@ private:
XrPosef cursorPose3d = XrMath::Posef::Identity();
XrVector2f cursorPos2d = {0, 0};
float scaleFactor = 0.01f;
CursorLayer::CursorType cursorType = appState.mLowerMenuType == LowerMenuType::POSITIONAL_MENU ? CursorLayer::CursorType::CURSOR_TYPE_TOP_PANEL : CursorLayer::CursorType::CURSOR_TYPE_NORMAL;
CursorLayer::CursorType cursorType =
appState.mLowerMenuType == LowerMenuType::POSITIONAL_MENU
? CursorLayer::CursorType::CURSOR_TYPE_TOP_PANEL
: CursorLayer::CursorType::CURSOR_TYPE_NORMAL;
[[maybe_unused]] const auto nonPreferredController =
mInputStateFrame.mPreferredHand == InputStateFrame::LEFT_CONTROLLER
@ -660,10 +663,15 @@ private:
// unless neither controller is available.
assert(mInputStateFrame.mIsHandActive[mInputStateFrame.mPreferredHand] ||
!mInputStateFrame.mIsHandActive[nonPreferredController]);
{
const bool isPreferredControllerActive =
mInputStateFrame.mIsHandActive[mInputStateFrame.mPreferredHand];
static bool sIsLowerPanelBeingPositioned = false;
sIsLowerPanelBeingPositioned &=
appState.mLowerMenuType == LowerMenuType::POSITIONAL_MENU &&
isPreferredControllerActive;
if (isPreferredControllerActive) {
const XrPosef pose =
mInputStateFrame.mHandPositions[mInputStateFrame.mPreferredHand].pose;
@ -677,6 +685,8 @@ private:
mInputStateFrame.mHandPositions[mInputStateFrame.mPreferredHand].pose,
XrVector3f{0, 0, -3.5f});
sIsLowerPanelBeingPositioned &= triggerState.currentState > 0;
// Hit-test panels in order of priority (and known depth)
if (appState.mShouldShowErrorMessage) {
@ -696,6 +706,7 @@ private:
}
// No dialogs/popups that should impede normal cursor interaction with
// applicable panels
if (!shouldRenderCursor && appState.ShouldShowLowerPanel()) {
shouldRenderCursor = mGameSurfaceLayer->GetRayIntersectionWithPanel(
start, end, cursorPos2d, cursorPose3d);
@ -713,13 +724,14 @@ private:
cursorPos2d.x, cursorPos2d.y, 2);
}
}
if (!shouldRenderCursor) {
shouldRenderCursor = mRibbonLayer->GetRayIntersectionWithPanel(
start, end, cursorPos2d, cursorPose3d);
if (shouldRenderCursor && triggerState.changedSinceLastSync) {
mRibbonLayer->SendClickToUI(cursorPos2d, triggerState.currentState);
}
if (shouldRenderCursor &&
if ((shouldRenderCursor || sIsLowerPanelBeingPositioned) &&
appState.mLowerMenuType == LowerMenuType::POSITIONAL_MENU &&
triggerState.currentState) {
@ -730,28 +742,15 @@ private:
mInputStateFrame.mThumbStickState[mInputStateFrame.mPreferredHand];
if (std::abs(thumbstickState.currentState.y) >
kThumbStickDirectionThreshold) {
const XrPosef lowerPanelPose = mGameSurfaceLayer->SetLowerPanelFromThumbstick(
thumbstickState.currentState.y);
const XrPosef lowerPanelPose =
mGameSurfaceLayer->SetLowerPanelFromThumbstick(
thumbstickState.currentState.y);
mRibbonLayer->SetPanelWithPose(lowerPanelPose);
sIsLowerPanelBeingPositioned = true;
}
}
}
if (!shouldRenderCursor) {
// Handling this here means L2/R2 are liable to
// be slightly out of sync with the other
// buttons (which are handled before
// WaitFrame()). We'll see if that ends up being
// a problem for any games.
ForwardButtonStateIfNeeded(
jni, mActivityObject, mForwardVRInputMethodID, 104 /* BUTTON_L2 */,
mInputStateFrame.mIndexTriggerState[InputStateFrame::LEFT_CONTROLLER],
"l2");
ForwardButtonStateIfNeeded(
jni, mActivityObject, mForwardVRInputMethodID, 105 /* BUTTON_R2 */,
mInputStateFrame.mIndexTriggerState[InputStateFrame::RIGHT_CONTROLLER],
"r2");
}
if (sIsLowerPanelBeingPositioned) { shouldRenderCursor = true; }
// Hit test the top panel if positional menu is active.
if (!shouldRenderCursor &&
@ -779,6 +778,22 @@ private:
}
}
if (!shouldRenderCursor) {
// Handling this here means L2/R2 are liable to
// be slightly out of sync with the other
// buttons (which are handled before
// WaitFrame()). We'll see if that ends up being
// a problem for any games.
ForwardButtonStateIfNeeded(
jni, mActivityObject, mForwardVRInputMethodID, 104 /* BUTTON_L2 */,
mInputStateFrame.mIndexTriggerState[InputStateFrame::LEFT_CONTROLLER],
"l2");
ForwardButtonStateIfNeeded(
jni, mActivityObject, mForwardVRInputMethodID, 105 /* BUTTON_R2 */,
mInputStateFrame.mIndexTriggerState[InputStateFrame::RIGHT_CONTROLLER],
"r2");
}
// Add a scale factor so the cursor doesn't scale as
// quickly as the panel(s) with distance. This may be
// mildly unsettling, but it helps to ensure the cursor