Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Work on improved hand menu + improved subsystem query API #10852

Closed
wants to merge 42 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
9cb7d2f
Work on improved hand menu + improved subsystem query API
Zee2 Aug 5, 2022
be5d790
Merge branch 'mrtk3' into new_hand_menu
Zee2 Aug 10, 2022
fdc646d
Merge branch 'mrtk3' into new_hand_menu
Zee2 Aug 12, 2022
5a5f332
Merge branch 'mrtk3' into new_hand_menu
Zee2 Aug 12, 2022
68e864c
Hand menu improvements
Zee2 Aug 12, 2022
9ee4ac9
Button disabled effects fixes
Zee2 Aug 12, 2022
8c12efc
Update hand menu prefab + grab bar material
Zee2 Aug 12, 2022
7fdb5ee
New API for RHMV
Zee2 Aug 12, 2022
ab5ef15
Hand mesh settings on the hand menu
Zee2 Aug 12, 2022
348ec81
Merge branch 'mrtk3' into new_hand_menu
Zee2 Aug 16, 2022
f4b3a6b
Merge branch 'mrtk3' into new_hand_menu
Zee2 Aug 17, 2022
ada7e85
FOV-based activation + polish
Zee2 Aug 24, 2022
f47a69a
Merge branch 'new_hand_menu' of https://github.com/Zee2/MixedRealityT…
Zee2 Aug 24, 2022
40f10ae
Merge branch 'mrtk3' into new_hand_menu
Zee2 Aug 24, 2022
2fb4de7
Hand menu prefab update
Zee2 Aug 24, 2022
7c288ab
Fixing incorrect transition time + missing font icon reference in dis…
Zee2 Aug 24, 2022
ee2ce10
Merge branch 'button_disable_effect_fix' into new_hand_menu
Zee2 Aug 24, 2022
de7136a
Syncing with other branch's stateviz changes
Zee2 Aug 24, 2022
a13f0aa
Adding implicit cast operator to HandJointPose
Zee2 Aug 25, 2022
9e6c562
Adding TransformPose to PlayspaceUtilities
Zee2 Aug 25, 2022
225e26c
More improvements to HandMenu
Zee2 Aug 25, 2022
30904a0
View angle is wonky
Zee2 Aug 25, 2022
23296e2
FOV cone still wonky
Zee2 Aug 26, 2022
e4f9f1b
Refactoring...
Zee2 Aug 27, 2022
7167db7
Merge branch 'mrtk3' into new_hand_menu
Zee2 Oct 4, 2022
98a7799
Merge branch 'new_hand_menu' of https://github.com/Zee2/MixedRealityT…
Zee2 Oct 4, 2022
a5c4049
Merge branch 'mrtk3' into new_hand_menu
Zee2 Oct 4, 2022
b7d5466
Finished refactor
Zee2 Oct 4, 2022
77613aa
Tuning + tweaking
Zee2 Oct 5, 2022
fcfa741
Hands and controllers both working
Zee2 Oct 6, 2022
330f0e4
Re-adding gaze check to hands
Zee2 Oct 6, 2022
dac3baf
Prefab edits
Zee2 Oct 6, 2022
8f05baf
Fixed oopsie
Zee2 Oct 6, 2022
688c162
Merge branch 'mrtk3' into new_hand_menu
Zee2 Oct 6, 2022
d450256
Property refactors
Zee2 Oct 27, 2022
741f3a2
Merge branch 'new_hand_menu' of https://github.com/Zee2/MixedRealityT…
Zee2 Oct 27, 2022
dfcb944
Refactors
Zee2 Oct 27, 2022
6eacb02
Moving constants
Zee2 Oct 28, 2022
e8f5ccf
Merge branch 'mrtk3' into new_hand_menu
Zee2 Oct 28, 2022
1a7c47b
Merging in change for PlayspaceUtilities from mrtk3
Zee2 Oct 28, 2022
658de76
Merge branch 'mrtk3' into new_hand_menu
Zee2 Dec 28, 2022
30959cf
Merge branch 'mrtk3' into new_hand_menu
Zee2 Dec 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view

Large diffs are not rendered by default.

@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Collections.Generic;
using System.Linq;
using Microsoft.MixedReality.Toolkit.Input;
using Microsoft.MixedReality.Toolkit.UX;
using Microsoft.MixedReality.Toolkit.Diagnostics;
Expand All @@ -22,6 +24,9 @@ internal class SampleSceneHandMenu : MonoBehaviour
[SerializeField]
private StatefulInteractable gazePinchToggle;

[SerializeField]
private StatefulInteractable handMeshToggle;

[SerializeField]
private StatefulInteractable perfOverlayToggle;

Expand All @@ -31,13 +36,16 @@ internal class SampleSceneHandMenu : MonoBehaviour
[SerializeField]
private StatefulInteractable nextSceneButton;


[SerializeField]
private TMP_Text sceneTitleLabel;

[SerializeField]
private GameObject profilerObject;

private void Awake()
private List<RiggedHandMeshVisualizer> handMeshes = new List<RiggedHandMeshVisualizer>();

