From c59dfe69aa83bd100612b5ef9666d191ccd6bbdd Mon Sep 17 00:00:00 2001 From: Marlena Klein Date: Tue, 11 Jul 2023 15:44:17 -0700 Subject: [PATCH 1/7] Consolidate LocateTargetHitPoint functions into one helper function --- .../SpatialMouseInteractorCursorVisual.cs | 53 +------------ .../InteractorVisuals/Lines/LineUtility.cs | 76 +++++++++++++++++++ .../InteractorVisuals/MRTKLineVisual.cs | 69 ++--------------- .../InteractorVisuals/MRTKRayReticleVisual.cs | 66 ++-------------- 4 files changed, 90 insertions(+), 174 deletions(-) diff --git a/com.microsoft.mrtk.input/Experimental/SpatialMouse/Interactor/SpatialMouseInteractorCursorVisual.cs b/com.microsoft.mrtk.input/Experimental/SpatialMouse/Interactor/SpatialMouseInteractorCursorVisual.cs index b0f41da6d40..6abb46df080 100644 --- a/com.microsoft.mrtk.input/Experimental/SpatialMouse/Interactor/SpatialMouseInteractorCursorVisual.cs +++ b/com.microsoft.mrtk.input/Experimental/SpatialMouse/Interactor/SpatialMouseInteractorCursorVisual.cs @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using System.Diagnostics; using UnityEngine; -using UnityEngine.Rendering; using UnityEngine.XR.Interaction.Toolkit; +using static Microsoft.MixedReality.Toolkit.Input.LineUtility; namespace Microsoft.MixedReality.Toolkit.Input.Experimental { @@ -53,9 +52,7 @@ protected virtual void OnDisable() Application.onBeforeRender -= OnBeforeRenderCursor; } - private Vector3 targetLocalHitPoint; - private Vector3 targetLocalHitNormal; - private Transform hitTargetTransform; + private TargetHitInfo selectedHitInfo = new TargetHitInfo(); // reusable lists of the points returned by the XRRayInteractor Vector3[] rayPositions; @@ -68,49 +65,7 @@ protected virtual void OnDisable() private void LocateTargetHitPoint(SelectEnterEventArgs args) { - // If no hit, abort. - if (!mouseInteractor.TryGetCurrentRaycast( - out RaycastHit? raycastHit, - out _, - out UnityEngine.EventSystems.RaycastResult? raycastResult, - out _, - out bool isUIHitClosest)) - { - return; - } - - // Sanity check. - if (rayPositions == null || - rayPositions.Length == 0 || - rayPositionsCount == 0 || - rayPositionsCount > rayPositions.Length) - { - return; - } - - // Record relevant data about the hit point. - if (raycastResult.HasValue && isUIHitClosest) - { - hitTargetTransform = raycastResult.Value.gameObject.transform; - targetLocalHitPoint = hitTargetTransform.InverseTransformPoint(raycastResult.Value.worldPosition); - targetLocalHitNormal = hitTargetTransform.InverseTransformDirection(raycastResult.Value.worldNormal); - } - else if (raycastHit.HasValue) - { - // In the case of affordances/handles, we can stick the ray right on to the handle. - if (args.interactableObject is ISnapInteractable snappable) - { - hitTargetTransform = snappable.HandleTransform; - targetLocalHitPoint = Vector3.zero; - targetLocalHitNormal = Vector3.up; - } - else - { - hitTargetTransform = raycastHit.Value.collider.transform; - targetLocalHitPoint = hitTargetTransform.InverseTransformPoint(raycastHit.Value.point); - targetLocalHitNormal = hitTargetTransform.InverseTransformPoint(raycastHit.Value.normal); - } - } + selectedHitInfo = mouseInteractor.LocateTargetHitPoint(args.interactableObject); } private void OnBeforeRenderCursor() @@ -142,7 +97,7 @@ private void OnBeforeRenderCursor() // If the mouse is selecting an interactable, then position the cursor based on the target transform if (mouseInteractor.interactablesSelected.Count > 0) { - reticlePosition = hitTargetTransform.TransformPoint(targetLocalHitPoint); + reticlePosition = selectedHitInfo.hitTargetTransform.TransformPoint(selectedHitInfo.targetLocalHitPoint); } // otherwise, try getting reticlePosition from the ray hit or set it a default distance from the user else if (!mouseInteractor.TryGetHitInfo(out reticlePosition, out reticleNormal, out endPositionInLine, out bool isValidTarget)) diff --git a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/Lines/LineUtility.cs b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/Lines/LineUtility.cs index 66136224430..c8ae78a749e 100644 --- a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/Lines/LineUtility.cs +++ b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/Lines/LineUtility.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using UnityEngine; +using UnityEngine.XR.Interaction.Toolkit; namespace Microsoft.MixedReality.Toolkit.Input { @@ -217,5 +218,80 @@ public static Vector3 GetEllipsePoint(Vector2 radius, float angle) /// Used to calculate the ellipse point in /// private static Vector3 cachedEllipsePoint = Vector3.zero; + + /// + /// Used to locate and lock the raycast hit data on a select. + /// + public static TargetHitInfo LocateTargetHitPoint(this XRRayInteractor rayInteractor, IXRSelectInteractable interactableObject) + { + TargetHitInfo hitInfo = new TargetHitInfo(); + bool hitPointAndTransformUpdated = false; + bool hitNormalUpdated = false; + + // In the case of affordances/handles, we can stick the ray right on to the handle. + if (interactableObject is ISnapInteractable snappable) + { + hitInfo.hitTargetTransform = snappable.HandleTransform; + hitInfo.targetLocalHitPoint = Vector3.zero; + hitInfo.targetLocalHitNormal = Vector3.up; + hitPointAndTransformUpdated = true; + hitNormalUpdated = true; + } + + // In the case of an IScrollable being selected, ensure that the reticle locks to the + // scroller and not to the a list item within the scroller, such as a button. + if (interactableObject is IScrollable scrollable && + scrollable.IsScrolling && + scrollable.ScrollingInteractor == (IXRInteractor)rayInteractor) + { + hitInfo.hitTargetTransform = scrollable.ScrollableTransform; + hitInfo.targetLocalHitPoint = scrollable.ScrollingLocalAnchorPosition; + hitPointAndTransformUpdated = true; + } + + // If no hit, abort. + if (!rayInteractor.TryGetCurrentRaycast( + out RaycastHit? raycastHit, + out _, + out UnityEngine.EventSystems.RaycastResult? raycastResult, + out _, + out bool isUIHitClosest)) + { + return hitInfo; + } + + // Align the reticle with a UI hit if applicable + if (raycastResult.HasValue && isUIHitClosest) + { + hitInfo.hitTargetTransform = raycastResult.Value.gameObject.transform; + hitInfo.targetLocalHitPoint = hitInfo.hitTargetTransform.InverseTransformPoint(raycastResult.Value.worldPosition); + hitInfo.targetLocalHitNormal = hitInfo.hitTargetTransform.InverseTransformDirection(raycastResult.Value.worldNormal); + } + // Otherwise, calculate the reticle pose based on the raycast hit. + else if (raycastHit.HasValue) + { + if (!hitPointAndTransformUpdated) + { + hitInfo.hitTargetTransform = raycastHit.Value.collider.transform; + hitInfo.targetLocalHitPoint = hitInfo.hitTargetTransform.InverseTransformPoint(raycastHit.Value.point); + } + + if (!hitNormalUpdated) + { + hitInfo.targetLocalHitNormal = hitInfo.hitTargetTransform.InverseTransformDirection(raycastHit.Value.normal); + } + } + return hitInfo; + } + + /// + /// A data container for managing the position, normal, and transform of a target hit point. + /// + public struct TargetHitInfo + { + public Vector3 targetLocalHitPoint; + public Vector3 targetLocalHitNormal; + public Transform hitTargetTransform; + } } } diff --git a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs index 30066a05245..52718da6772 100644 --- a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs +++ b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs @@ -5,6 +5,7 @@ using UnityEngine; using UnityEngine.Rendering; using UnityEngine.XR.Interaction.Toolkit; +using static Microsoft.MixedReality.Toolkit.Input.LineUtility; namespace Microsoft.MixedReality.Toolkit.Input { @@ -181,8 +182,7 @@ public bool StopLineAtFirstRaycastHit // reusable values derived from raycast hit data private Vector3 reticlePosition; - private Transform hitTargetTransform; - private Vector3 targetLocalHitPoint; + private TargetHitInfo selectedHitInfo = new TargetHitInfo(); private float hitDistance; /// @@ -324,7 +324,7 @@ private void UpdateLineVisual() if (rayInteractor.hasSelection) { // Assign the last point to the one saved by the callback - lineDataProvider.LastPoint = hitTargetTransform.TransformPoint(targetLocalHitPoint); + lineDataProvider.LastPoint = selectedHitInfo.hitTargetTransform.TransformPoint(selectedHitInfo.targetLocalHitPoint); rayHasHit = true; } // Otherwise draw out the line exactly as the Ray Interactor prescribes @@ -447,67 +447,8 @@ private void InitializeLineRendererProperties() /// private void LocateTargetHitPoint(SelectEnterEventArgs args) { - // If no hit interactable, abort - if (args == null) - { - return; - } - - bool hitPointAndTransformUpdated = false; - - // In the case of affordances/handles, we can stick the ray right on to the handle. - if (args.interactableObject is ISnapInteractable snappable) - { - hitTargetTransform = snappable.HandleTransform; - targetLocalHitPoint = Vector3.zero; - hitPointAndTransformUpdated = true; - } - - // In the case of an IScrollable being selected, ensure that the line visual locks to - // the scroller and not to the a list item within the scroller, such as a button. - if (args.interactableObject is IScrollable scrollable && - scrollable.IsScrolling && - scrollable.ScrollingInteractor == (IXRInteractor)rayInteractor) - { - hitTargetTransform = scrollable.ScrollableTransform; - targetLocalHitPoint = scrollable.ScrollingLocalAnchorPosition; - hitPointAndTransformUpdated = true; - } - - // If no hit, abort. - if (!rayInteractor.TryGetCurrentRaycast( - out RaycastHit? raycastHit, - out _, - out UnityEngine.EventSystems.RaycastResult? raycastResult, - out _, - out bool isUIHitClosest)) - { - return; - } - - // If we haven't even gotten any ray positions yet, abort. - if (rayPositions == null || rayPositionsCount <= 0) - { - return; - } - - // Record relevant data about the hit point. - if (raycastResult.HasValue && isUIHitClosest) - { - hitTargetTransform = raycastResult.Value.gameObject.transform; - targetLocalHitPoint = hitTargetTransform.InverseTransformPoint(raycastResult.Value.worldPosition); - hitDistance = (raycastResult.Value.worldPosition - rayPositions[0]).magnitude; - } - else if (raycastHit.HasValue) - { - if (!hitPointAndTransformUpdated) - { - hitTargetTransform = raycastHit.Value.collider.transform; - targetLocalHitPoint = hitTargetTransform.InverseTransformPoint(raycastHit.Value.point); - } - - hitDistance = (hitTargetTransform.TransformPoint(targetLocalHitPoint) - rayPositions[0]).magnitude; - } + selectedHitInfo = rayInteractor.LocateTargetHitPoint(args.interactableObject); + hitDistance = (selectedHitInfo.hitTargetTransform.TransformPoint(selectedHitInfo.targetLocalHitPoint) - rayPositions[0]).magnitude; } #endregion diff --git a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKRayReticleVisual.cs b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKRayReticleVisual.cs index 2979e2d7f73..861060a6f8c 100644 --- a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKRayReticleVisual.cs +++ b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKRayReticleVisual.cs @@ -4,6 +4,7 @@ using Unity.Profiling; using UnityEngine; using UnityEngine.XR.Interaction.Toolkit; +using static Microsoft.MixedReality.Toolkit.Input.LineUtility; namespace Microsoft.MixedReality.Toolkit.Input { @@ -83,8 +84,8 @@ private void UpdateReticle() { if (rayInteractor.interactablesSelected.Count > 0) { - reticlePosition = hitTargetTransform.TransformPoint(targetLocalHitPoint); - reticleNormal = hitTargetTransform.TransformDirection(targetLocalHitNormal); + reticlePosition = selectedHitInfo.hitTargetTransform.TransformPoint(selectedHitInfo.targetLocalHitPoint); + reticleNormal = selectedHitInfo.hitTargetTransform.TransformDirection(selectedHitInfo.targetLocalHitNormal); ReticleSetActive(true); } else @@ -131,71 +132,14 @@ private void ReticleSetActive(bool value) } } - private Vector3 targetLocalHitPoint; - private Vector3 targetLocalHitNormal; - private Transform hitTargetTransform; + private TargetHitInfo selectedHitInfo = new TargetHitInfo(); /// /// Used to locate and lock the raycast hit data on a select /// private void LocateTargetHitPoint(SelectEnterEventArgs args) { - bool hitPointAndTransformUpdated = false; - bool hitNormalUpdated = false; - - // In the case of affordances/handles, we can stick the ray right on to the handle. - if (args.interactableObject is ISnapInteractable snappable) - { - hitTargetTransform = snappable.HandleTransform; - targetLocalHitPoint = Vector3.zero; - targetLocalHitNormal = Vector3.up; - hitPointAndTransformUpdated = true; - hitNormalUpdated = true; - } - - // In the case of an IScrollable being selected, ensure that the reticle locks to the - // scroller and not to the a list item within the scroller, such as a button. - if (args.interactableObject is IScrollable scrollable && - scrollable.IsScrolling && - scrollable.ScrollingInteractor == (IXRInteractor)rayInteractor) - { - hitTargetTransform = scrollable.ScrollableTransform; - targetLocalHitPoint = scrollable.ScrollingLocalAnchorPosition; - hitPointAndTransformUpdated = true; - } - - // If no hit, abort. - if (!rayInteractor.TryGetCurrentRaycast( - out RaycastHit? raycastHit, - out _, - out UnityEngine.EventSystems.RaycastResult? raycastResult, - out _, - out bool isUIHitClosest)) - { - return; - } - - // Align the reticle with a UI hit if applicable - if (raycastResult.HasValue && isUIHitClosest) - { - hitTargetTransform = raycastResult.Value.gameObject.transform; - targetLocalHitPoint = hitTargetTransform.InverseTransformPoint(raycastResult.Value.worldPosition); - targetLocalHitNormal = hitTargetTransform.InverseTransformDirection(raycastResult.Value.worldNormal); - } - // Otherwise, calculate the reticle pose based on the raycast hit. - else if (raycastHit.HasValue) - { - if (!hitPointAndTransformUpdated) - { - hitTargetTransform = raycastHit.Value.collider.transform; - targetLocalHitPoint = hitTargetTransform.InverseTransformPoint(raycastHit.Value.point); - } - - if (!hitNormalUpdated) - { - targetLocalHitNormal = hitTargetTransform.InverseTransformDirection(raycastHit.Value.normal); - } - } + selectedHitInfo = rayInteractor.LocateTargetHitPoint(args.interactableObject); } /// From f03a9a1a17063f1c1d728213cafbd4711a81d06d Mon Sep 17 00:00:00 2001 From: Marlena Klein Date: Tue, 11 Jul 2023 16:10:41 -0700 Subject: [PATCH 2/7] Update distance --- .../SpatialMouseInteractorCursorVisual.cs | 11 ++++++- .../InteractorVisuals/Lines/LineUtility.cs | 32 +++++++++++-------- .../InteractorVisuals/MRTKLineVisual.cs | 10 ++++-- .../InteractorVisuals/MRTKRayReticleVisual.cs | 4 +-- 4 files changed, 38 insertions(+), 19 deletions(-) diff --git a/com.microsoft.mrtk.input/Experimental/SpatialMouse/Interactor/SpatialMouseInteractorCursorVisual.cs b/com.microsoft.mrtk.input/Experimental/SpatialMouse/Interactor/SpatialMouseInteractorCursorVisual.cs index 6abb46df080..0b3e91fdf59 100644 --- a/com.microsoft.mrtk.input/Experimental/SpatialMouse/Interactor/SpatialMouseInteractorCursorVisual.cs +++ b/com.microsoft.mrtk.input/Experimental/SpatialMouse/Interactor/SpatialMouseInteractorCursorVisual.cs @@ -65,6 +65,15 @@ protected virtual void OnDisable() private void LocateTargetHitPoint(SelectEnterEventArgs args) { + // Sanity check. + if (rayPositions == null || + rayPositions.Length == 0 || + rayPositionsCount == 0 || + rayPositionsCount > rayPositions.Length) + { + return; + } + selectedHitInfo = mouseInteractor.LocateTargetHitPoint(args.interactableObject); } @@ -97,7 +106,7 @@ private void OnBeforeRenderCursor() // If the mouse is selecting an interactable, then position the cursor based on the target transform if (mouseInteractor.interactablesSelected.Count > 0) { - reticlePosition = selectedHitInfo.hitTargetTransform.TransformPoint(selectedHitInfo.targetLocalHitPoint); + reticlePosition = selectedHitInfo.HitTargetTransform.TransformPoint(selectedHitInfo.TargetLocalHitPoint); } // otherwise, try getting reticlePosition from the ray hit or set it a default distance from the user else if (!mouseInteractor.TryGetHitInfo(out reticlePosition, out reticleNormal, out endPositionInLine, out bool isValidTarget)) diff --git a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/Lines/LineUtility.cs b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/Lines/LineUtility.cs index c8ae78a749e..b76c7b95895 100644 --- a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/Lines/LineUtility.cs +++ b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/Lines/LineUtility.cs @@ -231,9 +231,9 @@ public static TargetHitInfo LocateTargetHitPoint(this XRRayInteractor rayInterac // In the case of affordances/handles, we can stick the ray right on to the handle. if (interactableObject is ISnapInteractable snappable) { - hitInfo.hitTargetTransform = snappable.HandleTransform; - hitInfo.targetLocalHitPoint = Vector3.zero; - hitInfo.targetLocalHitNormal = Vector3.up; + hitInfo.HitTargetTransform = snappable.HandleTransform; + hitInfo.TargetLocalHitPoint = Vector3.zero; + hitInfo.TargetLocalHitNormal = Vector3.up; hitPointAndTransformUpdated = true; hitNormalUpdated = true; } @@ -244,8 +244,8 @@ public static TargetHitInfo LocateTargetHitPoint(this XRRayInteractor rayInterac scrollable.IsScrolling && scrollable.ScrollingInteractor == (IXRInteractor)rayInteractor) { - hitInfo.hitTargetTransform = scrollable.ScrollableTransform; - hitInfo.targetLocalHitPoint = scrollable.ScrollingLocalAnchorPosition; + hitInfo.HitTargetTransform = scrollable.ScrollableTransform; + hitInfo.TargetLocalHitPoint = scrollable.ScrollingLocalAnchorPosition; hitPointAndTransformUpdated = true; } @@ -263,23 +263,26 @@ public static TargetHitInfo LocateTargetHitPoint(this XRRayInteractor rayInterac // Align the reticle with a UI hit if applicable if (raycastResult.HasValue && isUIHitClosest) { - hitInfo.hitTargetTransform = raycastResult.Value.gameObject.transform; - hitInfo.targetLocalHitPoint = hitInfo.hitTargetTransform.InverseTransformPoint(raycastResult.Value.worldPosition); - hitInfo.targetLocalHitNormal = hitInfo.hitTargetTransform.InverseTransformDirection(raycastResult.Value.worldNormal); + hitInfo.HitTargetTransform = raycastResult.Value.gameObject.transform; + hitInfo.TargetLocalHitPoint = hitInfo.HitTargetTransform.InverseTransformPoint(raycastResult.Value.worldPosition); + hitInfo.TargetLocalHitNormal = hitInfo.HitTargetTransform.InverseTransformDirection(raycastResult.Value.worldNormal); + hitInfo.HitDistanceReference = raycastResult.Value.worldPosition; } // Otherwise, calculate the reticle pose based on the raycast hit. else if (raycastHit.HasValue) { if (!hitPointAndTransformUpdated) { - hitInfo.hitTargetTransform = raycastHit.Value.collider.transform; - hitInfo.targetLocalHitPoint = hitInfo.hitTargetTransform.InverseTransformPoint(raycastHit.Value.point); + hitInfo.HitTargetTransform = raycastHit.Value.collider.transform; + hitInfo.TargetLocalHitPoint = hitInfo.HitTargetTransform.InverseTransformPoint(raycastHit.Value.point); } if (!hitNormalUpdated) { - hitInfo.targetLocalHitNormal = hitInfo.hitTargetTransform.InverseTransformDirection(raycastHit.Value.normal); + hitInfo.TargetLocalHitNormal = hitInfo.HitTargetTransform.InverseTransformDirection(raycastHit.Value.normal); } + + hitInfo.HitDistanceReference = hitInfo.HitTargetTransform.TransformPoint(hitInfo.TargetLocalHitPoint); } return hitInfo; } @@ -289,9 +292,10 @@ public static TargetHitInfo LocateTargetHitPoint(this XRRayInteractor rayInterac /// public struct TargetHitInfo { - public Vector3 targetLocalHitPoint; - public Vector3 targetLocalHitNormal; - public Transform hitTargetTransform; + public Vector3 TargetLocalHitPoint; + public Vector3 TargetLocalHitNormal; + public Transform HitTargetTransform; + public Vector3 HitDistanceReference; } } } diff --git a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs index 52718da6772..9e3f95b3586 100644 --- a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs +++ b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs @@ -324,7 +324,7 @@ private void UpdateLineVisual() if (rayInteractor.hasSelection) { // Assign the last point to the one saved by the callback - lineDataProvider.LastPoint = selectedHitInfo.hitTargetTransform.TransformPoint(selectedHitInfo.targetLocalHitPoint); + lineDataProvider.LastPoint = selectedHitInfo.HitTargetTransform.TransformPoint(selectedHitInfo.TargetLocalHitPoint); rayHasHit = true; } // Otherwise draw out the line exactly as the Ray Interactor prescribes @@ -447,8 +447,14 @@ private void InitializeLineRendererProperties() /// private void LocateTargetHitPoint(SelectEnterEventArgs args) { + // If no hit interactable or we haven't even gotten any ray positions yet, abort + if (args == null || rayPositions == null || rayPositionsCount <= 0) + { + return; + } + selectedHitInfo = rayInteractor.LocateTargetHitPoint(args.interactableObject); - hitDistance = (selectedHitInfo.hitTargetTransform.TransformPoint(selectedHitInfo.targetLocalHitPoint) - rayPositions[0]).magnitude; + hitDistance = (selectedHitInfo.HitDistanceReference - rayPositions[0]).magnitude; } #endregion diff --git a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKRayReticleVisual.cs b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKRayReticleVisual.cs index 861060a6f8c..5acd12e5abe 100644 --- a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKRayReticleVisual.cs +++ b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKRayReticleVisual.cs @@ -84,8 +84,8 @@ private void UpdateReticle() { if (rayInteractor.interactablesSelected.Count > 0) { - reticlePosition = selectedHitInfo.hitTargetTransform.TransformPoint(selectedHitInfo.targetLocalHitPoint); - reticleNormal = selectedHitInfo.hitTargetTransform.TransformDirection(selectedHitInfo.targetLocalHitNormal); + reticlePosition = selectedHitInfo.HitTargetTransform.TransformPoint(selectedHitInfo.TargetLocalHitPoint); + reticleNormal = selectedHitInfo.HitTargetTransform.TransformDirection(selectedHitInfo.TargetLocalHitNormal); ReticleSetActive(true); } else From cc6312512e7e8a24824c2586c3b04c47a50089e0 Mon Sep 17 00:00:00 2001 From: Marlena Klein Date: Tue, 11 Jul 2023 16:25:06 -0700 Subject: [PATCH 3/7] Update comments --- .../Interactors/InteractorVisuals/Lines/LineUtility.cs | 9 ++++++--- .../Interactors/InteractorVisuals/MRTKLineVisual.cs | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/Lines/LineUtility.cs b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/Lines/LineUtility.cs index b76c7b95895..537f8195d11 100644 --- a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/Lines/LineUtility.cs +++ b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/Lines/LineUtility.cs @@ -222,6 +222,9 @@ public static Vector3 GetEllipsePoint(Vector2 radius, float angle) /// /// Used to locate and lock the raycast hit data on a select. /// + /// The XRRayInteractor responsible for the raycast hit. + /// The IXRSelectInteractable which has been selected. + /// The local position and normal of the hit target, the hit target transform, and a reference point to calculate hit distance, contained in a TargetHitInfo struct. public static TargetHitInfo LocateTargetHitPoint(this XRRayInteractor rayInteractor, IXRSelectInteractable interactableObject) { TargetHitInfo hitInfo = new TargetHitInfo(); @@ -266,7 +269,7 @@ public static TargetHitInfo LocateTargetHitPoint(this XRRayInteractor rayInterac hitInfo.HitTargetTransform = raycastResult.Value.gameObject.transform; hitInfo.TargetLocalHitPoint = hitInfo.HitTargetTransform.InverseTransformPoint(raycastResult.Value.worldPosition); hitInfo.TargetLocalHitNormal = hitInfo.HitTargetTransform.InverseTransformDirection(raycastResult.Value.worldNormal); - hitInfo.HitDistanceReference = raycastResult.Value.worldPosition; + hitInfo.HitDistanceReferencePoint = raycastResult.Value.worldPosition; } // Otherwise, calculate the reticle pose based on the raycast hit. else if (raycastHit.HasValue) @@ -282,7 +285,7 @@ public static TargetHitInfo LocateTargetHitPoint(this XRRayInteractor rayInterac hitInfo.TargetLocalHitNormal = hitInfo.HitTargetTransform.InverseTransformDirection(raycastHit.Value.normal); } - hitInfo.HitDistanceReference = hitInfo.HitTargetTransform.TransformPoint(hitInfo.TargetLocalHitPoint); + hitInfo.HitDistanceReferencePoint = hitInfo.HitTargetTransform.TransformPoint(hitInfo.TargetLocalHitPoint); } return hitInfo; } @@ -295,7 +298,7 @@ public struct TargetHitInfo public Vector3 TargetLocalHitPoint; public Vector3 TargetLocalHitNormal; public Transform HitTargetTransform; - public Vector3 HitDistanceReference; + public Vector3 HitDistanceReferencePoint; } } } diff --git a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs index 9e3f95b3586..6cf82d93e73 100644 --- a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs +++ b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs @@ -454,7 +454,7 @@ private void LocateTargetHitPoint(SelectEnterEventArgs args) } selectedHitInfo = rayInteractor.LocateTargetHitPoint(args.interactableObject); - hitDistance = (selectedHitInfo.HitDistanceReference - rayPositions[0]).magnitude; + hitDistance = (selectedHitInfo.HitDistanceReferencePoint - rayPositions[0]).magnitude; } #endregion From 7393a14f8ee32443c2dea5e4ec6d2efb56da1510 Mon Sep 17 00:00:00 2001 From: Marlena Klein Date: Tue, 11 Jul 2023 17:41:32 -0700 Subject: [PATCH 4/7] PR Fix --- .../SpatialMouseInteractorCursorVisual.cs | 2 +- .../InteractorVisuals/Lines/LineUtility.cs | 83 ------------- .../InteractorVisuals/MRTKLineVisual.cs | 2 +- .../InteractorVisuals/MRTKRayReticleVisual.cs | 2 +- .../Interactors/XRRayInteractorExtensions.cs | 109 ++++++++++++++++++ .../XRRayInteractorExtensions.cs.meta | 11 ++ .../Visuals/SqueezableBoxVisuals.cs | 3 + 7 files changed, 126 insertions(+), 86 deletions(-) create mode 100644 com.microsoft.mrtk.input/Interactors/XRRayInteractorExtensions.cs create mode 100644 com.microsoft.mrtk.input/Interactors/XRRayInteractorExtensions.cs.meta diff --git a/com.microsoft.mrtk.input/Experimental/SpatialMouse/Interactor/SpatialMouseInteractorCursorVisual.cs b/com.microsoft.mrtk.input/Experimental/SpatialMouse/Interactor/SpatialMouseInteractorCursorVisual.cs index 0b3e91fdf59..d4112be8799 100644 --- a/com.microsoft.mrtk.input/Experimental/SpatialMouse/Interactor/SpatialMouseInteractorCursorVisual.cs +++ b/com.microsoft.mrtk.input/Experimental/SpatialMouse/Interactor/SpatialMouseInteractorCursorVisual.cs @@ -3,7 +3,7 @@ using UnityEngine; using UnityEngine.XR.Interaction.Toolkit; -using static Microsoft.MixedReality.Toolkit.Input.LineUtility; +using static Microsoft.MixedReality.Toolkit.Input.XRRayInteractorExtensions; namespace Microsoft.MixedReality.Toolkit.Input.Experimental { diff --git a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/Lines/LineUtility.cs b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/Lines/LineUtility.cs index 537f8195d11..66136224430 100644 --- a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/Lines/LineUtility.cs +++ b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/Lines/LineUtility.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using UnityEngine; -using UnityEngine.XR.Interaction.Toolkit; namespace Microsoft.MixedReality.Toolkit.Input { @@ -218,87 +217,5 @@ public static Vector3 GetEllipsePoint(Vector2 radius, float angle) /// Used to calculate the ellipse point in /// private static Vector3 cachedEllipsePoint = Vector3.zero; - - /// - /// Used to locate and lock the raycast hit data on a select. - /// - /// The XRRayInteractor responsible for the raycast hit. - /// The IXRSelectInteractable which has been selected. - /// The local position and normal of the hit target, the hit target transform, and a reference point to calculate hit distance, contained in a TargetHitInfo struct. - public static TargetHitInfo LocateTargetHitPoint(this XRRayInteractor rayInteractor, IXRSelectInteractable interactableObject) - { - TargetHitInfo hitInfo = new TargetHitInfo(); - bool hitPointAndTransformUpdated = false; - bool hitNormalUpdated = false; - - // In the case of affordances/handles, we can stick the ray right on to the handle. - if (interactableObject is ISnapInteractable snappable) - { - hitInfo.HitTargetTransform = snappable.HandleTransform; - hitInfo.TargetLocalHitPoint = Vector3.zero; - hitInfo.TargetLocalHitNormal = Vector3.up; - hitPointAndTransformUpdated = true; - hitNormalUpdated = true; - } - - // In the case of an IScrollable being selected, ensure that the reticle locks to the - // scroller and not to the a list item within the scroller, such as a button. - if (interactableObject is IScrollable scrollable && - scrollable.IsScrolling && - scrollable.ScrollingInteractor == (IXRInteractor)rayInteractor) - { - hitInfo.HitTargetTransform = scrollable.ScrollableTransform; - hitInfo.TargetLocalHitPoint = scrollable.ScrollingLocalAnchorPosition; - hitPointAndTransformUpdated = true; - } - - // If no hit, abort. - if (!rayInteractor.TryGetCurrentRaycast( - out RaycastHit? raycastHit, - out _, - out UnityEngine.EventSystems.RaycastResult? raycastResult, - out _, - out bool isUIHitClosest)) - { - return hitInfo; - } - - // Align the reticle with a UI hit if applicable - if (raycastResult.HasValue && isUIHitClosest) - { - hitInfo.HitTargetTransform = raycastResult.Value.gameObject.transform; - hitInfo.TargetLocalHitPoint = hitInfo.HitTargetTransform.InverseTransformPoint(raycastResult.Value.worldPosition); - hitInfo.TargetLocalHitNormal = hitInfo.HitTargetTransform.InverseTransformDirection(raycastResult.Value.worldNormal); - hitInfo.HitDistanceReferencePoint = raycastResult.Value.worldPosition; - } - // Otherwise, calculate the reticle pose based on the raycast hit. - else if (raycastHit.HasValue) - { - if (!hitPointAndTransformUpdated) - { - hitInfo.HitTargetTransform = raycastHit.Value.collider.transform; - hitInfo.TargetLocalHitPoint = hitInfo.HitTargetTransform.InverseTransformPoint(raycastHit.Value.point); - } - - if (!hitNormalUpdated) - { - hitInfo.TargetLocalHitNormal = hitInfo.HitTargetTransform.InverseTransformDirection(raycastHit.Value.normal); - } - - hitInfo.HitDistanceReferencePoint = hitInfo.HitTargetTransform.TransformPoint(hitInfo.TargetLocalHitPoint); - } - return hitInfo; - } - - /// - /// A data container for managing the position, normal, and transform of a target hit point. - /// - public struct TargetHitInfo - { - public Vector3 TargetLocalHitPoint; - public Vector3 TargetLocalHitNormal; - public Transform HitTargetTransform; - public Vector3 HitDistanceReferencePoint; - } } } diff --git a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs index 6cf82d93e73..868b175cea2 100644 --- a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs +++ b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs @@ -5,7 +5,7 @@ using UnityEngine; using UnityEngine.Rendering; using UnityEngine.XR.Interaction.Toolkit; -using static Microsoft.MixedReality.Toolkit.Input.LineUtility; +using static Microsoft.MixedReality.Toolkit.Input.XRRayInteractorExtensions; namespace Microsoft.MixedReality.Toolkit.Input { diff --git a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKRayReticleVisual.cs b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKRayReticleVisual.cs index 5acd12e5abe..5367f6229ff 100644 --- a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKRayReticleVisual.cs +++ b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKRayReticleVisual.cs @@ -4,7 +4,7 @@ using Unity.Profiling; using UnityEngine; using UnityEngine.XR.Interaction.Toolkit; -using static Microsoft.MixedReality.Toolkit.Input.LineUtility; +using static Microsoft.MixedReality.Toolkit.Input.XRRayInteractorExtensions; namespace Microsoft.MixedReality.Toolkit.Input { diff --git a/com.microsoft.mrtk.input/Interactors/XRRayInteractorExtensions.cs b/com.microsoft.mrtk.input/Interactors/XRRayInteractorExtensions.cs new file mode 100644 index 00000000000..62190f02f31 --- /dev/null +++ b/com.microsoft.mrtk.input/Interactors/XRRayInteractorExtensions.cs @@ -0,0 +1,109 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using UnityEngine; +using UnityEngine.XR.Interaction.Toolkit; + +namespace Microsoft.MixedReality.Toolkit.Input +{ + + public static class XRRayInteractorExtensions + { + /// + /// Used to locate and lock the raycast hit data on a select. + /// + /// The XRRayInteractor responsible for the raycast hit. + /// The IXRSelectInteractable which has been selected. + /// The local position and normal of the hit target, the hit target transform, and a reference point to calculate hit distance, contained in a TargetHitInfo struct. + public static TargetHitInfo LocateTargetHitPoint(this XRRayInteractor rayInteractor, IXRSelectInteractable interactableObject) + { + TargetHitInfo hitInfo = new TargetHitInfo(); + bool hitPointAndTransformUpdated = false; + bool hitNormalUpdated = false; + + // In the case of affordances/handles, we can stick the ray right on to the handle. + if (interactableObject is ISnapInteractable snappable) + { + hitInfo.HitTargetTransform = snappable.HandleTransform; + hitInfo.TargetLocalHitPoint = Vector3.zero; + hitInfo.TargetLocalHitNormal = Vector3.up; + hitPointAndTransformUpdated = true; + hitNormalUpdated = true; + } + + // In the case of an IScrollable being selected, ensure that the reticle locks to the + // scroller and not to the a list item within the scroller, such as a button. + if (interactableObject is IScrollable scrollable && + scrollable.IsScrolling && + scrollable.ScrollingInteractor == (IXRInteractor)rayInteractor) + { + hitInfo.HitTargetTransform = scrollable.ScrollableTransform; + hitInfo.TargetLocalHitPoint = scrollable.ScrollingLocalAnchorPosition; + hitPointAndTransformUpdated = true; + } + + // If no hit, abort. + if (!rayInteractor.TryGetCurrentRaycast( + out RaycastHit? raycastHit, + out _, + out UnityEngine.EventSystems.RaycastResult? raycastResult, + out _, + out bool isUIHitClosest)) + { + return hitInfo; + } + + // Align the reticle with a UI hit if applicable + if (raycastResult.HasValue && isUIHitClosest) + { + hitInfo.HitTargetTransform = raycastResult.Value.gameObject.transform; + hitInfo.TargetLocalHitPoint = hitInfo.HitTargetTransform.InverseTransformPoint(raycastResult.Value.worldPosition); + hitInfo.TargetLocalHitNormal = hitInfo.HitTargetTransform.InverseTransformDirection(raycastResult.Value.worldNormal); + hitInfo.HitDistanceReferencePoint = raycastResult.Value.worldPosition; + } + // Otherwise, calculate the reticle pose based on the raycast hit. + else if (raycastHit.HasValue) + { + if (!hitPointAndTransformUpdated) + { + hitInfo.HitTargetTransform = raycastHit.Value.collider.transform; + hitInfo.TargetLocalHitPoint = hitInfo.HitTargetTransform.InverseTransformPoint(raycastHit.Value.point); + } + + if (!hitNormalUpdated) + { + hitInfo.TargetLocalHitNormal = hitInfo.HitTargetTransform.InverseTransformDirection(raycastHit.Value.normal); + } + + hitInfo.HitDistanceReferencePoint = hitInfo.HitTargetTransform.TransformPoint(hitInfo.TargetLocalHitPoint); + } + return hitInfo; + } + + /// + /// A data container for managing the position, normal, and transform of a target hit point. + /// + public struct TargetHitInfo + { + /// + /// The position of the target hit. + /// + public Vector3 TargetLocalHitPoint; + + /// + /// The normal of the target hit. + /// + public Vector3 TargetLocalHitNormal; + + /// + /// The Transform of the selected target. + /// + public Transform HitTargetTransform; + + /// + /// The position used to calculate hit distance from a given ray position. + /// + public Vector3 HitDistanceReferencePoint; + } + } +} \ No newline at end of file diff --git a/com.microsoft.mrtk.input/Interactors/XRRayInteractorExtensions.cs.meta b/com.microsoft.mrtk.input/Interactors/XRRayInteractorExtensions.cs.meta new file mode 100644 index 00000000000..2a4c0c74a4d --- /dev/null +++ b/com.microsoft.mrtk.input/Interactors/XRRayInteractorExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 05901b375352bf8478c5ca6d1bd52807 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.microsoft.mrtk.spatialmanipulation/BoundsControl/Visuals/SqueezableBoxVisuals.cs b/com.microsoft.mrtk.spatialmanipulation/BoundsControl/Visuals/SqueezableBoxVisuals.cs index 7cd7b8df67e..adbb906e89f 100644 --- a/com.microsoft.mrtk.spatialmanipulation/BoundsControl/Visuals/SqueezableBoxVisuals.cs +++ b/com.microsoft.mrtk.spatialmanipulation/BoundsControl/Visuals/SqueezableBoxVisuals.cs @@ -263,6 +263,9 @@ private void Update() protected virtual void OnEnable() { + // Ensures that when the GameObject is re-enabled, the handles are occluded ny default. + // If the handles are active, they will be un-occluded by the next frame. + // Prevents undesirable behaviour from the handle animations. foreach (var handle in handles) { handle.HideOnStartup(); From 198de9b5e040ebbbe0656ca5560d177fe548b5d6 Mon Sep 17 00:00:00 2001 From: Marlena Klein Date: Tue, 11 Jul 2023 17:43:37 -0700 Subject: [PATCH 5/7] Comments --- .../Interactors/XRRayInteractorExtensions.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/com.microsoft.mrtk.input/Interactors/XRRayInteractorExtensions.cs b/com.microsoft.mrtk.input/Interactors/XRRayInteractorExtensions.cs index 62190f02f31..1fce9b30f4d 100644 --- a/com.microsoft.mrtk.input/Interactors/XRRayInteractorExtensions.cs +++ b/com.microsoft.mrtk.input/Interactors/XRRayInteractorExtensions.cs @@ -6,7 +6,9 @@ namespace Microsoft.MixedReality.Toolkit.Input { - + /// + /// Extensions to the XRRayInteractor and associated structs. + /// public static class XRRayInteractorExtensions { /// From 9f726e7adc2c6a87f18e3f210a10ae4897a73713 Mon Sep 17 00:00:00 2001 From: Marlena Klein Date: Tue, 11 Jul 2023 17:46:47 -0700 Subject: [PATCH 6/7] Typo --- .../BoundsControl/Visuals/SqueezableBoxVisuals.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/com.microsoft.mrtk.spatialmanipulation/BoundsControl/Visuals/SqueezableBoxVisuals.cs b/com.microsoft.mrtk.spatialmanipulation/BoundsControl/Visuals/SqueezableBoxVisuals.cs index adbb906e89f..b8c897d2318 100644 --- a/com.microsoft.mrtk.spatialmanipulation/BoundsControl/Visuals/SqueezableBoxVisuals.cs +++ b/com.microsoft.mrtk.spatialmanipulation/BoundsControl/Visuals/SqueezableBoxVisuals.cs @@ -263,7 +263,7 @@ private void Update() protected virtual void OnEnable() { - // Ensures that when the GameObject is re-enabled, the handles are occluded ny default. + // Ensures that when the GameObject is re-enabled, the handles are occluded by default. // If the handles are active, they will be un-occluded by the next frame. // Prevents undesirable behaviour from the handle animations. foreach (var handle in handles) From 9931d095558b8ac4fb631fbf8bddbd4576e11344 Mon Sep 17 00:00:00 2001 From: Marlena Klein Date: Wed, 12 Jul 2023 10:33:41 -0700 Subject: [PATCH 7/7] Renaming / refactoring --- .../SpatialMouseInteractorCursorVisual.cs | 6 +-- .../InteractorVisuals/MRTKLineVisual.cs | 8 +-- .../InteractorVisuals/MRTKRayReticleVisual.cs | 8 +-- .../Interactors/XRRayInteractorExtensions.cs | 51 ++++++++++--------- 4 files changed, 37 insertions(+), 36 deletions(-) diff --git a/com.microsoft.mrtk.input/Experimental/SpatialMouse/Interactor/SpatialMouseInteractorCursorVisual.cs b/com.microsoft.mrtk.input/Experimental/SpatialMouse/Interactor/SpatialMouseInteractorCursorVisual.cs index d4112be8799..b5925b74e47 100644 --- a/com.microsoft.mrtk.input/Experimental/SpatialMouse/Interactor/SpatialMouseInteractorCursorVisual.cs +++ b/com.microsoft.mrtk.input/Experimental/SpatialMouse/Interactor/SpatialMouseInteractorCursorVisual.cs @@ -52,7 +52,7 @@ protected virtual void OnDisable() Application.onBeforeRender -= OnBeforeRenderCursor; } - private TargetHitInfo selectedHitInfo = new TargetHitInfo(); + private TargetHitDetails selectedHitDetails = new TargetHitDetails(); // reusable lists of the points returned by the XRRayInteractor Vector3[] rayPositions; @@ -74,7 +74,7 @@ private void LocateTargetHitPoint(SelectEnterEventArgs args) return; } - selectedHitInfo = mouseInteractor.LocateTargetHitPoint(args.interactableObject); + mouseInteractor.TryLocateTargetHitPoint(args.interactableObject, out selectedHitDetails); } private void OnBeforeRenderCursor() @@ -106,7 +106,7 @@ private void OnBeforeRenderCursor() // If the mouse is selecting an interactable, then position the cursor based on the target transform if (mouseInteractor.interactablesSelected.Count > 0) { - reticlePosition = selectedHitInfo.HitTargetTransform.TransformPoint(selectedHitInfo.TargetLocalHitPoint); + reticlePosition = selectedHitDetails.HitTargetTransform.TransformPoint(selectedHitDetails.TargetLocalHitPoint); } // otherwise, try getting reticlePosition from the ray hit or set it a default distance from the user else if (!mouseInteractor.TryGetHitInfo(out reticlePosition, out reticleNormal, out endPositionInLine, out bool isValidTarget)) diff --git a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs index 868b175cea2..65c72f84427 100644 --- a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs +++ b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKLineVisual.cs @@ -182,7 +182,7 @@ public bool StopLineAtFirstRaycastHit // reusable values derived from raycast hit data private Vector3 reticlePosition; - private TargetHitInfo selectedHitInfo = new TargetHitInfo(); + private TargetHitDetails selectedHitDetails = new TargetHitDetails(); private float hitDistance; /// @@ -324,7 +324,7 @@ private void UpdateLineVisual() if (rayInteractor.hasSelection) { // Assign the last point to the one saved by the callback - lineDataProvider.LastPoint = selectedHitInfo.HitTargetTransform.TransformPoint(selectedHitInfo.TargetLocalHitPoint); + lineDataProvider.LastPoint = selectedHitDetails.HitTargetTransform.TransformPoint(selectedHitDetails.TargetLocalHitPoint); rayHasHit = true; } // Otherwise draw out the line exactly as the Ray Interactor prescribes @@ -453,8 +453,8 @@ private void LocateTargetHitPoint(SelectEnterEventArgs args) return; } - selectedHitInfo = rayInteractor.LocateTargetHitPoint(args.interactableObject); - hitDistance = (selectedHitInfo.HitDistanceReferencePoint - rayPositions[0]).magnitude; + rayInteractor.TryLocateTargetHitPoint(args.interactableObject, out selectedHitDetails); + hitDistance = (selectedHitDetails.HitDistanceReferencePoint - rayPositions[0]).magnitude; } #endregion diff --git a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKRayReticleVisual.cs b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKRayReticleVisual.cs index 5367f6229ff..f1379603432 100644 --- a/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKRayReticleVisual.cs +++ b/com.microsoft.mrtk.input/Interactors/InteractorVisuals/MRTKRayReticleVisual.cs @@ -84,8 +84,8 @@ private void UpdateReticle() { if (rayInteractor.interactablesSelected.Count > 0) { - reticlePosition = selectedHitInfo.HitTargetTransform.TransformPoint(selectedHitInfo.TargetLocalHitPoint); - reticleNormal = selectedHitInfo.HitTargetTransform.TransformDirection(selectedHitInfo.TargetLocalHitNormal); + reticlePosition = selectedHitDetails.HitTargetTransform.TransformPoint(selectedHitDetails.TargetLocalHitPoint); + reticleNormal = selectedHitDetails.HitTargetTransform.TransformDirection(selectedHitDetails.TargetLocalHitNormal); ReticleSetActive(true); } else @@ -132,14 +132,14 @@ private void ReticleSetActive(bool value) } } - private TargetHitInfo selectedHitInfo = new TargetHitInfo(); + private TargetHitDetails selectedHitDetails = new TargetHitDetails(); /// /// Used to locate and lock the raycast hit data on a select /// private void LocateTargetHitPoint(SelectEnterEventArgs args) { - selectedHitInfo = rayInteractor.LocateTargetHitPoint(args.interactableObject); + rayInteractor.TryLocateTargetHitPoint(args.interactableObject, out selectedHitDetails); } /// diff --git a/com.microsoft.mrtk.input/Interactors/XRRayInteractorExtensions.cs b/com.microsoft.mrtk.input/Interactors/XRRayInteractorExtensions.cs index 1fce9b30f4d..ca151c0706c 100644 --- a/com.microsoft.mrtk.input/Interactors/XRRayInteractorExtensions.cs +++ b/com.microsoft.mrtk.input/Interactors/XRRayInteractorExtensions.cs @@ -11,24 +11,25 @@ namespace Microsoft.MixedReality.Toolkit.Input /// public static class XRRayInteractorExtensions { - /// - /// Used to locate and lock the raycast hit data on a select. - /// - /// The XRRayInteractor responsible for the raycast hit. - /// The IXRSelectInteractable which has been selected. - /// The local position and normal of the hit target, the hit target transform, and a reference point to calculate hit distance, contained in a TargetHitInfo struct. - public static TargetHitInfo LocateTargetHitPoint(this XRRayInteractor rayInteractor, IXRSelectInteractable interactableObject) + /// + /// Used to locate and lock the raycast hit data on a select. + /// + /// The XRRayInteractor responsible for the raycast hit. + /// The IXRSelectInteractable which has been selected. + /// The local position and normal of the hit target, the hit target transform, and a reference point to calculate hit distance, contained in a TargetHitDetails struct. + /// Returns true if there was a raycast hit and false otherwise. + public static bool TryLocateTargetHitPoint(this XRRayInteractor rayInteractor, IXRSelectInteractable interactableObject, out TargetHitDetails hitDetails) { - TargetHitInfo hitInfo = new TargetHitInfo(); + hitDetails = new TargetHitDetails(); bool hitPointAndTransformUpdated = false; bool hitNormalUpdated = false; // In the case of affordances/handles, we can stick the ray right on to the handle. if (interactableObject is ISnapInteractable snappable) { - hitInfo.HitTargetTransform = snappable.HandleTransform; - hitInfo.TargetLocalHitPoint = Vector3.zero; - hitInfo.TargetLocalHitNormal = Vector3.up; + hitDetails.HitTargetTransform = snappable.HandleTransform; + hitDetails.TargetLocalHitPoint = Vector3.zero; + hitDetails.TargetLocalHitNormal = Vector3.up; hitPointAndTransformUpdated = true; hitNormalUpdated = true; } @@ -39,8 +40,8 @@ public static TargetHitInfo LocateTargetHitPoint(this XRRayInteractor rayInterac scrollable.IsScrolling && scrollable.ScrollingInteractor == (IXRInteractor)rayInteractor) { - hitInfo.HitTargetTransform = scrollable.ScrollableTransform; - hitInfo.TargetLocalHitPoint = scrollable.ScrollingLocalAnchorPosition; + hitDetails.HitTargetTransform = scrollable.ScrollableTransform; + hitDetails.TargetLocalHitPoint = scrollable.ScrollingLocalAnchorPosition; hitPointAndTransformUpdated = true; } @@ -52,40 +53,40 @@ public static TargetHitInfo LocateTargetHitPoint(this XRRayInteractor rayInterac out _, out bool isUIHitClosest)) { - return hitInfo; + return false; } // Align the reticle with a UI hit if applicable if (raycastResult.HasValue && isUIHitClosest) { - hitInfo.HitTargetTransform = raycastResult.Value.gameObject.transform; - hitInfo.TargetLocalHitPoint = hitInfo.HitTargetTransform.InverseTransformPoint(raycastResult.Value.worldPosition); - hitInfo.TargetLocalHitNormal = hitInfo.HitTargetTransform.InverseTransformDirection(raycastResult.Value.worldNormal); - hitInfo.HitDistanceReferencePoint = raycastResult.Value.worldPosition; + hitDetails.HitTargetTransform = raycastResult.Value.gameObject.transform; + hitDetails.TargetLocalHitPoint = hitDetails.HitTargetTransform.InverseTransformPoint(raycastResult.Value.worldPosition); + hitDetails.TargetLocalHitNormal = hitDetails.HitTargetTransform.InverseTransformDirection(raycastResult.Value.worldNormal); + hitDetails.HitDistanceReferencePoint = raycastResult.Value.worldPosition; } // Otherwise, calculate the reticle pose based on the raycast hit. else if (raycastHit.HasValue) { if (!hitPointAndTransformUpdated) { - hitInfo.HitTargetTransform = raycastHit.Value.collider.transform; - hitInfo.TargetLocalHitPoint = hitInfo.HitTargetTransform.InverseTransformPoint(raycastHit.Value.point); + hitDetails.HitTargetTransform = raycastHit.Value.collider.transform; + hitDetails.TargetLocalHitPoint = hitDetails.HitTargetTransform.InverseTransformPoint(raycastHit.Value.point); } if (!hitNormalUpdated) { - hitInfo.TargetLocalHitNormal = hitInfo.HitTargetTransform.InverseTransformDirection(raycastHit.Value.normal); + hitDetails.TargetLocalHitNormal = hitDetails.HitTargetTransform.InverseTransformDirection(raycastHit.Value.normal); } - hitInfo.HitDistanceReferencePoint = hitInfo.HitTargetTransform.TransformPoint(hitInfo.TargetLocalHitPoint); + hitDetails.HitDistanceReferencePoint = hitDetails.HitTargetTransform.TransformPoint(hitDetails.TargetLocalHitPoint); } - return hitInfo; + return true; } /// /// A data container for managing the position, normal, and transform of a target hit point. /// - public struct TargetHitInfo + public struct TargetHitDetails { /// /// The position of the target hit. @@ -108,4 +109,4 @@ public struct TargetHitInfo public Vector3 HitDistanceReferencePoint; } } -} \ No newline at end of file +}