Skip to content

Commit

Permalink
Fix jaggy hand pose transition when an interactable overrides the han…
Browse files Browse the repository at this point in the history
…d pose to use (#141)

* Fix source pose not filtering for source ID

* Fix hand pose override is detected too late and causes jaggy transition

* Clean up profile
  • Loading branch information
FejZa committed Jul 17, 2024
1 parent a5511f6 commit 4f62ae5
Show file tree
Hide file tree
Showing 10 changed files with 175 additions and 13 deletions.
1 change: 0 additions & 1 deletion Assets~/Profiles/Input/InteractorsProfile.asset
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 5f1708952b3739a47908a0fb9a103a7e, type: 3}
m_Name: InteractorsProfile
m_EditorClassIdentifier:
pointingExtent: 10
pointerRaycastLayerMasks:
- serializedVersion: 2
m_Bits: 4294967291
Expand Down
26 changes: 26 additions & 0 deletions Runtime/Input/Hands/Poses/IProvideHandPose.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Reality Collective. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

namespace RealityToolkit.Input.Hands.Poses
{
/// <summary>
/// Identifies and implementation that provides <see cref="HandPose"/>s to <see cref="Visualizers.BaseHandControllerVisualizer"/>s.
/// </summary>
public interface IProvideHandPose
{
/// <summary>
/// Optional focus <see cref="HandPose"/> override.
/// </summary>
HandPose FocusPose { get; }

/// <summary>
/// Optional select <see cref="HandPose"/> override.
/// </summary>
HandPose SelectPose { get; }

/// <summary>
/// Optional grab <see cref="HandPose"/> override.
/// </summary>
HandPose GrabPose { get; }
}
}
11 changes: 11 additions & 0 deletions Runtime/Input/Hands/Poses/IProvideHandPose.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 45 additions & 1 deletion Runtime/Input/Hands/Visualizers/BaseHandControllerVisualizer.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// Copyright (c) Reality Collective. All rights reserved.
// Copyright (c) Reality Collective. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using RealityCollective.Utilities.Extensions;
using RealityToolkit.EventDatum.Input;
using RealityToolkit.Input.Controllers;
using RealityToolkit.Input.Hands.Poses;
using System;
using UnityEngine;

Expand All @@ -25,5 +28,46 @@ protected virtual void Awake()
return;
}
}

/// <summary>
/// Checks whether any of the <see cref="Interactors.IInteractor"/>s on this <see cref="BaseHandControllerVisualizer"/> is targeting
/// an object that has a <see cref="IProvideHandPose"/> implementation attached to it.
/// </summary>
/// <param name="eventData">The input event data received.</param>
/// <param name="checkFocus">Check whether there is a <see cref="IProvideHandPose"/> that provides a focus pose.</param>
/// <param name="checkSelect">Check whether there is a <see cref="IProvideHandPose"/> that provides a select pose.</param>
/// <param name="checkGrab">Check whether there is a <see cref="IProvideHandPose"/> that provides a grab pose.</param>
/// <returns></returns>
protected bool IsTargetingHandPoseProvider(InputEventData eventData, bool checkFocus, bool checkSelect, bool checkGrab)
{
for (var i = 0; i < eventData.InputSource.Pointers.Length; i++)
{
var interactor = eventData.InputSource.Pointers[i];
if (interactor.Result.CurrentTarget.IsNotNull())
{
var poseProviders = interactor.Result.CurrentTarget.GetComponents<IProvideHandPose>();
for (var j = 0; j < poseProviders.Length; j++)
{
var poseProvider = poseProviders[j];
if (checkFocus && poseProvider.FocusPose.IsNotNull())
{
return true;
}

if (checkSelect && poseProvider.SelectPose.IsNotNull())
{
return true;
}

if (checkGrab && poseProvider.GrabPose.IsNotNull())
{
return true;
}
}
}
}

return false;
}
}
}
18 changes: 12 additions & 6 deletions Runtime/Input/Hands/Visualizers/RiggedHandControllerVisualizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,14 @@ public override void OnInputDown(InputEventData eventData)
}

