diff --git a/UnityProjects/MRTKDevTemplate/Assets/Scripts/Editor/AndroidXRConfig.cs b/UnityProjects/MRTKDevTemplate/Assets/Scripts/Editor/AndroidXRConfig.cs index 81bc871f5..75e222a44 100644 --- a/UnityProjects/MRTKDevTemplate/Assets/Scripts/Editor/AndroidXRConfig.cs +++ b/UnityProjects/MRTKDevTemplate/Assets/Scripts/Editor/AndroidXRConfig.cs @@ -24,8 +24,8 @@ public static void InstallPackages() return; } - Debug.Log("Adding com.unity.xr.androidxr-openxr and com.google.xr.extensions..."); - request = Client.AddAndRemove(new[] { "com.unity.xr.androidxr-openxr", "https://github.com/android/android-xr-unity-package.git" }); + Debug.Log("Adding the Unity OpenXR Android XR package..."); + request = Client.AddAndRemove(new[] { "com.unity.xr.androidxr-openxr" }); EditorApplication.update += Progress; } @@ -33,7 +33,7 @@ private static void Progress() { if (request.IsCompleted) { - Debug.Log($"Package install request complete ({request.Status})"); + Debug.Log($"Package install request complete ({request.Status})."); EditorApplication.update -= Progress; request = null; } diff --git a/UnityProjects/MRTKDevTemplate/Packages/packages-lock.json b/UnityProjects/MRTKDevTemplate/Packages/packages-lock.json index f282671d1..18fbf5893 100644 --- a/UnityProjects/MRTKDevTemplate/Packages/packages-lock.json +++ b/UnityProjects/MRTKDevTemplate/Packages/packages-lock.json @@ -264,12 +264,13 @@ "url": "https://packages.unity.com" }, "com.unity.xr.hands": { - "version": "1.3.0", + "version": "1.6.0", "depth": 1, "source": "registry", "dependencies": { "com.unity.modules.xr": "1.0.0", "com.unity.inputsystem": "1.3.0", + "com.unity.mathematics": "1.2.6", "com.unity.xr.core-utils": "2.2.0", "com.unity.xr.management": "4.0.1" }, @@ -389,7 +390,7 @@ "com.unity.inputsystem": "1.6.1", "com.unity.xr.arfoundation": "5.0.5", "com.unity.xr.core-utils": "2.1.0", - "com.unity.xr.hands": "1.3.0", + "com.unity.xr.hands": "1.6.0", "com.unity.xr.interaction.toolkit": "3.0.4", "org.mixedrealitytoolkit.core": "4.0.0" } diff --git a/org.mixedrealitytoolkit.input/CHANGELOG.md b/org.mixedrealitytoolkit.input/CHANGELOG.md index bb0000f72..de95f8c87 100644 --- a/org.mixedrealitytoolkit.input/CHANGELOG.md +++ b/org.mixedrealitytoolkit.input/CHANGELOG.md @@ -2,6 +2,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). +## Unreleased + +### Added + +* Added support for XR_MSFT_hand_tracking_mesh and XR_ANDROID_hand_mesh on compatible runtimes. [PR #993](https://github.com/MixedRealityToolkit/MixedRealityToolkit-Unity/pull/993) + ## [4.0.0-pre.2] - 2025-12-05 ### Changed diff --git a/org.mixedrealitytoolkit.input/Controllers/HandModel.cs b/org.mixedrealitytoolkit.input/Controllers/HandModel.cs index 72d0c9548..32ed74ae3 100644 --- a/org.mixedrealitytoolkit.input/Controllers/HandModel.cs +++ b/org.mixedrealitytoolkit.input/Controllers/HandModel.cs @@ -57,7 +57,7 @@ public Transform ModelPrefab /// the hand model prefab when implementing . /// public XRInputButtonReader SelectInput => selectInput; - + #endregion Associated hand select values /// @@ -73,9 +73,13 @@ protected virtual void Start() Debug.Assert(selectInput != null, $"The Select Input reader for {name} is not set and will not be used with the instantiated hand model."); // Set the select input reader for the model if it implements ISelectInputVisualizer - if (selectInput != null && model != null && model.TryGetComponent(out ISelectInputVisualizer selectInputVisualizer)) + if (selectInput != null && model != null) { - selectInputVisualizer.SelectInput = selectInput; + ISelectInputVisualizer[] selectInputVisualizers = model.GetComponentsInChildren(); + foreach (ISelectInputVisualizer selectInputVisualizer in selectInputVisualizers) + { + selectInputVisualizer.SelectInput = selectInput; + } } } } diff --git a/org.mixedrealitytoolkit.input/Subsystems/Hands/UnityHandsSubsystem.cs b/org.mixedrealitytoolkit.input/Subsystems/Hands/UnityHandsSubsystem.cs index ef893321a..ee0ffb182 100644 --- a/org.mixedrealitytoolkit.input/Subsystems/Hands/UnityHandsSubsystem.cs +++ b/org.mixedrealitytoolkit.input/Subsystems/Hands/UnityHandsSubsystem.cs @@ -263,8 +263,7 @@ private XRHand GetTrackedHand() } } - XRHand hand = HandNode == XRNode.LeftHand ? xrHandSubsystem.leftHand : xrHandSubsystem.rightHand; - return hand; + return HandNode == XRNode.LeftHand ? xrHandSubsystem.leftHand : xrHandSubsystem.rightHand; } } diff --git a/org.mixedrealitytoolkit.input/Tracking/HandPoseDriver.cs b/org.mixedrealitytoolkit.input/Tracking/HandPoseDriver.cs index 0872c35d6..b0c9dc106 100644 --- a/org.mixedrealitytoolkit.input/Tracking/HandPoseDriver.cs +++ b/org.mixedrealitytoolkit.input/Tracking/HandPoseDriver.cs @@ -33,6 +33,7 @@ public class HandPoseDriver : TrackedPoseDriver private bool m_firstUpdate = true; private InputAction m_boundTrackingAction = null; private InputTrackingState m_trackingState = InputTrackingState.None; + private const InputTrackingState m_polyfillTrackingState = InputTrackingState.Position | InputTrackingState.Rotation; /// /// Expose the tracking state for the hand pose driver, to allow to query it. @@ -40,7 +41,7 @@ public class HandPoseDriver : TrackedPoseDriver /// /// Avoid exposing this publicly as this is a workaround solution to support hand tracking on devices without interaction profiles. /// - internal InputTrackingState CachedTrackingState => m_trackingState; + internal InputTrackingState CachedTrackingState => IsPolyfillDevicePose ? m_polyfillTrackingState : m_trackingState; /// /// Get if the last pose set was from a polyfill device pose. That is, if the last pose originated from the . @@ -48,6 +49,7 @@ public class HandPoseDriver : TrackedPoseDriver internal bool IsPolyfillDevicePose { get; private set; } #region Serialized Fields + [Header("Hand Pose Driver Settings")] [SerializeField, Tooltip("The XRNode associated with this Hand Controller. Expected to be XRNode.LeftHand or XRNode.RightHand.")] @@ -58,9 +60,11 @@ public class HandPoseDriver : TrackedPoseDriver /// /// Expected to be XRNode.LeftHand or XRNode.RightHand. public XRNode HandNode => handNode; + #endregion Serialized Fields #region TrackedPoseDriver Overrides + /// protected override void PerformUpdate() { @@ -94,7 +98,6 @@ protected override void PerformUpdate() if ((missingPositionController || missingRotationController || IsTrackingNone()) && TryGetPolyfillDevicePose(out Pose devicePose)) { - m_trackingState = InputTrackingState.Position | InputTrackingState.Rotation; IsPolyfillDevicePose = true; ForceSetLocalTransform(devicePose.position, devicePose.rotation); } @@ -103,9 +106,11 @@ protected override void PerformUpdate() IsPolyfillDevicePose = false; } } + #endregion TrackedPoseDriver Overrides #region Private Functions + /// /// Check the tracking state here to account for a bound but untracked interaction profile. /// This could show up on runtimes where a controller is disconnected, hand tracking spins up, @@ -278,6 +283,7 @@ private void OnTrackingStateInputCanceled(InputAction.CallbackContext context) m_trackingState = InputTrackingState.None; } } + #endregion Private Functions } } diff --git a/org.mixedrealitytoolkit.input/Visualizers/HandMeshVisualizer.cs b/org.mixedrealitytoolkit.input/Visualizers/HandMeshVisualizer.cs new file mode 100644 index 000000000..cf1eae3c4 --- /dev/null +++ b/org.mixedrealitytoolkit.input/Visualizers/HandMeshVisualizer.cs @@ -0,0 +1,232 @@ +// Copyright (c) Mixed Reality Toolkit Contributors +// Licensed under the BSD 3-Clause + +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.XR; +using UnityEngine.XR.Interaction.Toolkit; +using UnityEngine.XR.Interaction.Toolkit.Inputs.Readers; + +namespace MixedReality.Toolkit.Input +{ + public abstract class HandMeshVisualizer : MonoBehaviour, ISelectInputVisualizer + { + [SerializeField] + [Tooltip("The XRNode on which this hand is located.")] + private XRNode handNode = XRNode.LeftHand; + + /// The XRNode on which this hand is located. + public XRNode HandNode { get => handNode; set => handNode = value; } + + [SerializeField] + [Tooltip("When true, this visualizer will render rigged hands even on XR devices " + + "with transparent displays or with passthrough enabled. When false, the rigged hands will only render " + + "on devices with opaque displays. This behavior uses XRDisplaySubsystem.displayOpaque.")] + private bool showHandsOnTransparentDisplays; + + /// + /// When true, this visualizer will render rigged hands even on XR devices with transparent displays or with passthrough enabled. + /// When false, the rigged hands will only render on devices with opaque displays. + /// + /// + /// This behavior uses . + /// Usually, it's recommended not to show hand visualization on transparent displays as it can + /// distract from the user's real hands, and cause a "double image" effect that can be disconcerting. + /// + public bool ShowHandsOnTransparentDisplays + { + get => showHandsOnTransparentDisplays; + set => showHandsOnTransparentDisplays = value; + } + + [SerializeField] + [Tooltip("Name of the shader property used to drive pinch-amount-based visual effects. " + + "Generally, maps to something like a glow or an outline color!")] + private string pinchAmountMaterialProperty = "_PinchAmount"; + + [SerializeField] + [Tooltip("The input reader used when pinch selecting an interactable.")] + private XRInputButtonReader selectInput = new XRInputButtonReader("Select"); + + #region ISelectInputVisualizer implementation + + /// + /// Input reader used when pinch selecting an interactable. + /// + public XRInputButtonReader SelectInput + { + get => selectInput; + set => SetInputProperty(ref selectInput, value); + } + + #endregion ISelectInputVisualizer implementation + + // The property block used to modify the pinch amount property on the material + private MaterialPropertyBlock propertyBlock = null; + + // Scratch list for checking for the presence of display subsystems. + private readonly List displaySubsystems = new List(); + + // The XRController that is used to determine the pinch strength (i.e., select value!) + [Obsolete("This field has been deprecated in version 4.0.0 and will be removed in a future version. Use the SelectInput property instead.")] + private XRBaseController controller; + + /// + /// The list of button input readers used by this interactor. This interactor will automatically enable or disable direct actions + /// if that mode is used during and . + /// + /// + /// + private readonly List buttonReaders = new List(); + + /// + /// Whether this visualizer currently has a loaded and visible hand mesh or not. + /// + protected internal bool IsRendering => HandRenderer != null && HandRenderer.enabled; + + /// + /// The renderer for this visualizer, to use to visualize the pinch amount. + /// + protected abstract Renderer HandRenderer { get; } + + /// + /// A Unity event function that is called when an enabled script instance is being loaded. + /// + protected virtual void Awake() + { + propertyBlock = new MaterialPropertyBlock(); + buttonReaders.Add(selectInput); + } + + /// + /// A Unity event function that is called when the script component has been enabled. + /// + protected virtual void OnEnable() + { + buttonReaders.ForEach(reader => reader?.EnableDirectActionIfModeUsed()); + + // Ensure hand is not visible until we can update position first time. + HandRenderer.enabled = false; + + Debug.Assert(handNode == XRNode.LeftHand || handNode == XRNode.RightHand, + $"HandVisualizer has an invalid XRNode ({handNode})!"); + } + + /// + /// A Unity event function that is called when the script component has been disabled. + /// + protected virtual void OnDisable() + { + buttonReaders.ForEach(reader => reader?.DisableDirectActionIfModeUsed()); + + // Disable the rigged hand renderer when this component is disabled + HandRenderer.enabled = false; + } + + /// + /// Helper method for setting an input property. + /// + /// The to the field. + /// The new value being set. + /// + /// If the application is playing, this method will also enable or disable directly embedded input actions + /// serialized by the input if that mode is used. It will also add or remove the input from the list of button inputs + /// to automatically manage enabling and disabling direct actions with this behavior. + /// + /// + protected void SetInputProperty(ref XRInputButtonReader property, XRInputButtonReader value) + { + if (value == null) + { + Debug.LogError("Setting XRInputButtonReader property to null is disallowed and has therefore been ignored."); + return; + } + + if (Application.isPlaying && property != null) + { + buttonReaders?.Remove(property); + property.DisableDirectActionIfModeUsed(); + } + + property = value; + + if (Application.isPlaying) + { + buttonReaders?.Add(property); + if (isActiveAndEnabled) + { + property.EnableDirectActionIfModeUsed(); + } + } + } + + protected virtual bool ShouldRenderHand() + { + if (displaySubsystems.Count == 0) + { + SubsystemManager.GetSubsystems(displaySubsystems); + } + + // Are we running on an XR display and it happens to be transparent? + // Probably shouldn't be showing rigged hands! (Users can + // specify showHandsOnTransparentDisplays if they disagree.) + if (displaySubsystems.Count > 0 && + displaySubsystems[0].running && + !displaySubsystems[0].displayOpaque && + !showHandsOnTransparentDisplays) + { + return false; + } + + // All checks out! + return true; + } + + protected virtual void UpdateHandMaterial() + { + if (HandRenderer == null) + { + return; + } + + // Update the hand material + float pinchAmount = TryGetSelectionValue(out float selectionValue) ? Mathf.Pow(selectionValue, 2.0f) : 0; + HandRenderer.GetPropertyBlock(propertyBlock); + propertyBlock.SetFloat(pinchAmountMaterialProperty, pinchAmount); + HandRenderer.SetPropertyBlock(propertyBlock); + } + + /// + /// Try to obtain the tracked devices selection value from the provided input reader. + /// + /// + /// For backwards compatibility, this method will also attempt to get the selection amount from a + /// legacy XRI controller if the input reader is not set. + /// + private bool TryGetSelectionValue(out float value) + { + if (selectInput != null && selectInput.TryReadValue(out value)) + { + return true; + } + + bool success = false; + value = 0.0f; + +#pragma warning disable CS0618 // XRBaseController is obsolete + if (controller == null) + { + controller = GetComponentInParent(); + } + if (controller != null) + { + value = controller.selectInteractionState.value; + success = true; + } +#pragma warning restore CS0618 // XRBaseController is obsolete + + return success; + } + } +} diff --git a/org.mixedrealitytoolkit.input/Visualizers/HandMeshVisualizer.cs.meta b/org.mixedrealitytoolkit.input/Visualizers/HandMeshVisualizer.cs.meta new file mode 100644 index 000000000..5efd406a4 --- /dev/null +++ b/org.mixedrealitytoolkit.input/Visualizers/HandMeshVisualizer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3a383c22545b8774b8e5891adaccecf4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/org.mixedrealitytoolkit.input/Visualizers/PlatformHandVisualizer.meta b/org.mixedrealitytoolkit.input/Visualizers/PlatformHandVisualizer.meta new file mode 100644 index 000000000..cfb1734fe --- /dev/null +++ b/org.mixedrealitytoolkit.input/Visualizers/PlatformHandVisualizer.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 503070eeec7bc98479b1459387014145 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/org.mixedrealitytoolkit.input/Visualizers/PlatformHandVisualizer/PlatformHandMeshVisualizer.cs b/org.mixedrealitytoolkit.input/Visualizers/PlatformHandVisualizer/PlatformHandMeshVisualizer.cs new file mode 100644 index 000000000..14d6ed1da --- /dev/null +++ b/org.mixedrealitytoolkit.input/Visualizers/PlatformHandVisualizer/PlatformHandMeshVisualizer.cs @@ -0,0 +1,265 @@ +// Copyright (c) Mixed Reality Toolkit Contributors +// Licensed under the BSD 3-Clause + +using System.Collections.Generic; +using Unity.XR.CoreUtils; +using UnityEngine; +using UnityEngine.SubsystemsImplementation.Extensions; +using UnityEngine.XR; +using UnityEngine.XR.Hands; +using UnityEngine.XR.Hands.Meshing; +using UnityEngine.XR.Hands.OpenXR; + +#if MROPENXR_PRESENT && (UNITY_STANDALONE_WIN || UNITY_WSA || UNITY_ANDROID) +using Microsoft.MixedReality.OpenXR; +#endif + +namespace MixedReality.Toolkit.Input +{ + [AddComponentMenu("MRTK/Input/Visualizers/Platform Hand Mesh Visualizer")] + public class PlatformHandMeshVisualizer : HandMeshVisualizer + { + [SerializeField] + private MeshFilter meshFilter; + + [SerializeField] + private MeshRenderer handRenderer; + + [SerializeField, Range(0, 1)] + private float fadeDistance = 0.025f; + + /// + protected override Renderer HandRenderer => handRenderer; + +#if MROPENXR_PRESENT && (UNITY_STANDALONE_WIN || UNITY_WSA || UNITY_ANDROID) + private HandMeshTracker handMeshTracker; + private Mesh neutralPoseMesh; + private bool initializedUVs = false; +#endif + + // Share these among all instances to only query once per frame + private static int lastUpdatedFrame = -1; + private static XRHandSubsystem handSubsystem = null; + private static XRHandMeshDataQueryResult result; + private XRHandSubsystem.UpdateSuccessFlags updateSuccessFlags; + + // The property block used to modify the wrist position property on the material + private MaterialPropertyBlock propertyBlock = null; + + /// + protected override void OnEnable() + { + base.OnEnable(); + + handRenderer.enabled = false; + + // Use propertyBlock as an indicator that this is our first time through OnEnable + if (propertyBlock == null) + { + propertyBlock = new MaterialPropertyBlock(); + + updateSuccessFlags = HandNode == XRNode.LeftHand ? + XRHandSubsystem.UpdateSuccessFlags.LeftHandJoints | XRHandSubsystem.UpdateSuccessFlags.LeftHandRootPose : + XRHandSubsystem.UpdateSuccessFlags.RightHandJoints | XRHandSubsystem.UpdateSuccessFlags.RightHandRootPose; + + // Since the hand mesh is likely to change every frame, we + // "optimize mesh for frequent updates" by marking it dynamic + meshFilter.mesh.MarkDynamic(); + } + + // If we already found our subsystem, just return + if (handSubsystem != null && handSubsystem.running) { return; } + + List subsystems = XRSubsystemHelpers.GetAllSubsystems(); + foreach (XRHandSubsystem subsystem in subsystems) + { + if (subsystem.GetProvider() is OpenXRHandProvider provider && provider.handMeshDataSupplier != null) + { + Debug.Log($"Using {provider.handMeshDataSupplier.GetType()} for hand visualization."); + handSubsystem = subsystem; + return; + } + } + +#if MROPENXR_PRESENT && (UNITY_STANDALONE_WIN || UNITY_WSA || UNITY_ANDROID) + if (UnityEngine.XR.OpenXR.OpenXRRuntime.IsExtensionEnabled("XR_MSFT_hand_tracking_mesh")) + { + Debug.Log($"Using XR_MSFT_hand_tracking_mesh for {HandNode} visualization."); + handMeshTracker = HandNode == XRNode.LeftHand ? HandMeshTracker.Left : HandMeshTracker.Right; + + if (neutralPoseMesh == null) + { + neutralPoseMesh = new Mesh(); + } + + return; + } +#endif + + Debug.Log($"No active hand mesh extension was found for {HandNode} visualization."); + enabled = false; + } + + protected void Update() + { + if (!ShouldRenderHand()) + { + // Hide the hand and abort if we shouldn't be + // showing the hand, for whatever reason. + // (Missing joint data, no subsystem, additive + // display, etc!) + handRenderer.enabled = false; + return; + } + + if (handSubsystem != null && handSubsystem.running && (handSubsystem.updateSuccessFlags & updateSuccessFlags) != 0) + { + XRHandMeshDataQueryParams queryParams = new() + { + allocator = Unity.Collections.Allocator.Temp, + }; + + // Sometimes, the mesh retrieval will fail, but that doesn't mean we aren't being tracked + // So, reuse the last mesh until the subsystem tells us we're untracked + if (lastUpdatedFrame != Time.frameCount && !handSubsystem.TryGetMeshData(out result, ref queryParams)) + { + return; + } + + lastUpdatedFrame = Time.frameCount; + XRHandMeshData handMeshData = HandNode == XRNode.LeftHand ? result.leftHand : result.rightHand; + handRenderer.enabled = true; + Mesh mesh = meshFilter.mesh; + + if (handMeshData.positions.Length > 0 && handMeshData.indices.Length > 0) + { + mesh.SetVertices(handMeshData.positions); + Unity.Collections.NativeArray indices = handMeshData.indices; + // This API appears to return CCW triangles, but Unity expects CW triangles + for (int i = 0; i < indices.Length; i += 3) + { + (indices[i + 1], indices[i + 2]) = (indices[i + 2], indices[i + 1]); + } + mesh.SetIndices(indices, MeshTopology.Triangles, 0); + mesh.RecalculateBounds(); + } + + if (handMeshData.uvs.IsCreated && handMeshData.uvs.Length == mesh.vertexCount) + { + mesh.SetUVs(0, handMeshData.uvs); + } + else + { + mesh.uv = null; + } + + if (handMeshData.normals.IsCreated && handMeshData.normals.Length == mesh.vertexCount) + { + mesh.SetNormals(handMeshData.normals); + } + else + { + mesh.RecalculateNormals(); + } + + if (handMeshData.TryGetRootPose(out Pose rootPose)) + { + transform.SetWorldPose(PlayspaceUtilities.TransformPose(rootPose)); + } + UpdateHandMaterial(); + return; + } + +#if MROPENXR_PRESENT && (UNITY_STANDALONE_WIN || UNITY_WSA || UNITY_ANDROID) + if (handMeshTracker != null + && handMeshTracker.TryGetHandMesh(FrameTime.OnUpdate, meshFilter.mesh) + && handMeshTracker.TryLocateHandMesh(FrameTime.OnUpdate, out Pose pose)) + { + // On some runtimes, the mesh is moved in its local space instead of world space, + // while its world space location is unchanged. In this case, we want to ensure the + // bounds follow the hand around by manually recalculating them. + meshFilter.mesh.RecalculateBounds(); + + handRenderer.enabled = true; + + if (!initializedUVs && handMeshTracker.TryGetHandMesh(FrameTime.OnUpdate, neutralPoseMesh, HandPoseType.ReferenceOpenPalm)) + { + meshFilter.mesh.uv = InitializeUVs(neutralPoseMesh.vertices); + initializedUVs = true; + } + + transform.SetWorldPose(PlayspaceUtilities.TransformPose(pose)); + UpdateHandMaterial(); + return; + } +#endif + + // Hide the hand if we weren't able to obtain a valid mesh + handRenderer.enabled = false; + } + + protected override bool ShouldRenderHand() + { + // If we're missing anything, don't render the hand. + return meshFilter != null && handRenderer != null && base.ShouldRenderHand(); + } + + protected override void UpdateHandMaterial() + { + base.UpdateHandMaterial(); + + if ((XRSubsystemHelpers.HandsAggregator?.TryGetJoint(TrackedHandJoint.Wrist, HandNode, out HandJointPose wristPose) ?? false) + && XRSubsystemHelpers.HandsAggregator.TryGetJoint(TrackedHandJoint.LittleMetacarpal, HandNode, out HandJointPose littleMetaPose) + && XRSubsystemHelpers.HandsAggregator.TryGetJoint(TrackedHandJoint.ThumbMetacarpal, HandNode, out HandJointPose thumbMetaPose)) + { + HandRenderer.GetPropertyBlock(propertyBlock); + float radius = Vector3.Distance(littleMetaPose.Position, thumbMetaPose.Position); + propertyBlock.SetVector("_FadeSphereCenter", wristPose.Position - (radius * 0.5f * wristPose.Forward)); + propertyBlock.SetFloat("_FadeSphereRadius", radius); + propertyBlock.SetFloat("_FadeDistance", fadeDistance); + HandRenderer.SetPropertyBlock(propertyBlock); + } + } + +#if MROPENXR_PRESENT && (UNITY_STANDALONE_WIN || UNITY_WSA || UNITY_ANDROID) + private static Vector2[] InitializeUVs(Vector3[] neutralPoseVertices) + { + if (neutralPoseVertices?.Length == 0) + { + Debug.LogError("Loaded 0 vertices for neutralPoseVertices"); + return System.Array.Empty(); + } + + float minY = neutralPoseVertices[0].y; + float maxY = minY; + + for (int ix = 1; ix < neutralPoseVertices.Length; ix++) + { + Vector3 p = neutralPoseVertices[ix]; + + if (p.y < minY) + { + minY = p.y; + } + else if (p.y > maxY) + { + maxY = p.y; + } + } + + float scale = 1.0f / (maxY - minY); + + Vector2[] uvs = new Vector2[neutralPoseVertices.Length]; + + for (int ix = 0; ix < neutralPoseVertices.Length; ix++) + { + Vector3 p = neutralPoseVertices[ix]; + + uvs[ix] = new Vector2(p.x * scale + 0.5f, (p.y - minY) * scale); + } + + return uvs; + } +#endif + } +} diff --git a/org.mixedrealitytoolkit.input/Visualizers/PlatformHandVisualizer/PlatformHandMeshVisualizer.cs.meta b/org.mixedrealitytoolkit.input/Visualizers/PlatformHandVisualizer/PlatformHandMeshVisualizer.cs.meta new file mode 100644 index 000000000..5f1d749f5 --- /dev/null +++ b/org.mixedrealitytoolkit.input/Visualizers/PlatformHandVisualizer/PlatformHandMeshVisualizer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f42ee07c35d33c44989eee5953f625d2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/org.mixedrealitytoolkit.input/Visualizers/Prefabs.meta b/org.mixedrealitytoolkit.input/Visualizers/Prefabs.meta new file mode 100644 index 000000000..8fe79ca76 --- /dev/null +++ b/org.mixedrealitytoolkit.input/Visualizers/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: db472eec1a7c5c34a874ee394c08966f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/openxr_left_hand.prefab b/org.mixedrealitytoolkit.input/Visualizers/Prefabs/openxr_left_hand.prefab similarity index 91% rename from org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/openxr_left_hand.prefab rename to org.mixedrealitytoolkit.input/Visualizers/Prefabs/openxr_left_hand.prefab index 37c3a06e3..2219e6279 100644 --- a/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/openxr_left_hand.prefab +++ b/org.mixedrealitytoolkit.input/Visualizers/Prefabs/openxr_left_hand.prefab @@ -5,6 +5,7 @@ PrefabInstance: m_ObjectHideFlags: 0 serializedVersion: 2 m_Modification: + serializedVersion: 3 m_TransformParent: {fileID: 0} m_Modifications: - target: {fileID: -7366846053233975685, guid: da93d751ddc0f64468dfc02f18d02d00, type: 3} @@ -47,6 +48,10 @@ PrefabInstance: propertyPath: m_controllerDetectedAction.m_Name value: Controller Detected objectReference: {fileID: 0} + - target: {fileID: -7366846053233975685, guid: da93d751ddc0f64468dfc02f18d02d00, type: 3} + propertyPath: controllerDetectedAction.m_Reference + value: + objectReference: {fileID: -7613329581162844239, guid: 18c412191cdc9274897f101c7fd5316f, type: 3} - target: {fileID: -7366846053233975685, guid: da93d751ddc0f64468dfc02f18d02d00, type: 3} propertyPath: controllerDetectedAction.m_Action.m_Id value: 4204bd93-73df-4026-97f6-48cc7932da0b @@ -99,6 +104,18 @@ PrefabInstance: propertyPath: controllerDetectedAction.m_Action.m_SingletonActionBindings.Array.data[0].m_Action value: Controller Detected objectReference: {fileID: 0} + - target: {fileID: 1493009138236857671, guid: da93d751ddc0f64468dfc02f18d02d00, type: 3} + propertyPath: m_LocalScale.x + value: -1 + objectReference: {fileID: 0} + - target: {fileID: 1800205545854781715, guid: da93d751ddc0f64468dfc02f18d02d00, type: 3} + propertyPath: handNode + value: 4 + objectReference: {fileID: 0} + - target: {fileID: 2263138549649042646, guid: da93d751ddc0f64468dfc02f18d02d00, type: 3} + propertyPath: handNode + value: 4 + objectReference: {fileID: 0} - target: {fileID: 3507431783398283103, guid: da93d751ddc0f64468dfc02f18d02d00, type: 3} propertyPath: handNode value: 4 @@ -111,10 +128,6 @@ PrefabInstance: propertyPath: m_RootOrder value: 0 objectReference: {fileID: 0} - - target: {fileID: 3973969148631863464, guid: da93d751ddc0f64468dfc02f18d02d00, type: 3} - propertyPath: m_LocalScale.x - value: -1 - objectReference: {fileID: 0} - target: {fileID: 3973969148631863464, guid: da93d751ddc0f64468dfc02f18d02d00, type: 3} propertyPath: m_LocalPosition.x value: 0 @@ -160,4 +173,7 @@ PrefabInstance: value: openxr_left_hand objectReference: {fileID: 0} m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: da93d751ddc0f64468dfc02f18d02d00, type: 3} diff --git a/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/openxr_left_hand.prefab.meta b/org.mixedrealitytoolkit.input/Visualizers/Prefabs/openxr_left_hand.prefab.meta similarity index 100% rename from org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/openxr_left_hand.prefab.meta rename to org.mixedrealitytoolkit.input/Visualizers/Prefabs/openxr_left_hand.prefab.meta diff --git a/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/openxr_right_hand.prefab b/org.mixedrealitytoolkit.input/Visualizers/Prefabs/openxr_right_hand.prefab similarity index 83% rename from org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/openxr_right_hand.prefab rename to org.mixedrealitytoolkit.input/Visualizers/Prefabs/openxr_right_hand.prefab index b5dbb75e4..f9a9b68b3 100644 --- a/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/openxr_right_hand.prefab +++ b/org.mixedrealitytoolkit.input/Visualizers/Prefabs/openxr_right_hand.prefab @@ -23,6 +23,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 16087387050962746} + serializedVersion: 2 m_LocalRotation: {x: -0.04134135, y: 0.020228544, z: 0.07561951, w: 0.996074} m_LocalPosition: {x: 3.0267983e-11, y: 0, z: 0.0004089724} m_LocalScale: {x: 1, y: 0.99999994, z: 0.9999998} @@ -30,7 +31,6 @@ Transform: m_Children: - {fileID: 7427278357790150308} m_Father: {fileID: 5458823143432554036} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &264115022450059308 GameObject: @@ -55,6 +55,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 264115022450059308} + serializedVersion: 2 m_LocalRotation: {x: -0.09019473, y: -0.112213634, z: -0.082327574, w: 0.98615175} m_LocalPosition: {x: 1.6298145e-11, y: 1.3969838e-11, z: 0.00039010096} m_LocalScale: {x: 0.99999994, y: 1, z: 1} @@ -62,7 +63,6 @@ Transform: m_Children: - {fileID: 9006935288519073739} m_Father: {fileID: 498931685021915093} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &488343164757858754 GameObject: @@ -87,6 +87,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 488343164757858754} + serializedVersion: 2 m_LocalRotation: {x: 0.018171376, y: -0.07332422, z: 0.0016571282, w: 0.99714124} m_LocalPosition: {x: -1.2751115e-11, y: 4.4383342e-12, z: 0.00068246824} m_LocalScale: {x: 0.99999994, y: 0.9999999, z: 0.99999994} @@ -94,7 +95,6 @@ Transform: m_Children: - {fileID: 6541163434380589232} m_Father: {fileID: 1077227819275269935} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &550855178322120980 GameObject: @@ -119,6 +119,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 550855178322120980} + serializedVersion: 2 m_LocalRotation: {x: -0.051032774, y: 0.020922784, z: 0.0021605818, w: 0.9984755} m_LocalPosition: {x: -1.8189894e-12, y: -1.4888427e-11, z: 0.00045456158} m_LocalScale: {x: 1, y: 1, z: 0.9999999} @@ -126,7 +127,6 @@ Transform: m_Children: - {fileID: 1828752077698417225} m_Father: {fileID: 8089865949473389596} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &723288405160749330 GameObject: @@ -151,6 +151,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 723288405160749330} + serializedVersion: 2 m_LocalRotation: {x: -0.018254701, y: 0.00089057756, z: 0.0014708434, w: 0.9998319} m_LocalPosition: {x: -5.784386e-12, y: -1.1641532e-12, z: 0.00027976793} m_LocalScale: {x: 0.99999994, y: 0.9999999, z: 0.9999998} @@ -158,7 +159,6 @@ Transform: m_Children: - {fileID: 5817228883765955420} m_Father: {fileID: 8748218160129236693} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &762971720275621074 GameObject: @@ -183,6 +183,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 762971720275621074} + serializedVersion: 2 m_LocalRotation: {x: 0.009341898, y: -0.25212786, z: 0.0016238193, w: 0.9676475} m_LocalPosition: {x: -0, y: 0, z: 0} m_LocalScale: {x: 0.99999994, y: 1, z: 0.99999964} @@ -190,7 +191,6 @@ Transform: m_Children: - {fileID: 6793337788569349462} m_Father: {fileID: 5446693289115484214} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1143263375470404621 GameObject: @@ -215,13 +215,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1143263375470404621} + serializedVersion: 2 m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} m_LocalPosition: {x: -0, y: 0, z: 0.00013116258} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 3640015180784389109} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1449011787537462570 GameObject: @@ -246,6 +246,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1449011787537462570} + serializedVersion: 2 m_LocalRotation: {x: -0.008052746, y: 0.048775665, z: -0.006817606, w: 0.998754} m_LocalPosition: {x: -2.9685907e-11, y: 6.6938807e-12, z: 0.0007289571} m_LocalScale: {x: 1, y: 0.9999999, z: 0.99999994} @@ -253,7 +254,6 @@ Transform: m_Children: - {fileID: 5921367078976266107} m_Father: {fileID: 6793337788569349462} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &2928499560571120432 GameObject: @@ -278,6 +278,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2928499560571120432} + serializedVersion: 2 m_LocalRotation: {x: -0.02028584, y: 0.3819591, z: 0.004533123, w: 0.9239455} m_LocalPosition: {x: -0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1.0000001, z: 1.0000001} @@ -285,7 +286,6 @@ Transform: m_Children: - {fileID: 5334553598884166511} m_Father: {fileID: 5446693289115484214} - m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &3184605578150545217 GameObject: @@ -310,6 +310,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 3184605578150545217} + serializedVersion: 2 m_LocalRotation: {x: -0.016732441, y: -0.41903344, z: 0.6049222, w: 0.67690486} m_LocalPosition: {x: -0, y: 0, z: 0} m_LocalScale: {x: 0.9999999, y: 0.99999976, z: 0.99999964} @@ -317,7 +318,6 @@ Transform: m_Children: - {fileID: 5458823143432554036} m_Father: {fileID: 5446693289115484214} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &3331529553617436422 GameObject: @@ -342,6 +342,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 3331529553617436422} + serializedVersion: 2 m_LocalRotation: {x: 0.049683567, y: -0.0682403, z: 0.005375236, w: 0.99641657} m_LocalPosition: {x: -2.6921044e-12, y: -1.0913936e-13, z: 0.00026415734} m_LocalScale: {x: 1, y: 1, z: 0.99999994} @@ -349,7 +350,6 @@ Transform: m_Children: - {fileID: 6402884463806494666} m_Father: {fileID: 6356967279678601896} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &3914579612821526105 GameObject: @@ -374,6 +374,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 3914579612821526105} + serializedVersion: 2 m_LocalRotation: {x: -0.03612786, y: 0.013062499, z: -0.0013056236, w: 0.99926096} m_LocalPosition: {x: 2.52974e-11, y: 3.3469403e-12, z: 0.00018895004} m_LocalScale: {x: 1.0000001, y: 0.9999999, z: 0.99999994} @@ -381,7 +382,6 @@ Transform: m_Children: - {fileID: 3661087396984794893} m_Father: {fileID: 4528600584950922117} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &3957823326167938785 GameObject: @@ -407,13 +407,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 3957823326167938785} - m_LocalRotation: {x: 0.000000021855694, y: 0, z: -0, w: 1} - m_LocalPosition: {x: -0, y: 0, z: 0} + serializedVersion: 2 + m_LocalRotation: {x: 0.000000021855694, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 100, y: 100, z: 100} m_ConstrainProportionsScale: 0 m_Children: [] - m_Father: {fileID: 3973969148631863464} - m_RootOrder: 0 + m_Father: {fileID: 1493009138236857671} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!137 &5709336421934327412 SkinnedMeshRenderer: @@ -517,13 +517,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 4042160540912683627} + serializedVersion: 2 m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} m_LocalPosition: {x: -0, y: 0, z: 0.00015126375} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 5817228883765955420} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &4122089786851792721 GameObject: @@ -548,6 +548,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 4122089786851792721} + serializedVersion: 2 m_LocalRotation: {x: -0.04099412, y: -0.012571383, z: 0.00082643394, w: 0.99908} m_LocalPosition: {x: -7.858469e-12, y: -4.574758e-12, z: 0.0002651471} m_LocalScale: {x: 0.99999994, y: 0.9999999, z: 1} @@ -555,7 +556,6 @@ Transform: m_Children: - {fileID: 9017335721188770727} m_Father: {fileID: 6541163434380589232} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &4354293980546992658 GameObject: @@ -566,7 +566,6 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 3973969148631863464} - - component: {fileID: 3507431783398283103} - component: {fileID: -7366846053233975685} m_Layer: 0 m_Name: openxr_right_hand @@ -582,33 +581,16 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 4354293980546992658} + serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: - - {fileID: 5499070473167639758} - - {fileID: 5446693289115484214} + - {fileID: 7460324237988116690} + - {fileID: 1493009138236857671} m_Father: {fileID: 0} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &3507431783398283103 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4354293980546992658} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4a4cc0663b372fd4795c4e6d942500fb, type: 3} - m_Name: - m_EditorClassIdentifier: - handNode: 5 - showHandsOnTransparentDisplays: 0 - wrist: {fileID: 5446693289115484214} - handRenderer: {fileID: 5709336421934327412} - pinchAmountMaterialProperty: _PinchAmount --- !u!114 &-7366846053233975685 MonoBehaviour: m_ObjectHideFlags: 0 @@ -624,7 +606,7 @@ MonoBehaviour: handNode: 5 fallbackControllerModel: {fileID: 3339478339056654981, guid: 3bd614f14cda63940b56faf0518b55f3, type: 3} controllerDetectedAction: - m_UseReference: 0 + m_UseReference: 1 m_Action: m_Name: Controller Detected m_Type: 0 @@ -642,7 +624,7 @@ MonoBehaviour: m_Action: Controller Detected m_Flags: 0 m_Flags: 0 - m_Reference: {fileID: 0} + m_Reference: {fileID: 3239510804178183174, guid: 18c412191cdc9274897f101c7fd5316f, type: 3} --- !u!1 &4657295888579565740 GameObject: m_ObjectHideFlags: 0 @@ -666,6 +648,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 4657295888579565740} + serializedVersion: 2 m_LocalRotation: {x: -0.012391907, y: -0.07663214, z: 0.01388792, w: 0.9968857} m_LocalPosition: {x: 1.4151737e-11, y: -1.16415315e-11, z: 0.0006916037} m_LocalScale: {x: 1, y: 1, z: 1} @@ -673,7 +656,6 @@ Transform: m_Children: - {fileID: 4528600584950922117} m_Father: {fileID: 5334553598884166511} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &5237677254925488276 GameObject: @@ -698,6 +680,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 5237677254925488276} + serializedVersion: 2 m_LocalRotation: {x: -0.02189448, y: 0.011967821, z: 0.000007822243, w: 0.9996887} m_LocalPosition: {x: 4.5656634e-12, y: -2.2937456e-11, z: 0.00041979662} m_LocalScale: {x: 0.99999994, y: 1, z: 1} @@ -705,8 +688,141 @@ Transform: m_Children: - {fileID: 6273793641032179826} m_Father: {fileID: 2464973069511612448} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &5460435942034699144 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7460324237988116690} + - component: {fileID: 3936565761691908697} + - component: {fileID: 769216864695519206} + - component: {fileID: 2263138549649042646} + m_Layer: 0 + m_Name: PlatformHandMesh + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7460324237988116690 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5460435942034699144} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 3973969148631863464} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &3936565761691908697 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5460435942034699144} + m_Mesh: {fileID: 0} +--- !u!23 &769216864695519206 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5460435942034699144} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 4c63e230f530e6c4e8be8b25846c0989, type: 2} + - {fileID: 2100000, guid: 5138877b31bc96046b8d186cd276d724, type: 2} + - {fileID: 2100000, guid: d2ac3579866c33749b7ac30d8393d4e2, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!114 &2263138549649042646 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5460435942034699144} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f42ee07c35d33c44989eee5953f625d2, type: 3} + m_Name: + m_EditorClassIdentifier: + handNode: 5 + showHandsOnTransparentDisplays: 0 + pinchAmountMaterialProperty: _PinchAmount + selectInput: + m_InputSourceMode: 2 + m_InputActionPerformed: + m_Name: Select + m_Type: 1 + m_ExpectedControlType: + m_Id: 5a174afe-679f-4e85-a45a-988046773313 + m_Processors: + m_Interactions: + m_SingletonActionBindings: [] + m_Flags: 0 + m_InputActionValue: + m_Name: Select Value + m_Type: 0 + m_ExpectedControlType: Axis + m_Id: 8594ff63-7803-4c60-a5c8-62dc67ba5c1a + m_Processors: + m_Interactions: + m_SingletonActionBindings: [] + m_Flags: 0 + m_InputActionReferencePerformed: {fileID: 0} + m_InputActionReferenceValue: {fileID: 0} + m_ObjectReferenceObject: {fileID: 0} + m_ManualPerformed: 0 + m_ManualValue: 0 + m_ManualQueuePerformed: 0 + m_ManualQueueWasPerformedThisFrame: 0 + m_ManualQueueWasCompletedThisFrame: 0 + m_ManualQueueValue: 0 + m_ManualQueueTargetFrame: 0 + meshFilter: {fileID: 3936565761691908697} + handRenderer: {fileID: 769216864695519206} + fadeDistance: 0.025 --- !u!1 &5839269735351241340 GameObject: m_ObjectHideFlags: 0 @@ -730,8 +846,9 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 5839269735351241340} - m_LocalRotation: {x: 0.000000021855694, y: 0, z: -0, w: 1} - m_LocalPosition: {x: -0, y: 0, z: 0} + serializedVersion: 2 + m_LocalRotation: {x: 0.000000021855694, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 100, y: 100, z: 100} m_ConstrainProportionsScale: 0 m_Children: @@ -740,8 +857,7 @@ Transform: - {fileID: 3103993496388122979} - {fileID: 6356967279678601896} - {fileID: 4523630147034299841} - m_Father: {fileID: 3973969148631863464} - m_RootOrder: 1 + m_Father: {fileID: 1493009138236857671} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &6303298619132591738 GameObject: @@ -766,6 +882,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 6303298619132591738} + serializedVersion: 2 m_LocalRotation: {x: 0.041502926, y: 0.1045213, z: -0.014521739, w: 0.9935502} m_LocalPosition: {x: -1.1641532e-12, y: 9.3132255e-12, z: 0.00037181645} m_LocalScale: {x: 1, y: 0.99999994, z: 0.9999998} @@ -773,8 +890,89 @@ Transform: m_Children: - {fileID: 498931685021915093} m_Father: {fileID: 1529682561352593866} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &6309398931433067091 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1493009138236857671} + - component: {fileID: 1800205545854781715} + m_Layer: 0 + m_Name: RiggedHandMesh + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1493009138236857671 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6309398931433067091} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 5499070473167639758} + - {fileID: 5446693289115484214} + m_Father: {fileID: 3973969148631863464} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1800205545854781715 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6309398931433067091} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4a4cc0663b372fd4795c4e6d942500fb, type: 3} + m_Name: + m_EditorClassIdentifier: + handNode: 5 + showHandsOnTransparentDisplays: 0 + pinchAmountMaterialProperty: _PinchAmount + selectInput: + m_InputSourceMode: 2 + m_InputActionPerformed: + m_Name: Select + m_Type: 1 + m_ExpectedControlType: + m_Id: 455696a2-5c34-4e97-838a-bc2b6ac85675 + m_Processors: + m_Interactions: + m_SingletonActionBindings: [] + m_Flags: 0 + m_InputActionValue: + m_Name: Select Value + m_Type: 0 + m_ExpectedControlType: Axis + m_Id: de553aeb-f229-4e9f-af88-39757e695f7d + m_Processors: + m_Interactions: + m_SingletonActionBindings: [] + m_Flags: 0 + m_InputActionReferencePerformed: {fileID: 0} + m_InputActionReferenceValue: {fileID: 0} + m_ObjectReferenceObject: {fileID: 0} + m_ManualPerformed: 0 + m_ManualValue: 0 + m_ManualQueuePerformed: 0 + m_ManualQueueWasPerformedThisFrame: 0 + m_ManualQueueWasCompletedThisFrame: 0 + m_ManualQueueValue: 0 + m_ManualQueueTargetFrame: 0 + wrist: {fileID: 5446693289115484214} + handRenderer: {fileID: 5709336421934327412} + primaryMeshVisualizer: {fileID: 2263138549649042646} --- !u!1 &6561479249547925302 GameObject: m_ObjectHideFlags: 0 @@ -798,13 +996,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 6561479249547925302} + serializedVersion: 2 m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} m_LocalPosition: {x: -0, y: 0, z: 0.00015497528} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 6273793641032179826} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &6594130182080127020 GameObject: @@ -829,6 +1027,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 6594130182080127020} + serializedVersion: 2 m_LocalRotation: {x: 0.0032687124, y: 0.0924356, z: -0.00006233817, w: 0.99571335} m_LocalPosition: {x: -2.0396662e-12, y: -4.206413e-14, z: 0.0002682099} m_LocalScale: {x: 1, y: 1, z: 1} @@ -836,7 +1035,6 @@ Transform: m_Children: - {fileID: 8089865949473389596} m_Father: {fileID: 3103993496388122979} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &6832599985986192355 GameObject: @@ -861,13 +1059,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 6832599985986192355} + serializedVersion: 2 m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} m_LocalPosition: {x: -0, y: 0, z: 0.00017717812} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1828752077698417225} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &6963568092490684223 GameObject: @@ -892,6 +1090,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 6963568092490684223} + serializedVersion: 2 m_LocalRotation: {x: 0.00078201893, y: -0.08185144, z: 0.000027665115, w: 0.99664426} m_LocalPosition: {x: -0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 0.9999999} @@ -899,7 +1098,6 @@ Transform: m_Children: - {fileID: 3556776435536246939} m_Father: {fileID: 5446693289115484214} - m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &7416932990957639745 GameObject: @@ -924,6 +1122,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 7416932990957639745} + serializedVersion: 2 m_LocalRotation: {x: 0.06741448, y: -0.024361538, z: -0.0017286513, w: 0.9974261} m_LocalPosition: {x: -1.0143708e-12, y: 2.046363e-14, z: 0.00072257634} m_LocalScale: {x: 0.99999994, y: 1, z: 0.99999994} @@ -931,7 +1130,6 @@ Transform: m_Children: - {fileID: 7322559479628339466} m_Father: {fileID: 3556776435536246939} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &7446434647064107278 GameObject: @@ -956,6 +1154,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 7446434647064107278} + serializedVersion: 2 m_LocalRotation: {x: 0.004451058, y: -0.005708242, z: -0.000026027026, w: 0.99997383} m_LocalPosition: {x: -6.175469e-12, y: 2.6648193e-12, z: 0.00027607955} m_LocalScale: {x: 1, y: 1, z: 1} @@ -963,7 +1162,6 @@ Transform: m_Children: - {fileID: 2700898927078924524} m_Father: {fileID: 7322559479628339466} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &7522984908696370401 GameObject: @@ -988,6 +1186,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 7522984908696370401} + serializedVersion: 2 m_LocalRotation: {x: -0.04126447, y: 0.042427324, z: 0.00036548893, w: 0.99824697} m_LocalPosition: {x: 1.2982326e-11, y: 9.363248e-12, z: 0.00024728195} m_LocalScale: {x: 1, y: 0.9999999, z: 0.9999999} @@ -995,7 +1194,6 @@ Transform: m_Children: - {fileID: 8610246813914124521} m_Father: {fileID: 5921367078976266107} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &7630331428036862893 GameObject: @@ -1020,13 +1218,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 7630331428036862893} + serializedVersion: 2 m_LocalRotation: {x: 0, y: -0, z: -0, w: 1} m_LocalPosition: {x: -0, y: 0, z: 0.0002066094} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 7427278357790150308} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &7764930180859818638 GameObject: @@ -1051,6 +1249,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 7764930180859818638} + serializedVersion: 2 m_LocalRotation: {x: 0.115323275, y: -0.2855898, z: 0.024722293, w: 0.9510667} m_LocalPosition: {x: 1.117769e-11, y: 0, z: 0.00028927124} m_LocalScale: {x: 0.99999994, y: 0.99999994, z: 0.99999994} @@ -1058,7 +1257,6 @@ Transform: m_Children: - {fileID: 8748218160129236693} m_Father: {fileID: 4523630147034299841} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &7922940236267228883 GameObject: @@ -1083,6 +1281,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 7922940236267228883} + serializedVersion: 2 m_LocalRotation: {x: 0.036102794, y: 0.18826051, z: -0.0076552806, w: 0.9814255} m_LocalPosition: {x: 0.000009, y: -0.000002, z: 0.000321} m_LocalScale: {x: 1, y: 0.99999994, z: 1} @@ -1090,7 +1289,6 @@ Transform: m_Children: - {fileID: 2464973069511612448} m_Father: {fileID: 872140809330182763} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &7960153440799608892 GameObject: @@ -1115,6 +1313,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 7960153440799608892} + serializedVersion: 2 m_LocalRotation: {x: -0.009721841, y: 0.13904916, z: 0.0008851419, w: 0.99023736} m_LocalPosition: {x: -0, y: 0, z: 0} m_LocalScale: {x: 1, y: 0.99999994, z: 0.9999997} @@ -1122,7 +1321,6 @@ Transform: m_Children: - {fileID: 1077227819275269935} m_Father: {fileID: 5446693289115484214} - m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &8261617224528375871 GameObject: @@ -1147,6 +1345,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 8261617224528375871} + serializedVersion: 2 m_LocalRotation: {x: -0.0051415353, y: 0.005024616, z: 0.0022183317, w: 0.9999717} m_LocalPosition: {x: -2.0008884e-12, y: -7.639755e-12, z: 0.0004286098} m_LocalScale: {x: 1, y: 1, z: 1} @@ -1154,5 +1353,4 @@ Transform: m_Children: - {fileID: 3640015180784389109} m_Father: {fileID: 6402884463806494666} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/openxr_right_hand.prefab.meta b/org.mixedrealitytoolkit.input/Visualizers/Prefabs/openxr_right_hand.prefab.meta similarity index 100% rename from org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/openxr_right_hand.prefab.meta rename to org.mixedrealitytoolkit.input/Visualizers/Prefabs/openxr_right_hand.prefab.meta diff --git a/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/RiggedHand-InvertedShell.mat b/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/RiggedHand-InvertedShell.mat index 83dab5e11..b61238583 100644 --- a/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/RiggedHand-InvertedShell.mat +++ b/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/RiggedHand-InvertedShell.mat @@ -9,6 +9,8 @@ Material: m_PrefabAsset: {fileID: 0} m_Name: RiggedHand-InvertedShell m_Shader: {fileID: 4800000, guid: 1e78bf4fa2e9ae0459a4b1836f7a74b5, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 m_ValidKeywords: [] m_InvalidKeywords: [] m_LightmapFlags: 4 @@ -17,6 +19,7 @@ Material: m_CustomRenderQueue: -1 stringTagMap: {} disabledShaderPasses: [] + m_LockedProperties: m_SavedProperties: serializedVersion: 3 m_TexEnvs: @@ -30,6 +33,8 @@ Material: - _Displacement_: 0 - _Enable_: 1 - _Exponent_: 2.16 + - _FadeDistance: 0.025 + - _FadeSphereRadius: 0.05 - _Fade_In_End_: 0 - _Fade_In_Start_: 0 - _HandThickness: 0 @@ -39,7 +44,7 @@ Material: - _Metallic: 0 - _OutlineExponent: 1 - _OutlineSmoothing: 0.05 - - _OutlineThickness: 0.00001337 + - _OutlineThickness: 0.0012 - _OutlineThreshold: 0.474 - _PinchAmount: 0 - _Radius_: 0.09 @@ -47,6 +52,7 @@ Material: m_Colors: - _Center_: {r: 0.5, g: 0.5, b: 0, a: 0} - _Color_: {r: 1, g: 1, b: 1, a: 1} + - _FadeSphereCenter: {r: 0, g: 0, b: 0, a: 1} - _HandColor: {r: 0.14150941, g: 0.14150941, b: 0.14150941, a: 0.7137255} - _OutlineColor: {r: 1, g: 1, b: 1, a: 0.03529412} - _OutlineColorPinching: {r: 1, g: 1, b: 1, a: 1} diff --git a/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/RiggedHand-Main.mat b/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/RiggedHand-Main.mat index 60925901f..933443742 100644 --- a/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/RiggedHand-Main.mat +++ b/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/RiggedHand-Main.mat @@ -9,6 +9,8 @@ Material: m_PrefabAsset: {fileID: 0} m_Name: RiggedHand-Main m_Shader: {fileID: 4800000, guid: 618b0da8e4e6bb2459a1cc27acf0dd57, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 m_ValidKeywords: [] m_InvalidKeywords: [] m_LightmapFlags: 4 @@ -17,6 +19,7 @@ Material: m_CustomRenderQueue: -1 stringTagMap: {} disabledShaderPasses: [] + m_LockedProperties: m_SavedProperties: serializedVersion: 3 m_TexEnvs: @@ -30,6 +33,8 @@ Material: - _Displacement_: 0 - _Enable_: 1 - _Exponent_: 2.16 + - _FadeDistance: 0.025 + - _FadeSphereRadius: 0.05 - _Fade_In_End_: 0 - _Fade_In_Start_: 0 - _HandThickness: 0 @@ -47,6 +52,7 @@ Material: m_Colors: - _Center_: {r: 0.5, g: 0.5, b: 0, a: 0} - _Color_: {r: 1, g: 1, b: 1, a: 1} + - _FadeSphereCenter: {r: 0, g: 0, b: 0, a: 1} - _HandColor: {r: 0.01886791, g: 0.01886791, b: 0.01886791, a: 0.8} - _OutlineColor: {r: 1, g: 1, b: 1, a: 0.2901961} - _OutlineColorPinching: {r: 1, g: 1, b: 1, a: 1} diff --git a/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/RiggedHandMeshVisualizer.cs b/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/RiggedHandMeshVisualizer.cs index 6fb8f0fe8..4b039cb50 100644 --- a/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/RiggedHandMeshVisualizer.cs +++ b/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/RiggedHandMeshVisualizer.cs @@ -2,13 +2,10 @@ // Licensed under the BSD 3-Clause using MixedReality.Toolkit.Subsystems; -using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.XR; -using UnityEngine.XR.Interaction.Toolkit; -using UnityEngine.XR.Interaction.Toolkit.Inputs.Readers; namespace MixedReality.Toolkit.Input { @@ -22,33 +19,8 @@ namespace MixedReality.Toolkit.Input /// can be more distracting than it's worth. However, for opaque platforms, this is a great solution. /// [AddComponentMenu("MRTK/Input/Visualizers/Rigged Hand Mesh Visualizer")] - public class RiggedHandMeshVisualizer : MonoBehaviour, ISelectInputVisualizer + public class RiggedHandMeshVisualizer : HandMeshVisualizer { - [SerializeField] - [Tooltip("The XRNode on which this hand is located.")] - private XRNode handNode = XRNode.LeftHand; - - /// The XRNode on which this hand is located. - public XRNode HandNode { get => handNode; set => handNode = value; } - - [SerializeField] - [Tooltip("When true, this visualizer will render rigged hands even on XR devices " + - "with transparent displays. When false, the rigged hands will only render " + - "on devices with opaque displays.")] - private bool showHandsOnTransparentDisplays; - - /// - /// When true, this visualizer will render rigged hands even on XR devices with transparent displays. - /// When false, the rigged hands will only render on devices with opaque displays. - /// Usually, it's recommended not to show hand visualization on transparent displays as it can - /// distract from the user's real hands, and cause a "double image" effect that can be disconcerting. - /// - public bool ShowHandsOnTransparentDisplays - { - get => showHandsOnTransparentDisplays; - set => showHandsOnTransparentDisplays = value; - } - [SerializeField] [Tooltip("The transform of the wrist joint.")] private Transform wrist; @@ -58,44 +30,19 @@ public bool ShowHandsOnTransparentDisplays private SkinnedMeshRenderer handRenderer = null; [SerializeField] - [Tooltip("Name of the shader property used to drive pinch-amount-based visual effects. " + - "Generally, maps to something like a glow or an outline color!")] - private string pinchAmountMaterialProperty = "_PinchAmount"; + [Tooltip("The primary visualizer. Rigged hand will not render if the primary is rendering.")] + private HandMeshVisualizer primaryMeshVisualizer = null; - [SerializeField] - [Tooltip("The input reader used when pinch selecting an interactable.")] - XRInputButtonReader selectInput = new XRInputButtonReader("Select"); - - #region ISelectInputVisualizer implementation - - /// - /// Input reader used when pinch selecting an interactable. - /// - public XRInputButtonReader SelectInput - { - get => selectInput; - set => SetInputProperty(ref selectInput, value); - } - - #endregion ISelectInputVisualizer implementation + /// + protected override Renderer HandRenderer => handRenderer; // Automatically calculated over time, based on the accumulated error // between the user's actual joint locations and the armature's bones/joints. private float handScale = 1.0f; - // The property block used to modify the pinch amount property on the material - private MaterialPropertyBlock propertyBlock = null; - - // Caching local references + // Caching local references private HandsAggregatorSubsystem handsSubsystem; - // Scratch list for checking for the presence of display subsystems. - private List displaySubsystems = new List(); - - // The XRController that is used to determine the pinch strength (i.e., select value!) - [Obsolete("This field has been deprecated in version 4.0.0 and will be removed in a future version. Use the SelectInput property instead.")] - private XRBaseController controller; - // The actual, physical, rigged joints that drive the skinned mesh. // Otherwise referred to as "armature". Must be in OpenXR order. private readonly Transform[] riggedVisualJointsArray = new Transform[(int)TrackedHandJoint.TotalJoints]; @@ -104,21 +51,12 @@ public XRInputButtonReader SelectInput // at the end of a finger, which is discarded. private const string endJointName = "end"; - /// - /// The list of button input readers used by this interactor. This interactor will automatically enable or disable direct actions - /// if that mode is used during and . - /// - /// - /// - protected List buttonReaders { get; } = new List(); - /// /// A Unity event function that is called when an enabled script instance is being loaded. /// - protected virtual void Awake() + protected override void Awake() { - propertyBlock = new MaterialPropertyBlock(); - buttonReaders.Add(selectInput); + base.Awake(); if (handRenderer == null) { @@ -160,18 +98,10 @@ protected virtual void Awake() } } - /// - /// A Unity event function that is called when the script component has been enabled. - /// - protected void OnEnable() + /// + protected override void OnEnable() { - buttonReaders.ForEach(reader => reader?.EnableDirectActionIfModeUsed()); - - // Ensure hand is not visible until we can update position first time. - handRenderer.enabled = false; - - Debug.Assert(handNode == XRNode.LeftHand || handNode == XRNode.RightHand, - $"HandVisualizer has an invalid XRNode ({handNode})!"); + base.OnEnable(); handsSubsystem = XRSubsystemHelpers.GetFirstRunningSubsystem(); @@ -181,17 +111,6 @@ protected void OnEnable() } } - /// - /// A Unity event function that is called when the script component has been disabled. - /// - protected void OnDisable() - { - buttonReaders.ForEach(reader => reader?.DisableDirectActionIfModeUsed()); - - // Disable the rigged hand renderer when this component is disabled - handRenderer.enabled = false; - } - /// /// Coroutine to wait until subsystem becomes available. /// @@ -204,11 +123,11 @@ private IEnumerator EnableWhenSubsystemAvailable() /// /// A Unity event function that is called every frame, if this object is enabled. /// - private void Update() + protected void Update() { // Query all joints in the hand. if (!ShouldRenderHand() || - !handsSubsystem.TryGetEntireHand(handNode, out IReadOnlyList joints)) + !handsSubsystem.TryGetEntireHand(HandNode, out IReadOnlyList joints)) { // Hide the hand and abort if we shouldn't be // showing the hand, for whatever reason. @@ -293,49 +212,12 @@ private void Update() // Apply. handScale += -error * errorGainFactor; handScale = Mathf.Clamp(handScale, minScale, maxScale); - transform.localScale = new Vector3(handNode == XRNode.LeftHand ? -handScale : handScale, handScale, handScale); + transform.localScale = new Vector3(HandNode == XRNode.LeftHand ? -handScale : handScale, handScale, handScale); // Update the hand material based on selectedness value UpdateHandMaterial(); } - /// - /// Helper method for setting an input property. - /// - /// The to the field. - /// The new value being set. - /// - /// If the application is playing, this method will also enable or disable directly embedded input actions - /// serialized by the input if that mode is used. It will also add or remove the input from the list of button inputs - /// to automatically manage enabling and disabling direct actions with this behavior. - /// - /// - protected void SetInputProperty(ref XRInputButtonReader property, XRInputButtonReader value) - { - if (value == null) - { - Debug.LogError("Setting XRInputButtonReader property to null is disallowed and has therefore been ignored."); - return; - } - - if (Application.isPlaying && property != null) - { - buttonReaders?.Remove(property); - property.DisableDirectActionIfModeUsed(); - } - - property = value; - - if (Application.isPlaying) - { - buttonReaders?.Add(property); - if (isActiveAndEnabled) - { - property.EnableDirectActionIfModeUsed(); - } - } - } - // Computes the error between the rig's joint position and // the user's joint position along the finger vector. private float JointError(Vector3 armatureJointPosition, Vector3 userJointPosition, Vector3 fingerVector) @@ -346,78 +228,15 @@ private float JointError(Vector3 armatureJointPosition, Vector3 userJointPositio return Vector3.Dot((armatureJointPosition - userJointPosition), fingerVector); } - private bool ShouldRenderHand() + protected override bool ShouldRenderHand() { // If we're missing anything, don't render the hand. - if (handsSubsystem == null || wrist == null || handRenderer == null) - { - return false; - } - - if (displaySubsystems.Count == 0) - { - SubsystemManager.GetSubsystems(displaySubsystems); - } - - // Are we running on an XR display and it happens to be transparent? - // Probably shouldn't be showing rigged hands! (Users can - // specify showHandsOnTransparentDisplays if they disagree.) - if (displaySubsystems.Count > 0 && - displaySubsystems[0].running && - !displaySubsystems[0].displayOpaque && - !showHandsOnTransparentDisplays) - { - return false; - } - - // All checks out! - return true; - } - - private void UpdateHandMaterial() - { - if (handRenderer == null) - { - return; - } - - // Update the hand material - float pinchAmount = TryGetSelectionValue(out float selectionValue) ? Mathf.Pow(selectionValue, 2.0f) : 0; - handRenderer.GetPropertyBlock(propertyBlock); - propertyBlock.SetFloat(pinchAmountMaterialProperty, pinchAmount); - handRenderer.SetPropertyBlock(propertyBlock); - } - - /// - /// Try to obtain the tracked devices selection value from the provided input reader. - /// - /// - /// For backwards compatibility, this method will also attempt to get the selection amount from a - /// legacy XRI controller if the input reader is not set. - /// - private bool TryGetSelectionValue(out float value) - { - if (selectInput != null && selectInput.TryReadValue(out value)) - { - return true; - } - - bool success = false; - value = 0.0f; - -#pragma warning disable CS0618 // XRBaseController is obsolete - if (controller == null) - { - controller = GetComponentInParent(); - } - if (controller != null) - { - value = controller.selectInteractionState.value; - success = true; - } -#pragma warning restore CS0618 // XRBaseController is obsolete - - return success; + // Also don't render if the preferred visualizer is rendering. + return handsSubsystem != null + && wrist != null + && handRenderer != null + && (primaryMeshVisualizer == null || !primaryMeshVisualizer.IsRendering) + && base.ShouldRenderHand(); } } } diff --git a/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/TransparentOutlinedHand-InvertedShell.shader b/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/TransparentOutlinedHand-InvertedShell.shader index 2e80117a6..4ccc98705 100644 --- a/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/TransparentOutlinedHand-InvertedShell.shader +++ b/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/TransparentOutlinedHand-InvertedShell.shader @@ -13,9 +13,12 @@ Shader "Mixed Reality Toolkit/Transparent Outlined Hand (Inverted Shell)" { Properties { _OutlineColor ("Outline Color", Color) = (1,1,1,1) _OutlineColorPinching ("Outline Color (Pinching)", Color) = (1,1,1,1) - _OutlineThickness ("_OutlineThickness", Range(0.0,0.00003)) = 0.000012 - _HandThickness ("_HandThickness", Range(-0.0001,0.0001)) = 0.0 + _OutlineThickness ("Outline Thickness", Range(0.0,0.003)) = 0.0012 + _HandThickness ("Hand Thickness", Range(-0.01,0.01)) = 0.0 [PerRendererData]_PinchAmount ("Pinch Amount", Float) = 0 + [PerRendererData]_FadeSphereCenter ("Fade Sphere Center", Vector) = (0,0,0,1) + [PerRendererData]_FadeSphereRadius ("Fade Sphere Radius", Range(0,1)) = 0.05 + [PerRendererData]_FadeDistance ("Fade Distance", Range(0,1)) = 0.025 } SubShader { @@ -48,6 +51,7 @@ Shader "Mixed Reality Toolkit/Transparent Outlined Hand (Inverted Shell)" { float4 vertex : POSITION; float4 color : COLOR; float3 normal : NORMAL; + float3 worldPos : TEXCOORD1; UNITY_VERTEX_OUTPUT_STEREO }; @@ -61,16 +65,21 @@ Shader "Mixed Reality Toolkit/Transparent Outlined Hand (Inverted Shell)" { UNITY_INITIALIZE_OUTPUT(v2f, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + float4 objectPos = v.vertex + normalize(v.normal) * (_HandThickness + _OutlineThickness); o.normal = UnityObjectToWorldNormal(v.normal); - o.vertex = UnityObjectToClipPos(v.vertex + v.normal * (_HandThickness + _OutlineThickness)); + o.vertex = UnityObjectToClipPos(objectPos); o.color = v.color; - + o.worldPos = mul(unity_ObjectToWorld, objectPos).xyz; + return o; } uniform float4 _OutlineColor; uniform float4 _OutlineColorPinching; uniform float _PinchAmount; + uniform float4 _FadeSphereCenter; + uniform float _FadeSphereRadius; + uniform float _FadeDistance; fixed4 frag(v2f i) : SV_Target { @@ -81,7 +90,9 @@ Shader "Mixed Reality Toolkit/Transparent Outlined Hand (Inverted Shell)" { // Fade the entire result based on the red channel. This is used to fade the hand // out by the wrist, so the abrupt edge of the hand model is not visible. - return float4(blendedOutlineColor.r, blendedOutlineColor.g, blendedOutlineColor.b, blendedOutlineColor.a * i.color.r); + return float4(blendedOutlineColor.r, blendedOutlineColor.g, blendedOutlineColor.b, + blendedOutlineColor.a * + ((_FadeSphereCenter.w * i.color.r) + ((1 - _FadeSphereCenter.w) * smoothstep(_FadeSphereRadius, _FadeSphereRadius + _FadeDistance, distance(i.worldPos, _FadeSphereCenter))))); } ENDCG diff --git a/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/TransparentOutlinedHand-Main.shader b/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/TransparentOutlinedHand-Main.shader index 401bcd452..f50ccd33b 100644 --- a/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/TransparentOutlinedHand-Main.shader +++ b/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/TransparentOutlinedHand-Main.shader @@ -12,9 +12,12 @@ Shader "Mixed Reality Toolkit/Transparent Outlined Hand (Main)" { Properties { _HandColor ("Hand Color", Color) = (1,1,1,1) - _HandThickness ("_HandThickness", Range(-0.0001,0.0001)) = 0.0 + _HandThickness ("Hand Thickness", Range(-0.01,0.01)) = 0.0 _IlluminationExponent ("Illumination Exponent", Range(0,10)) = 1 _IlluminationAmount ("Illumination Amount", Range(0,10)) = 1 + [PerRendererData]_FadeSphereCenter ("Fade Sphere Center", Vector) = (0,0,0,1) + [PerRendererData]_FadeSphereRadius ("Fade Sphere Radius", Range(0,1)) = 0.05 + [PerRendererData]_FadeDistance ("Fade Distance", Range(0,1)) = 0.025 } SubShader { @@ -46,6 +49,7 @@ Shader "Mixed Reality Toolkit/Transparent Outlined Hand (Main)" { float4 color : COLOR; float3 normal : NORMAL; float3 viewDir: TEXCOORD1; + float3 worldPos : TEXCOORD2; UNITY_VERTEX_OUTPUT_STEREO }; @@ -58,9 +62,11 @@ Shader "Mixed Reality Toolkit/Transparent Outlined Hand (Main)" { UNITY_INITIALIZE_OUTPUT(v2f, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); + float4 objectPos = v.vertex + normalize(v.normal) * _HandThickness; o.normal = UnityObjectToWorldNormal(v.normal); - o.vertex = UnityObjectToClipPos(v.vertex + v.normal * _HandThickness); + o.vertex = UnityObjectToClipPos(objectPos); o.color = v.color; + o.worldPos = mul(unity_ObjectToWorld, objectPos).xyz; // Distance-invariant view pos. Create "normalized view point" // offset from object origin, then construct a new view vector @@ -76,6 +82,9 @@ Shader "Mixed Reality Toolkit/Transparent Outlined Hand (Main)" { uniform float _IlluminationAmount; uniform float _IlluminationExponent; uniform float4 _HandColor; + uniform float4 _FadeSphereCenter; + uniform float _FadeSphereRadius; + uniform float _FadeDistance; fixed4 frag(v2f i) : SV_Target { @@ -84,7 +93,8 @@ Shader "Mixed Reality Toolkit/Transparent Outlined Hand (Main)" { // Blend base color with the illumination/spotlight. float4 hand = _HandColor + pow(spotlight, _IlluminationExponent) * _IlluminationAmount; - return hand * float4(1,1,1,i.color.r); + return hand * float4(1,1,1, + ((_FadeSphereCenter.w * i.color.r) + ((1 - _FadeSphereCenter.w) * smoothstep(_FadeSphereRadius, _FadeSphereRadius + _FadeDistance, distance(i.worldPos, _FadeSphereCenter))))); } ENDCG diff --git a/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/TransparentOutlinedHand-PrepassZ.shader b/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/TransparentOutlinedHand-PrepassZ.shader index a32b1ef18..db0065d1b 100644 --- a/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/TransparentOutlinedHand-PrepassZ.shader +++ b/org.mixedrealitytoolkit.input/Visualizers/RiggedHandVisualizer/TransparentOutlinedHand-PrepassZ.shader @@ -50,7 +50,7 @@ Shader "Mixed Reality Toolkit/Transparent Outlined Hand (PrepassZ)" { UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); // Inflate/deflate hand based on thickness. - o.vertex = UnityObjectToClipPos(v.vertex + v.normal * _HandThickness); + o.vertex = UnityObjectToClipPos(v.vertex + normalize(v.normal) * _HandThickness); return o; } diff --git a/org.mixedrealitytoolkit.input/package.json b/org.mixedrealitytoolkit.input/package.json index a8d509f42..590b61790 100644 --- a/org.mixedrealitytoolkit.input/package.json +++ b/org.mixedrealitytoolkit.input/package.json @@ -21,7 +21,7 @@ "com.unity.inputsystem": "1.6.1", "com.unity.xr.arfoundation": "5.0.5", "com.unity.xr.core-utils": "2.1.0", - "com.unity.xr.hands": "1.3.0", + "com.unity.xr.hands": "1.6.0", "com.unity.xr.interaction.toolkit": "3.0.4", "org.mixedrealitytoolkit.core": "4.0.0" }