Skip to content

Commit 105e7b0

Browse files
Merge pull request #2398 from StephenHodgson/vNEXT-AttachToControllerRefactor
Refactored Pointers & Broke out raycasting into it's own static class.
2 parents de8af80 + fc93b0e commit 105e7b0

22 files changed

+515
-1479
lines changed

Assets/MixedRealityToolkit/InputSystem/Focus/FocusProvider.cs

Lines changed: 46 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Microsoft.MixedReality.Toolkit.Internal.Interfaces.InputSystem;
88
using Microsoft.MixedReality.Toolkit.Internal.Managers;
99
using Microsoft.MixedReality.Toolkit.Internal.Utilities;
10+
using Microsoft.MixedReality.Toolkit.Internal.Utilities.Physics;
1011
using System;
1112
using System.Collections.Generic;
1213
using UnityEngine;
@@ -530,6 +531,8 @@ private void UpdatePointers()
530531

531532
if (debugDrawPointingRays)
532533
{
534+
MixedRealityRaycaster.DebugEnabled = debugDrawPointingRays;
535+
533536
Color rayColor;
534537

535538
if ((debugDrawPointingRayColors != null) && (debugDrawPointingRayColors.Length > 0))
@@ -581,7 +584,7 @@ private void UpdatePointer(PointerData pointer)
581584
}
582585

583586
// Set the pointer's result last
584-
pointer.Pointer.Result = pointer as IPointerResult;
587+
pointer.Pointer.Result = pointer;
585588
}
586589
}
587590

@@ -591,12 +594,14 @@ private void UpdatePointer(PointerData pointer)
591594
pointer.Pointer.OnPostRaycast();
592595
}
593596

