Skip to content

Commit 4f62ae5

Browse files
authored
Fix jaggy hand pose transition when an interactable overrides the hand 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
1 parent a5511f6 commit 4f62ae5

10 files changed

+175
-13
lines changed

Assets~/Profiles/Input/InteractorsProfile.asset

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ MonoBehaviour:
1212
m_Script: {fileID: 11500000, guid: 5f1708952b3739a47908a0fb9a103a7e, type: 3}
1313
m_Name: InteractorsProfile
1414
m_EditorClassIdentifier:
15-
pointingExtent: 10
1615
pointerRaycastLayerMasks:
1716
- serializedVersion: 2
1817
m_Bits: 4294967291
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) Reality Collective. All rights reserved.
2+
// Licensed under the MIT License. See LICENSE in the project root for license information.
3+
4+
namespace RealityToolkit.Input.Hands.Poses
5+
{
6+
/// <summary>
7+
/// Identifies and implementation that provides <see cref="HandPose"/>s to <see cref="Visualizers.BaseHandControllerVisualizer"/>s.
8+
/// </summary>
9+
public interface IProvideHandPose
10+
{
11+
/// <summary>
12+
/// Optional focus <see cref="HandPose"/> override.
13+
/// </summary>
14+
HandPose FocusPose { get; }
15+
16+
/// <summary>
17+
/// Optional select <see cref="HandPose"/> override.
18+
/// </summary>
19+
HandPose SelectPose { get; }
20+
21+
/// <summary>
22+
/// Optional grab <see cref="HandPose"/> override.
23+
/// </summary>
24+
HandPose GrabPose { get; }
25+
}
26+
}

Runtime/Input/Hands/Poses/IProvideHandPose.cs.meta

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/Input/Hands/Visualizers/BaseHandControllerVisualizer.cs

+45-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
// Copyright (c) Reality Collective. All rights reserved.
1+
// Copyright (c) Reality Collective. All rights reserved.
22
// Licensed under the MIT License. See LICENSE in the project root for license information.
33

4+
using RealityCollective.Utilities.Extensions;
5+
using RealityToolkit.EventDatum.Input;
46
using RealityToolkit.Input.Controllers;
7+
using RealityToolkit.Input.Hands.Poses;
58
using System;
69
using UnityEngine;
710

@@ -25,5 +28,46 @@ protected virtual void Awake()
2528
return;
2629
}
2730
}
31+
32+
/// <summary>
33+
/// Checks whether any of the <see cref="Interactors.IInteractor"/>s on this <see cref="BaseHandControllerVisualizer"/> is targeting
34+
/// an object that has a <see cref="IProvideHandPose"/> implementation attached to it.
35+
/// </summary>
36+
/// <param name="eventData">The input event data received.</param>
37+
/// <param name="checkFocus">Check whether there is a <see cref="IProvideHandPose"/> that provides a focus pose.</param>
38+
/// <param name="checkSelect">Check whether there is a <see cref="IProvideHandPose"/> that provides a select pose.</param>
39+
/// <param name="checkGrab">Check whether there is a <see cref="IProvideHandPose"/> that provides a grab pose.</param>
40+
/// <returns></returns>
41+
protected bool IsTargetingHandPoseProvider(InputEventData eventData, bool checkFocus, bool checkSelect, bool checkGrab)
42+
{
43+
for (var i = 0; i < eventData.InputSource.Pointers.Length; i++)
44+
{
45+
var interactor = eventData.InputSource.Pointers[i];
46+
if (interactor.Result.CurrentTarget.IsNotNull())
47+
{
48+
var poseProviders = interactor.Result.CurrentTarget.GetComponents<IProvideHandPose>();
49+
for (var j = 0; j < poseProviders.Length; j++)
50+
{
51+
var poseProvider = poseProviders[j];
52+
if (checkFocus && poseProvider.FocusPose.IsNotNull())
53+
{
54+
return true;
55+
}
56+
57+
if (checkSelect && poseProvider.SelectPose.IsNotNull())
58+
{
59+
return true;
60+
}
61+
62+
if (checkGrab && poseProvider.GrabPose.IsNotNull())
63+
{
64+
return true;
65+
}
66+
}
67+
}
68+
}
69+
70+
return false;
71+
}
2872
}
2973
}

