diff --git a/org.mixedrealitytoolkit.input/CHANGELOG.md b/org.mixedrealitytoolkit.input/CHANGELOG.md index 7502b760c..f34c87afd 100644 --- a/org.mixedrealitytoolkit.input/CHANGELOG.md +++ b/org.mixedrealitytoolkit.input/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). * Added toggle for frame rate independent smoothing in camera simulation. [PR #1011](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1011) * Added implementation for the synthesized TriggerButton, accounting for animation smoothing. [PR #1043](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1043) * Added a "squeeze" alias for the grip states, to account for broader input action mapping support. [PR #1043](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1043) +* Added partial polyfill logic for one of "select" and "select value" being mapped while the other isn't, instead of fully polyfilling based on hand joint data when either is missing. [PR #1041](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/1041) ### Fixed diff --git a/org.mixedrealitytoolkit.input/Readers/PinchInputReader.cs b/org.mixedrealitytoolkit.input/Readers/PinchInputReader.cs index 32e638973..9a66568aa 100644 --- a/org.mixedrealitytoolkit.input/Readers/PinchInputReader.cs +++ b/org.mixedrealitytoolkit.input/Readers/PinchInputReader.cs @@ -29,7 +29,6 @@ public class PinchInputReader : MonoBehaviour, IXRInputButtonReader /// private struct FallbackState { - public bool hasPinchData; public bool isPerformed; public bool wasPerformedThisFrame; public bool wasCompletedThisFrame; @@ -167,10 +166,8 @@ public bool ReadIsPerformed() InputActionPhase phase = action.phase; return phase == InputActionPhase.Performed || (phase != InputActionPhase.Disabled && action.WasPerformedThisFrame()); } - else - { - return m_fallbackState.isPerformed; - } + + return m_fallbackState.isPerformed; } /// @@ -180,10 +177,8 @@ public bool ReadWasPerformedThisFrame() { return selectAction.action.WasPerformedThisFrame(); } - else - { - return m_fallbackState.wasPerformedThisFrame; - } + + return m_fallbackState.wasPerformedThisFrame; } /// @@ -193,10 +188,8 @@ public bool ReadWasCompletedThisFrame() { return selectAction.action.WasCompletedThisFrame(); } - else - { - return m_fallbackState.wasCompletedThisFrame; - } + + return m_fallbackState.wasCompletedThisFrame; } /// @@ -206,10 +199,8 @@ public float ReadValue() { return selectActionValue.action.ReadValue(); } - else - { - return m_fallbackState.value; - } + + return m_fallbackState.value; } /// @@ -221,11 +212,9 @@ public bool TryReadValue(out float value) value = action.ReadValue(); return action.IsInProgress(); } - else - { - value = m_fallbackState.value; - return m_fallbackState.hasPinchData; - } + + value = m_fallbackState.value; + return value > 0; } #endregion IXRInputButtonReader @@ -242,37 +231,49 @@ private void UpdatePinchSelection() { using (UpdatePinchSelectionPerfMarker.Auto()) { - // If we still don't have an aggregator, then don't update selects. - if (XRSubsystemHelpers.HandsAggregator == null) + bool hasPinchData = false; + float pinchAmount = 0; + float pinchProgress = 0; + + // Workaround for missing select actions on devices without interaction profiles + // for hands, such as Varjo and Quest. Should be removed once we have universal + // hand interaction profile(s) across vendors. + if (XRSubsystemHelpers.HandsAggregator != null + && XRSubsystemHelpers.HandsAggregator.TryGetPinchProgress(handNode, out _, out _, out pinchProgress)) { - return; + hasPinchData |= true; } - // If we got pinch data, write it into our select interaction state. - if (XRSubsystemHelpers.HandsAggregator.TryGetPinchProgress( - handNode, - out _, - out _, - out float pinchAmount)) + // This section accounts for one of "select" and "select value" being bound while the other is polyfilled. + // We can use the data from the bound action to synthesize the other better than the hand joint logic will. + if (!m_isSelectPolyfilled && !m_isTrackingStatePolyfilled) { - // Workaround for missing select actions on devices without interaction profiles - // for hands, such as Varjo and Quest. Should be removed once we have universal - // hand interaction profile(s) across vendors. - - // Debounce the polyfill pinch action value. - bool isPinched = pinchAmount >= (m_fallbackState.isPerformed ? 0.9f : 1.0f); - - m_fallbackState.wasPerformedThisFrame = isPinched && !m_fallbackState.isPerformed; - m_fallbackState.wasCompletedThisFrame = !isPinched && m_fallbackState.isPerformed; - m_fallbackState.isPerformed = isPinched; - m_fallbackState.value = pinchAmount; - m_fallbackState.hasPinchData = true; + // If we successfully read hand joint data, we should use that instead of clamping to 0 or 1 + pinchAmount = pinchProgress > 0 ? pinchProgress : ReadIsPerformed() ? 1 : 0; + hasPinchData |= true; } - else + else if (!m_isSelectValuePolyfilled && !m_isTrackingStatePolyfilled) + { + pinchAmount = ReadValue(); + hasPinchData |= true; + } + + if (!hasPinchData) { // If we didn't get pinch data, reset the fallback state. m_fallbackState = default; - } + return; + } + + const float PinchDeactivateThreshold = 0.9f; + const float PinchActivateThreshold = 1.0f; + + // Debounce the polyfill pinch action value. + bool isPinched = pinchAmount >= (m_fallbackState.isPerformed ? PinchDeactivateThreshold : PinchActivateThreshold); + m_fallbackState.wasPerformedThisFrame = isPinched && !m_fallbackState.isPerformed; + m_fallbackState.wasCompletedThisFrame = !isPinched && m_fallbackState.isPerformed; + m_fallbackState.isPerformed = isPinched; + m_fallbackState.value = pinchAmount; } }