597+
#region Physics Raycasting
598+
594599
/// <summary>
595600
/// Perform a Unity physics Raycast to determine which scene objects with a collider is currently being gazed at, if any.
596601
/// </summary>
597602
/// <param name="pointer"></param>
598603
/// <param name="prioritizedLayerMasks"></param>
599-
private void RaycastPhysics(PointerData pointer, LayerMask[] prioritizedLayerMasks)
604+
private static void RaycastPhysics(PointerData pointer, LayerMask[] prioritizedLayerMasks)
600605
{
601606
bool isHit = false;
602607
int rayStepIndex = 0;
@@ -609,15 +614,34 @@ private void RaycastPhysics(PointerData pointer, LayerMask[] prioritizedLayerMas
609614
// Check raycast for each step in the pointing source
610615
for (int i = 0; i < pointer.Pointer.Rays.Length; i++)
611616
{
612-
if (RaycastPhysicsStep(pointer.Pointer.Rays[i], prioritizedLayerMasks, out physicsHit))
617+
switch (pointer.Pointer.RaycastMode)
613618
{
614-
// Set the pointer source's origin ray to this step
615-
isHit = true;
616-
rayStep = pointer.Pointer.Rays[i];
617-
rayStepIndex = i;
618-
// No need to continue once we've hit something
619-
break;
619+
case RaycastModeType.Simple:
620+
if (MixedRealityRaycaster.RaycastSimplePhysicsStep(pointer.Pointer.Rays[i], prioritizedLayerMasks, out physicsHit))
621+
{
622+
// Set the pointer source's origin ray to this step
623+
isHit = true;
624+
rayStep = pointer.Pointer.Rays[i];
625+
rayStepIndex = i;
626+
}
627+
break;
628+
case RaycastModeType.Box:
629+
Debug.LogWarning("Box Raycasting Mode not supported for pointers.");
630+
break;
631+
case RaycastModeType.Sphere:
632+
if (MixedRealityRaycaster.RaycastSpherePhysicsStep(pointer.Pointer.Rays[i], pointer.Pointer.SphereCastRadius, prioritizedLayerMasks, out physicsHit))
633+
{
634+
// Set the pointer source's origin ray to this step
635+
isHit = true;
636+
rayStep = pointer.Pointer.Rays[i];
637+
rayStepIndex = i;
638+
}
639+
break;
640+
default:
641+
throw new ArgumentOutOfRangeException();
620642
}
643+
644+
if (isHit) { break; }
621645
}
622646

623647
if (isHit)
@@ -630,62 +654,9 @@ private void RaycastPhysics(PointerData pointer, LayerMask[] prioritizedLayerMas
630654
}
631655
}
632656

633-
/// <summary>
634-
/// Raycasts each physics <see cref="RayStep"/>
635-
/// </summary>
636-
/// <param name="step"></param>
637-
/// <param name="prioritizedLayerMasks"></param>
638-
/// <param name="physicsHit"></param>
639-
/// <returns></returns>
640-
private bool RaycastPhysicsStep(RayStep step, LayerMask[] prioritizedLayerMasks, out RaycastHit physicsHit)
641-
{
642-
return prioritizedLayerMasks.Length == 1
643-
// If there is only one priority, don't prioritize
644-
? Physics.Raycast(step.Origin, step.Direction, out physicsHit, step.Length, prioritizedLayerMasks[0])
645-
// Raycast across all layers and prioritize
646-
: TryGetPrioritizedHit(Physics.RaycastAll(step.Origin, step.Direction, step.Length, Physics.AllLayers), prioritizedLayerMasks, out physicsHit);
647-
}
648-
649-
/// <summary>
650-
/// Tries to ge the prioritized raycast hit based on the prioritized layer masks.
651-
/// <para><remarks>Sorts all hit objects first by layerMask, then by distance.</remarks></para>
652-
/// </summary>
653-
/// <param name="hits"></param>
654-
/// <param name="priorityLayers"></param>
655-
/// <param name="raycastHit"></param>
656-
/// <returns>The minimum distance hit within the first layer that has hits</returns>
657-
private static bool TryGetPrioritizedHit(RaycastHit[] hits, LayerMask[] priorityLayers, out RaycastHit raycastHit)
658-
{
659-
raycastHit = default(RaycastHit);
660-
661-
if (hits.Length == 0)
662-
{
663-
return false;
664-
}
665-
666-
for (int layerMaskIdx = 0; layerMaskIdx < priorityLayers.Length; layerMaskIdx++)
667-
{
668-
RaycastHit? minHit = null;
669-
670-
for (int hitIdx = 0; hitIdx < hits.Length; hitIdx++)
671-
{
672-
RaycastHit hit = hits[hitIdx];
673-
if (hit.transform.gameObject.layer.IsInLayerMask(priorityLayers[layerMaskIdx]) &&
674-
(minHit == null || hit.distance < minHit.Value.distance))
675-
{
676-
minHit = hit;
677-
}
678-
}
679-
680-
if (minHit != null)
681-
{
682-
raycastHit = minHit.Value;
683-
return true;
684-
}
685-
}
657+
#endregion Physics Raycasting
686658

687-
return false;
688-
}
659+
#region uGUI Graphics Raycasting
689660

690661
/// <summary>
691662
/// Perform a Unity Graphics Raycast to determine which uGUI element is currently being gazed at, if any.
@@ -736,6 +707,15 @@ private void RaycastGraphics(PointerData pointer, LayerMask[] prioritizedLayerMa
736707
}
737708
}
738709