if (eventData.InputSource == Controller.InputSource &&
eventData.InputAction == selectInputAction)
eventData.InputAction == selectInputAction &&
!IsTargetingHandPoseProvider(eventData, false, true, false))
{
poseAnimator.Transition(selectHandPose);
}
else if (eventData.InputSource == Controller.InputSource &&
eventData.InputAction == gripInputAction)
eventData.InputAction == gripInputAction &&
!IsTargetingHandPoseProvider(eventData, false, false, true))
{
poseAnimator.Transition(gripHandPose);
}
Expand All @@ -106,12 +108,14 @@ public override void OnInputUp(InputEventData eventData)
}

if (eventData.InputSource == Controller.InputSource &&
eventData.InputAction == selectInputAction)
eventData.InputAction == selectInputAction &&
!IsTargetingHandPoseProvider(eventData, false, true, false))
{
poseAnimator.Transition(idlePose);
}
else if (eventData.InputSource == Controller.InputSource &&
eventData.InputAction == gripInputAction)
eventData.InputAction == gripInputAction &&
!IsTargetingHandPoseProvider(eventData, false, false, true))
{
poseAnimator.Transition(idlePose);
}
Expand All @@ -130,12 +134,14 @@ public override void OnInputChanged(InputEventData<float> eventData)
}

if (eventData.InputSource == Controller.InputSource &&
eventData.InputAction == selectInputAction)
eventData.InputAction == selectInputAction &&
!IsTargetingHandPoseProvider(eventData, false, true, false))
{
OnSingleAxisInputChanged(eventData.InputData, selectHandPose);
}
else if (eventData.InputSource == Controller.InputSource &&
eventData.InputAction == gripInputAction)
eventData.InputAction == gripInputAction &&
!IsTargetingHandPoseProvider(eventData, false, false, true))
{
OnSingleAxisInputChanged(eventData.InputData, gripHandPose);
}
Expand Down
1 change: 0 additions & 1 deletion Runtime/Input/Interactables/Interactable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ public class Interactable : MonoBehaviour,
[Tooltip("The action that will grab this interactable, if focused by an interactor.")]
protected InputAction grabAction = InputAction.None;

[Space]
[SerializeField, Tooltip("The focus mode for this interactable.")]
private InteractableFocusMode focusMode = InteractableFocusMode.Single;