private void Start()
{
rayToggle.OnClicked.AddListener(() => SetHandRaysActive(rayToggle.IsToggled));
gazePinchToggle.OnClicked.AddListener(() => SetGazePinchActive(gazePinchToggle.IsToggled));
Expand All @@ -57,6 +65,11 @@ private void Awake()
perfOverlayToggle.gameObject.SetActive(false);
}

handMeshes = new List<RiggedHandMeshVisualizer>(Object.FindObjectsOfType<RiggedHandMeshVisualizer>());
handMeshToggle.ForceSetToggled((handMeshes.Any((handMesh) => handMesh.IsShowingHands)));
handMeshToggle.OnClicked.AddListener(() => SetHandMeshActive(handMeshToggle.IsToggled));


previousSceneButton.OnClicked.AddListener(() => GoToPreviousScene());
nextSceneButton.OnClicked.AddListener(() => GoToNextScene());

Expand Down Expand Up @@ -100,6 +113,32 @@ public void SetPerfOverlayActive(bool value)
}
}

void SetHandMeshActive(bool value)
{
if (handMeshes.Count == 0)
{
handMeshes = new List<RiggedHandMeshVisualizer>(Object.FindObjectsOfType<RiggedHandMeshVisualizer>());
}

if (handMeshes.Count == 0) {
handMeshToggle.enabled = false;
return;
}

foreach (var handMesh in handMeshes)
{
if (value)
{
handMesh.ShowHandsOnTransparentDisplays = true;
handMesh.enabled = true;
}
else
{
handMesh.enabled = false;
}
}
}

/// <summary>
/// Load the next scene in build order.
/// </summary>
Expand Down
6 changes: 6 additions & 0 deletions com.microsoft.mrtk.core/Utilities/HandJointPose.cs
Expand Up @@ -146,5 +146,11 @@ public override int GetHashCode()
}

#endregion IEqualityComparer Implementation

#region Conversions

public static implicit operator Pose(HandJointPose pose) => pose.pose;

#endregion
}
}
19 changes: 11 additions & 8 deletions com.microsoft.mrtk.core/Utilities/Handedness.cs
Expand Up @@ -6,27 +6,30 @@
namespace Microsoft.MixedReality.Toolkit
{
/// <summary>
/// Defines in which hand a controller is currently being used.
/// Represents handedness; as a bitflag, it can represent left-handedness,
/// right-handedness, both, or neither.
/// </summary>
[Flags]
public enum Handedness
{
/// <summary>
/// No hand specified by the SDK for the controller.
/// No handedness. Represents a non-handed controller or object.
/// </summary>
/// <remarks>
/// This value is used for controllers such as a gamepad or a mouse.
/// </remarks>
None = 0 << 0,

/// <summary>
/// The controller is identified as being provided in a Left hand
/// The user's left hand or controller.
/// </summary>
Left = 1 << 0,

/// <summary>
/// The controller is identified as being provided in a Right hand
/// The user's right hand or controller.
/// </summary>
Right = 1 << 1
Right = 1 << 1,

/// <summary>
/// Both, or either, hands.
/// </summary>
Both = Left | Right,
}
}
83 changes: 52 additions & 31 deletions com.microsoft.mrtk.core/Utilities/XRSubsystemHelpers.cs
Expand Up @@ -3,6 +3,7 @@

using Microsoft.MixedReality.Toolkit.Subsystems;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
Expand All @@ -16,21 +17,21 @@ namespace Microsoft.MixedReality.Toolkit
/// <remarks>These properties are only valid for the XR SDK pipeline.</remarks>
public static class XRSubsystemHelpers
{
private static Dictionary<Type, IList> scratchCaches = new Dictionary<Type, IList>();

/// <summary>
/// Get the first active subsystem of type T.
/// </summary>
/// <remarks>
/// Caution: this method allocs a new list of subsystems.
/// For performance critical (frame loop) applications,
/// consider calling SubsystemManager.GetSubsystems directly
/// with a pre-allocated list.
/// This method allocates on the first invocation with a new, unique type T.
/// Subsequent invocations with the same type T will no longer allocate.
/// </remarks>
public static T GetFirstSubsystem<T>() where T : ISubsystem
{
List<T> subsystems = GetAllSubsystems<T>();
List<T> results = GetAllSubsystems<T>();

// default returns null on reference type
return subsystems.Count > 0 ? subsystems[0] : default;
return results.Count > 0 ? results[0] : default;
}

/// <summary>
Expand All @@ -51,53 +52,56 @@ public static class XRSubsystemHelpers
}

/// <summary>
/// Get all running subsystems of type T without allocating a new list.
/// Get all running subsystems of type T.
/// </summary>
/// <param name="runningSubsystems">The list to fill with all running subsystems of the specified type.</param>
[Obsolete("GetAllRunningSubsystems now internally caches for you; this separate NonAlloc method is no longer necessary.")]
public static void GetAllRunningSubsystemsNonAlloc<T>(List<T> runningSubsystems) where T : ISubsystem
{
SubsystemManager.GetSubsystems(runningSubsystems);
runningSubsystems.RemoveAll(subsystem => !subsystem.running);
}