Runtime/Input/Hands/Visualizers/RiggedHandControllerVisualizer.cs

+12-6
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,14 @@ public override void OnInputDown(InputEventData eventData)
8686
}
8787

8888
if (eventData.InputSource == Controller.InputSource &&
89-
eventData.InputAction == selectInputAction)
89+
eventData.InputAction == selectInputAction &&
90+
!IsTargetingHandPoseProvider(eventData, false, true, false))
9091
{
9192
poseAnimator.Transition(selectHandPose);
9293
}
9394
else if (eventData.InputSource == Controller.InputSource &&
94-
eventData.InputAction == gripInputAction)
95+
eventData.InputAction == gripInputAction &&
96+
!IsTargetingHandPoseProvider(eventData, false, false, true))
9597
{
9698
poseAnimator.Transition(gripHandPose);
9799
}
@@ -106,12 +108,14 @@ public override void OnInputUp(InputEventData eventData)
106108
}
107109

108110
if (eventData.InputSource == Controller.InputSource &&
109-
eventData.InputAction == selectInputAction)
111+
eventData.InputAction == selectInputAction &&
112+
!IsTargetingHandPoseProvider(eventData, false, true, false))
110113
{
111114
poseAnimator.Transition(idlePose);
112115
}
113116
else if (eventData.InputSource == Controller.InputSource &&
114-
eventData.InputAction == gripInputAction)
117+
eventData.InputAction == gripInputAction &&
118+
!IsTargetingHandPoseProvider(eventData, false, false, true))
115119
{
116120
poseAnimator.Transition(idlePose);
117121
}
@@ -130,12 +134,14 @@ public override void OnInputChanged(InputEventData<float> eventData)
130134
}
131135

132136
if (eventData.InputSource == Controller.InputSource &&
133-
eventData.InputAction == selectInputAction)
137+
eventData.InputAction == selectInputAction &&
138+
!IsTargetingHandPoseProvider(eventData, false, true, false))
134139
{
135140
OnSingleAxisInputChanged(eventData.InputData, selectHandPose);
136141
}
137142
else if (eventData.InputSource == Controller.InputSource &&
138-
eventData.InputAction == gripInputAction)
143+
eventData.InputAction == gripInputAction &&
144+
!IsTargetingHandPoseProvider(eventData, false, false, true))
139145
{
140146
OnSingleAxisInputChanged(eventData.InputData, gripHandPose);
141147
}

Runtime/Input/Interactables/Interactable.cs

-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ public class Interactable : MonoBehaviour,
4949
[Tooltip("The action that will grab this interactable, if focused by an interactor.")]
5050
protected InputAction grabAction = InputAction.None;
5151

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

Runtime/Input/InteractionBehaviours/FocusHandPoseBehaviour.cs