Expand Down
15 changes: 12 additions & 3 deletions Runtime/Input/InteractionBehaviours/FocusHandPoseBehaviour.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,22 @@ namespace RealityToolkit.Input.InteractionBehaviours
/// into the assigned <see cref="focusPose"/>, when the <see cref="Interactables.IInteractable"/> is focused.
[HelpURL("https://www.realitytoolkit.io/docs/interactions/interaction-behaviours/default-behaviours/focus-hand-pose-behaviour")]
[AddComponentMenu(RealityToolkitRuntimePreferences.Toolkit_InteractionsAddComponentMenu + "/" + nameof(FocusHandPoseBehaviour))]
public class FocusHandPoseBehaviour : BaseInteractionBehaviour
public class FocusHandPoseBehaviour : BaseInteractionBehaviour, IProvideHandPose
{
[SerializeField, Tooltip("Hand pose applied when focusing the interactable.")]
private HandPose focusPose = null;

/// <inheritdoc/>
protected override void OnFirstFocusEntered(InteractionEventArgs eventArgs)
public HandPose FocusPose => focusPose;

/// <inheritdoc/>
public HandPose SelectPose { get; } = null;

/// <inheritdoc/>
public HandPose GrabPose { get; } = null;

/// <inheritdoc/>
protected override void OnFocusEntered(InteractionEventArgs eventArgs)
{
if (Interactable.IsSelected || Interactable.IsGrabbed)
{
Expand All @@ -35,7 +44,7 @@ protected override void OnFirstFocusEntered(InteractionEventArgs eventArgs)
}

/// <inheritdoc/>
protected override void OnLastFocusExited(InteractionExitEventArgs eventArgs)
protected override void OnFocusExited(InteractionExitEventArgs eventArgs)
{
if (Interactable.IsSelected || Interactable.IsGrabbed)
{
Expand Down
11 changes: 10 additions & 1 deletion Runtime/Input/InteractionBehaviours/GrabHandPoseBehaviour.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,20 @@ namespace RealityToolkit.Input.InteractionBehaviours
/// into the assigned <see cref="grabPose"/>, when the <see cref="Interactables.IInteractable"/> is grabbed.
[HelpURL("https://www.realitytoolkit.io/docs/interactions/interaction-behaviours/default-behaviours/grab-hand-pose-behaviour")]
[AddComponentMenu(RealityToolkitRuntimePreferences.Toolkit_InteractionsAddComponentMenu + "/" + nameof(GrabHandPoseBehaviour))]
public class GrabHandPoseBehaviour : BaseInteractionBehaviour
public class GrabHandPoseBehaviour : BaseInteractionBehaviour, IProvideHandPose
{
[SerializeField, Tooltip("Hand pose applied when grabbing the interactable.")]
private HandPose grabPose = null;

/// <inheritdoc/>
public HandPose FocusPose { get; } = null;

/// <inheritdoc/>
public HandPose SelectPose { get; } = null;

/// <inheritdoc/>
public HandPose GrabPose => grabPose;

/// <inheritdoc/>
protected override void OnGrabEntered(InteractionEventArgs eventArgs)
{
Expand Down
48 changes: 48 additions & 0 deletions Runtime/Input/InteractionBehaviours/SelectHandPoseBehaviour.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using RealityToolkit.Input.Events;
using RealityToolkit.Input.Hands.Poses;
using RealityToolkit.Input.Hands.Visualizers;
using RealityToolkit.Input.Interactors;
using UnityEngine;

namespace RealityToolkit.Input.InteractionBehaviours
{
/// <summary>
/// The <see cref="SelectHandPoseBehaviour"/> will animate the <see cref="RiggedHandControllerVisualizer"/>
/// into the assigned <see cref="selectPose"/>, when the <see cref="Interactables.IInteractable"/> is selected.
[HelpURL("https://www.realitytoolkit.io/docs/interactions/interaction-behaviours/default-behaviours/select-hand-pose-behaviour")]
[AddComponentMenu(RealityToolkitRuntimePreferences.Toolkit_InteractionsAddComponentMenu + "/" + nameof(SelectHandPoseBehaviour))]
public class SelectHandPoseBehaviour : BaseInteractionBehaviour, IProvideHandPose
{
[SerializeField, Tooltip("Select pose applied when selecting the interactable.")]
private HandPose selectPose = null;

/// <inheritdoc/>
public HandPose FocusPose { get; } = null;

/// <inheritdoc/>
public HandPose SelectPose => selectPose;

/// <inheritdoc/>
public HandPose GrabPose { get; } = null;

/// <inheritdoc/>
protected override void OnSelectEntered(InteractionEventArgs eventArgs)
{
if (eventArgs.Interactor is IDirectInteractor directInteractor &&
directInteractor.Controller.Visualizer is RiggedHandControllerVisualizer riggedHandControllerVisualizer)
{
riggedHandControllerVisualizer.OverridePose = selectPose;
}
}

/// <inheritdoc/>
protected override void OnSelectExited(InteractionExitEventArgs eventArgs)
{
if (eventArgs.Interactor is IDirectInteractor directInteractor &&
directInteractor.Controller.Visualizer is RiggedHandControllerVisualizer riggedHandControllerVisualizer)
{
riggedHandControllerVisualizer.OverridePose = null;
}
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 4f62ae5

Please sign in to comment.