710+
/// <summary>
711+
/// Raycasts each graphic <see cref="RayStep"/>
712+
/// </summary>
713+
/// <param name="pointer"></param>
714+
/// <param name="step"></param>
715+
/// <param name="prioritizedLayerMasks"></param>
716+
/// <param name="overridePhysicsRaycast"></param>
717+
/// <param name="uiRaycastResult"></param>
718+
/// <returns></returns>
739719
private bool RaycastGraphicsStep(PointerData pointer, RayStep step, LayerMask[] prioritizedLayerMasks, out bool overridePhysicsRaycast, out RaycastResult uiRaycastResult)
740720
{
741721
// Move the uiRaycast camera to the current pointer's position.
@@ -790,6 +770,8 @@ private bool RaycastGraphicsStep(PointerData pointer, RayStep step, LayerMask[]
790770
return false;
791771
}
792772

773+
#endregion uGUI Graphics Raycasting
774+
793775
/// <summary>
794776
/// Raises the Focus Events to the Input Manger if needed.
795777
/// </summary>

Assets/MixedRealityToolkit/InputSystem/Gaze/GazeProvider.cs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ namespace Microsoft.MixedReality.Toolkit.InputSystem.Gaze
1818
[DisallowMultipleComponent]
1919
public class GazeProvider : MonoBehaviour, IMixedRealityGazeProvider
2020
{
21+
private const float VelocityThreshold = 0.1f;
22+
23+
private const float MovementThreshold = 0.01f;
24+
2125
[SerializeField]
2226
[Tooltip("Optional Cursor Prefab to use if you don't wish to reference a cursor in the scene.")]
2327
private GameObject cursorPrefab = null;
@@ -60,6 +64,16 @@ public class GazeProvider : MonoBehaviour, IMixedRealityGazeProvider
6064
[Tooltip("Transform that should be used to represent the gaze position and rotation. Defaults to CameraCache.Main")]
6165
private Transform gazeTransform = null;
6266

67+
[SerializeField]
68+
[Range(0.01f, 1f)]
69+
[Tooltip("Minimum head velocity threshold")]
70+
private float minHeadVelocityThreshold = 0.5f;
71+
72+
[SerializeField]
73+
[Range(0.1f, 5f)]
74+
[Tooltip("Maximum head velocity threshold")]
75+
private float maxHeadVelocityThreshold = 2f;
76+
6377
[SerializeField]
6478
[Tooltip("True to draw a debug view of the ray.")]
6579
private bool debugDrawRay = false;
@@ -103,10 +117,18 @@ public IMixedRealityInputSource GazeInputSource
103117
/// <inheritdoc />
104118
public Vector3 GazeDirection => GazePointer.Rays[0].Direction;
105119

120+
/// <inheritdoc />
121+
public Vector3 HeadVelocity { get; private set; }
122+
123+
/// <inheritdoc />
124+
public Vector3 HeadMovementDirection { get; private set; }
125+
106126
private float lastHitDistance = 2.0f;
107127

108128
private bool delayInitialization = true;
109129

130+
private Vector3 lastHeadPosition = Vector3.zero;
131+
110132
private IMixedRealityInputSystem inputSystem = null;
111133
private IMixedRealityInputSystem InputSystem => inputSystem ?? (inputSystem = MixedRealityManager.Instance.GetManager<IMixedRealityInputSystem>());
112134

@@ -197,6 +219,11 @@ public override bool TryGetPointerRotation(out Quaternion rotation)
197219

198220
#region Monobehaiour Implementation
199221

222+
private void OnValidate()
223+
{
224+
Debug.Assert(minHeadVelocityThreshold < maxHeadVelocityThreshold, "Minimum head velocity threshold should be less than the maximum velocity threshold.");
225+
}
226+
200227
protected virtual void OnEnable()
201228
{
202229
if (!delayInitialization)
@@ -241,6 +268,44 @@ private void Update()
241268
}
242269
}
243270

271+
private void LateUpdate()
272+
{
273+
// Update head velocity.
274+
Vector3 headPosition = GazeOrigin;
275+
Vector3 headDelta = headPosition - lastHeadPosition;
276+
277+
if (headDelta.sqrMagnitude < MovementThreshold * MovementThreshold)
278+
{
279+
headDelta = Vector3.zero;
280+
}
281+
282+
if (Time.fixedDeltaTime > 0)
283+
{
284+
float velocityAdjustmentRate = 3f * Time.fixedDeltaTime;
285+
HeadVelocity = HeadVelocity * (1f - velocityAdjustmentRate) + headDelta * velocityAdjustmentRate / Time.fixedDeltaTime;
286+
287+
if (HeadVelocity.sqrMagnitude < VelocityThreshold * VelocityThreshold)
288+
{
289+
HeadVelocity = Vector3.zero;
290+
}
291+
}
292+
293+
// Update Head Movement Direction
294+
float multiplier = Mathf.Clamp01(Mathf.InverseLerp(minHeadVelocityThreshold, maxHeadVelocityThreshold, HeadVelocity.magnitude));
295+
296+
Vector3 newHeadMoveDirection = Vector3.Lerp(headPosition, HeadVelocity, multiplier).normalized;
297+
lastHeadPosition = headPosition;
298+
float directionAdjustmentRate = Mathf.Clamp01(5f * Time.fixedDeltaTime);
299+
300+
HeadMovementDirection = Vector3.Slerp(HeadMovementDirection, newHeadMoveDirection, directionAdjustmentRate);
301+
302+
if (debugDrawRay)
303+
{
304+
Debug.DrawLine(lastHeadPosition, lastHeadPosition + HeadMovementDirection * 10f, Color.Lerp(Color.red, Color.green, multiplier));
305+
Debug.DrawLine(lastHeadPosition, lastHeadPosition + HeadVelocity, Color.yellow);
306+
}
307+
}
308+
244309
private void OnDisable()
245310
{
246311
GazePointer.BaseCursor?.SetVisibility(false);

0 commit comments

Comments
 (0)