+12-3
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,22 @@ namespace RealityToolkit.Input.InteractionBehaviours
1414
/// into the assigned <see cref="focusPose"/>, when the <see cref="Interactables.IInteractable"/> is focused.
1515
[HelpURL("https://www.realitytoolkit.io/docs/interactions/interaction-behaviours/default-behaviours/focus-hand-pose-behaviour")]
1616
[AddComponentMenu(RealityToolkitRuntimePreferences.Toolkit_InteractionsAddComponentMenu + "/" + nameof(FocusHandPoseBehaviour))]
17-
public class FocusHandPoseBehaviour : BaseInteractionBehaviour
17+
public class FocusHandPoseBehaviour : BaseInteractionBehaviour, IProvideHandPose
1818
{
1919
[SerializeField, Tooltip("Hand pose applied when focusing the interactable.")]
2020
private HandPose focusPose = null;
2121

2222
/// <inheritdoc/>
23-
protected override void OnFirstFocusEntered(InteractionEventArgs eventArgs)
23+
public HandPose FocusPose => focusPose;
24+
25+
/// <inheritdoc/>
26+
public HandPose SelectPose { get; } = null;
27+
28+
/// <inheritdoc/>
29+
public HandPose GrabPose { get; } = null;
30+
31+
/// <inheritdoc/>
32+
protected override void OnFocusEntered(InteractionEventArgs eventArgs)
2433
{
2534
if (Interactable.IsSelected || Interactable.IsGrabbed)
2635
{
@@ -35,7 +44,7 @@ protected override void OnFirstFocusEntered(InteractionEventArgs eventArgs)
3544
}
3645

3746
/// <inheritdoc/>
38-
protected override void OnLastFocusExited(InteractionExitEventArgs eventArgs)
47+
protected override void OnFocusExited(InteractionExitEventArgs eventArgs)
3948
{
4049
if (Interactable.IsSelected || Interactable.IsGrabbed)
4150
{

Runtime/Input/InteractionBehaviours/GrabHandPoseBehaviour.cs

+10-1
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,20 @@ namespace RealityToolkit.Input.InteractionBehaviours
1414
/// into the assigned <see cref="grabPose"/>, when the <see cref="Interactables.IInteractable"/> is grabbed.
1515
[HelpURL("https://www.realitytoolkit.io/docs/interactions/interaction-behaviours/default-behaviours/grab-hand-pose-behaviour")]
1616
[AddComponentMenu(RealityToolkitRuntimePreferences.Toolkit_InteractionsAddComponentMenu + "/" + nameof(GrabHandPoseBehaviour))]
17-
public class GrabHandPoseBehaviour : BaseInteractionBehaviour
17+
public class GrabHandPoseBehaviour : BaseInteractionBehaviour, IProvideHandPose
1818
{
1919
[SerializeField, Tooltip("Hand pose applied when grabbing the interactable.")]
2020
private HandPose grabPose = null;
2121

22+
/// <inheritdoc/>
23+
public HandPose FocusPose { get; } = null;
24+
25+
/// <inheritdoc/>
26+
public HandPose SelectPose { get; } = null;
27+
28+
/// <inheritdoc/>
29+
public HandPose GrabPose => grabPose;
30+
2231
/// <inheritdoc/>
2332
protected override void OnGrabEntered(InteractionEventArgs eventArgs)
2433
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using RealityToolkit.Input.Events;
2+
using RealityToolkit.Input.Hands.Poses;
3+
using RealityToolkit.Input.Hands.Visualizers;
4+
using RealityToolkit.Input.Interactors;
5+
using UnityEngine;
6+
7+
namespace RealityToolkit.Input.InteractionBehaviours
8+
{
9+
/// <summary>
10+
/// The <see cref="SelectHandPoseBehaviour"/> will animate the <see cref="RiggedHandControllerVisualizer"/>
11+
/// into the assigned <see cref="selectPose"/>, when the <see cref="Interactables.IInteractable"/> is selected.
12+
[HelpURL("https://www.realitytoolkit.io/docs/interactions/interaction-behaviours/default-behaviours/select-hand-pose-behaviour")]
13+
[AddComponentMenu(RealityToolkitRuntimePreferences.Toolkit_InteractionsAddComponentMenu + "/" + nameof(SelectHandPoseBehaviour))]
14+
public class SelectHandPoseBehaviour : BaseInteractionBehaviour, IProvideHandPose
15+
{
16+
[SerializeField, Tooltip("Select pose applied when selecting the interactable.")]
17+
private HandPose selectPose = null;
18+
19+
/// <inheritdoc/>
20+
public HandPose FocusPose { get; } = null;
21+
22+
/// <inheritdoc/>
23+
public HandPose SelectPose => selectPose;
24+
25+
/// <inheritdoc/>
26+
public HandPose GrabPose { get; } = null;
27+
28+
/// <inheritdoc/>
29+
protected override void OnSelectEntered(InteractionEventArgs eventArgs)
30+
{
31+
if (eventArgs.Interactor is IDirectInteractor directInteractor &&
32+
directInteractor.Controller.Visualizer is RiggedHandControllerVisualizer riggedHandControllerVisualizer)
33+
{
34+
riggedHandControllerVisualizer.OverridePose = selectPose;
35+
}
36+
}
37+
38+
/// <inheritdoc/>
39+
protected override void OnSelectExited(InteractionExitEventArgs eventArgs)
40+
{
41+
if (eventArgs.Interactor is IDirectInteractor directInteractor &&
42+
directInteractor.Controller.Visualizer is RiggedHandControllerVisualizer riggedHandControllerVisualizer)
43+
{
44+
riggedHandControllerVisualizer.OverridePose = null;
45+
}
46+
}
47+
}
48+
}

Runtime/Input/InteractionBehaviours/SelectHandPoseBehaviour.cs.meta

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)