// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using Microsoft.MixedReality.Toolkit.Utilities; using UnityEngine; namespace Microsoft.MixedReality.Toolkit.Input { /// /// Utilities for accessing position, rotation of rays. /// public static class InputRayUtils { /// /// Gets the ray representing the position and direction of the user's head. /// /// The ray the head gaze public static Ray GetHeadGazeRay() { return new Ray(CameraCache.Main.transform.position, CameraCache.Main.transform.forward); } /// /// Gets the ray representing the position and direction of the user's eyes. /// /// The ray being returned /// /// True if the ray is being returned, false otherwise. /// public static bool TryGetEyeGazeRay(out Ray ray) { ray = new Ray(); IMixedRealityEyeGazeProvider eyeGazeProvider = CoreServices.InputSystem?.EyeGazeProvider; if ((eyeGazeProvider == null) || !eyeGazeProvider.IsEyeTrackingDataValid) { return false; } ray = eyeGazeProvider.LatestEyeGaze; return true; } /// /// Gets the ray associated with the user's hand. /// /// The handedness of the hand /// The ray being returned /// /// True if the ray is being returned, false otherwise. /// public static bool TryGetHandRay(Handedness hand, out Ray ray) { ray = new Ray(); IMixedRealityController controller; if (TryGetControllerInstance(InputSourceType.Hand, hand, out controller)) { MixedRealityInteractionMapping mapping; if (TryGetInteractionMapping(controller, DeviceInputType.SpatialPointer, out mapping)) { ray.origin = mapping.PositionData; ray.direction = MathUtilities.GetDirection(mapping.RotationData); return true; } } return false; } /// /// Gets the ray associated with the motion controller. /// /// The handedness of the motion controller /// The ray being returned /// /// True if the ray is being returned, false otherwise. /// public static bool TryGetMotionControllerRay(Handedness hand, out Ray ray) { ray = new Ray(); IMixedRealityController controller; if (TryGetControllerInstance(InputSourceType.Controller, hand, out controller)) { MixedRealityInteractionMapping mapping; if (TryGetInteractionMapping(controller, DeviceInputType.SpatialPointer, out mapping)) { ray.origin = mapping.PositionData; ray.direction = MathUtilities.GetDirection(mapping.RotationData); return true; } } return false; } /// /// Gets the first instance matching the specified source type and hand. /// /// Type of the input source /// The handedness of the controller /// The instance being returned /// /// True if the controller instance is being returned, false otherwise. /// private static bool TryGetControllerInstance(InputSourceType sourceType, Handedness hand, out IMixedRealityController controller) { controller = null; System.Collections.Generic.HashSet controllers = CoreServices.InputSystem?.DetectedControllers; if (controllers == null) { return false; } foreach (IMixedRealityController c in controllers) { if ((c.InputSource?.SourceType == sourceType) && (c.ControllerHandedness == hand)) { controller = c; return true; } } return false; } /// /// Gets the matching the for /// the specified controller. /// /// The instance /// The type of device input /// The being returned /// /// True if the interaction mapping is being returned, false otherwise. /// private static bool TryGetInteractionMapping(IMixedRealityController controller, DeviceInputType inputType, out MixedRealityInteractionMapping mapping) { mapping = null; MixedRealityInteractionMapping[] mappings = controller.Interactions; for (int i = 0; i < mappings.Length; i++) { if (mappings[i].InputType == inputType) { mapping = mappings[i]; return true; } } return false; } /// /// Gets the ray associated with the desired input source type /// and hand. /// /// The type of input source /// The handedness of the input source /// The ray being returned /// /// True if the ray is being returned, false otherwise. /// public static bool TryGetRay(InputSourceType sourceType, Handedness hand, out Ray ray) { bool success = false; switch (sourceType) { case InputSourceType.Head: // The head does not have a handedness, so we ignore the hand parameter. ray = GetHeadGazeRay(); success = true; break; case InputSourceType.Eyes: // The eyes do not have a handedness, so we ignore the hand parameter. success = TryGetEyeGazeRay(out ray); break; case InputSourceType.Hand: success = TryGetHandRay(hand, out ray); break; case InputSourceType.Controller: success = TryGetMotionControllerRay(hand, out ray); break; default: Debug.Log($"It is not supported to get the ray for {sourceType} sources."); ray = new Ray(); success = false; break; } return success; } } }