/// <summary>
/// Get all running subsystems of type T.
/// Get all running subsystems of type T. Note, this is internally cached, so
/// the list is only valid immediately after invocation.
/// </summary>
/// <remarks>
/// Caution: this method allocs a new list of subsystems.
/// For performance critical (frame loop) applications,
/// consider calling SubsystemManager.GetSubsystems directly
/// with a pre-allocated list.
/// This method allocates on the first invocation with a new, unique type T.
/// Subsequent invocations with the same type T will no longer allocate.
/// </remarks>
public static List<T> GetAllRunningSubsystems<T>() where T : ISubsystem
{
List<T> filtered = new List<T>();

foreach (T sys in GetAllSubsystems<T>())
{
if (sys.running)
{
filtered.Add(sys);
}
}

return filtered;
List<T> subsystems = GetAllSubsystems<T>();
subsystems.RemoveAll(subsystem => !subsystem.running);
return subsystems;
}

/// <summary>
/// Get all subsystems (not necessarily running) of type T.
/// Get all subsystems (not necessarily running) of type T. Note, this is
/// internally cached, so the list is only valid immediately after invocation.
/// </summary>
/// <remarks>
/// Caution: this method allocs a new list of subsystems.
/// For performance critical (frame loop) applications,
/// consider calling SubsystemManager.GetSubsystems directly
/// with a pre-allocated list.
/// This method allocates on the first invocation with a new, unique type T.
/// Subsequent invocations with the same type T will no longer allocate.
/// </remarks>
public static List<T> GetAllSubsystems<T>() where T : ISubsystem
{
List<T> subsystems = new List<T>();
SubsystemManager.GetSubsystems(subsystems);
return subsystems;
// If we haven't queried subsystems of this type before,
// we'll need to add a new entry in our cache. This will
// allocate the first time, but subsequent queries will
// reuse the same cached list. (The list will still be cleared
// and re-filled by the GetSubsystems call, but nothing will be
// allocated.)
if (!scratchCaches.ContainsKey(typeof(T)))
{
scratchCaches.Add(typeof(T), new List<T>());
}

List<T> cache = scratchCaches[typeof(T)] as List<T>;
SubsystemManager.GetSubsystems<T>(cache);

return cache;
}

private static XRInputSubsystem inputSubsystem = null;
Expand Down Expand Up @@ -151,6 +155,23 @@ public static XRDisplaySubsystem DisplaySubsystem
}
}

private static HandsAggregatorSubsystem handsAggregator = null;

/// <summary>
/// The currently loaded and running hands aggregator, if any.
/// </summary>
public static HandsAggregatorSubsystem HandsAggregator
{
get
{
if (handsAggregator == null || !handsAggregator.running)
{
handsAggregator = GetFirstRunningSubsystem<HandsAggregatorSubsystem>();
}
return handsAggregator;
}
}

#region Subsystem internal utilities

/// <summary>
Expand Down
Expand Up @@ -47,6 +47,25 @@ public bool ShowHandsOnTransparentDisplays
set => showHandsOnTransparentDisplays = value;
}

/// <summary>
/// Is the hand actually visible?
/// </summary>
public bool IsShowingHands
{
get
{
if (handRenderer != null)
{
return handRenderer.enabled &&
handRenderer.gameObject.activeInHierarchy;
}
else
{
return false;
}
}
}

[SerializeField]
[Tooltip("The transform of the wrist joint.")]
private Transform wrist;
Expand Down
@@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using UnityEditor;
using UnityEngine;

namespace Microsoft.MixedReality.Toolkit.SpatialManipulation.Editor
{
[CustomEditor(typeof(HandMenu))]
[CanEditMultipleObjects]
public class HandMenuEditor : UnityEditor.Editor
{
private SerializedProperty leftHandPosition;

private SerializedProperty leftHandRotation;

private SerializedProperty rightHandPosition;

private SerializedProperty rightHandRotation;

private static bool expanded = false;

private string[] drawnProperties = new string[]
{
nameof(leftHandPosition),
nameof(leftHandRotation),
nameof(rightHandPosition),
nameof(rightHandRotation)
};

protected virtual void OnEnable()
{
leftHandPosition = serializedObject.FindProperty(nameof(leftHandPosition));
leftHandRotation = serializedObject.FindProperty(nameof(leftHandRotation));
rightHandPosition = serializedObject.FindProperty(nameof(rightHandPosition));
rightHandRotation = serializedObject.FindProperty(nameof(rightHandRotation));
}

public override void OnInspectorGUI()
{
serializedObject.Update();
DrawPropertiesExcluding(serializedObject, drawnProperties);
EditorGUILayout.Space();

if (expanded = EditorGUILayout.BeginFoldoutHeaderGroup(expanded, "Fallback Bindings"))
{
EditorGUILayout.PropertyField(leftHandPosition);
EditorGUILayout.PropertyField(leftHandRotation);
EditorGUILayout.PropertyField(rightHandPosition);
EditorGUILayout.PropertyField(rightHandRotation);
EditorGUILayout.EndFoldoutHeaderGroup();
}

serializedObject.ApplyModifiedProperties();
}
}
}

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