/// <summary> /// Populates the event with data. /// </summary> /// <param name="inputSource"></param> /// <param name="controller"></param> /// <param name="pose"></param> public void Initialize(IMixedRealityInputSource inputSource, IMixedRealityController controller, MixedRealityPose pose) { Initialize(inputSource, controller); ThreeDofPosition = pose.Position; ThreeDofRotation = pose.Rotation; MixedRealityPose = pose; }
/// <inheritdoc /> public override void SolverUpdate() { // Determine the new active hand. IMixedRealityController newActivehand = null; foreach (var hand in handStack) { if (IsHandActive(hand)) { newActivehand = hand; break; } } // Track the new active hand. if (trackedHand == null || trackedHand != newActivehand) { ChangeTrackedObjectType(newActivehand); } // Update the goal position and rotation if a tracked hand is present. if (trackedHand != null && SolverHandler.TransformTarget != null) { if (updateWhenOppositeHandNear || !IsOppositeHandNear(trackedHand)) { GoalPosition = CalculateGoalPosition(); GoalRotation = CalculateGoalRotation(); } } UpdateWorkingPositionToGoal(); UpdateWorkingRotationToGoal(); }
private static T CreatePointerPrefab <T>(string prefabPath, out IMixedRealityInputSource inputSource, out IMixedRealityController controller) where T : IMixedRealityPointer { var pointerPrefab = AssetDatabase.LoadAssetAtPath <Object>(prefabPath); var result = PrefabUtility.InstantiatePrefab(pointerPrefab) as GameObject; T pointer = result.GetComponent <T>(); inputSource = CoreServices.InputSystem.RequestNewGenericInputSource( pointer.PointerName, new IMixedRealityPointer[] { pointer }); // use MouseController as dummy wrapper controller controller = new MouseController(TrackingState.Tracked, Handedness.Right, inputSource); if (inputSource != null) { for (int i = 0; i < inputSource.Pointers.Length; i++) { inputSource.Pointers[i].Controller = controller; } } CoreServices.InputSystem.RaiseSourceDetected(inputSource, controller); CoreServices.InputSystem?.RaiseSourceTrackingStateChanged(inputSource, controller, TrackingState.Tracked); return(pointer); }
protected void RemoveController(IMixedRealityController controller) { if (controller != null) { activeControllers.Remove(controller); } }
private static bool IsGgvOrDesktopController(IMixedRealityController controller) { return(controller is WindowsMixedRealityGGVHand || controller is MouseController # if UNITY_EDITOR // || controller is SimulatedArticulatedHand #endif ); }
private MixedRealityInteractionMapping GetSpatialGripInfoForController(IMixedRealityController controller) { if (controller == null) { return(null); } return(controller.Interactions?.First(x => x.InputType == DeviceInputType.SpatialGrip)); }
/// <summary> /// Starts to track the passed in controller's transform, assuming it meets the previously set handedness criteria. /// </summary> /// <param name="newController">The new controller to be tracked.</param> protected virtual void AddControllerTransform(IMixedRealityController newController) { if (newController.ControllerHandedness == handedness && newController.Visualizer.GameObjectProxy.transform != null && !newController.Visualizer.GameObjectProxy.transform.Equals(ControllerTransform)) { ControllerTransform = newController.Visualizer.GameObjectProxy.transform; OnControllerFound(); } }
protected override void OnEnable() { base.OnEnable(); handBounds = GetComponent <HandBounds>(); // Initially no hands are tacked or active. trackedController = null; OnLastHandLost.Invoke(); OnHandDeactivate.Invoke(); }
protected override void OnEnable() { base.OnEnable(); InputSystem?.RegisterHandler <IMixedRealitySourceStateHandler>(this); handBounds = GetComponent <HandBounds>(); // Initially no hands are tacked or active. trackedHand = null; onLastHandLost?.Invoke(); onHandDeactivate?.Invoke(); }
private static bool IsPalmFacingCamera(IMixedRealityController hand) { MixedRealityPose palmPose; var jointedHand = hand as IMixedRealityHand; if ((jointedHand != null) && jointedHand.TryGetJoint(TrackedHandJoint.Palm, out palmPose)) { return(Vector3.Dot(palmPose.Up, CameraCache.Main.transform.forward) > 0.0f); } return(false); }
public bool GetTransForm(out Vector3 _fingerposition) { IMixedRealityController c = GetController(Handedness.Left); var jointedHand = c as IMixedRealityHand; MixedRealityPose MiddleDistalParm; if (jointedHand.TryGetJoint(handjoint, out MiddleDistalParm)) { _fingerposition = MiddleDistalParm.Position; return(true); } _fingerposition = new Vector3(0, 0, 0); return(false); }
/// <summary> /// Gets the <seealso cref="MixedRealityInteractionMapping"/> matching the <seealso cref="DeviceInputType"/> for /// the specified controller. /// </summary> /// <param name="controller">The <seealso cref="IMixedRealityController"/> instance</param> /// <param name="inputType">The type of device input</param> /// <param name="mapping">The <seealso cref="MixedRealityInteractionMapping"/> being returned</param> /// <returns> /// True if the interaction mapping is being returned, false otherwise. /// </returns> 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); }
private void SetController(IMixedRealityController controller) { IMixedRealityHand hand = controller as IMixedRealityHand; IMixedRealityController mrcontroller = controller as IMixedRealityController; if (hand != null) { try { detectedHand = hand; if (controller.ControllerHandedness == Handedness.Left) { leftHand = hand; } else if (controller.ControllerHandedness == Handedness.Right) { rightHand = hand; } } catch (Exception) { //Debug.Log("Missed a hand, retrying"); } } else if (mrcontroller != null) { try { detectedController = mrcontroller; if (controller.ControllerHandedness == Handedness.Left) { leftController = mrcontroller; } else if (controller.ControllerHandedness == Handedness.Right) { rightController = mrcontroller; } } catch (Exception) { //Debug.Log("Missed a controller, retrying"); } } }
private static Ray CalculateProjectedSafeZoneRay(Vector3 origin, IMixedRealityController hand, SolverSafeZone handSafeZone) { Vector3 direction; switch (handSafeZone) { default: case SolverSafeZone.UlnarSide: { direction = Vector3.Cross(CameraCache.Main.transform.forward, Vector3.up); direction = IsPalmFacingCamera(hand) ? direction : -direction; if (hand.ControllerHandedness == Handedness.Left) { direction = -direction; } } break; case SolverSafeZone.RadialSide: { direction = Vector3.Cross(CameraCache.Main.transform.forward, Vector3.up); direction = IsPalmFacingCamera(hand) ? direction : -direction; if (hand.ControllerHandedness == Handedness.Right) { direction = -direction; } } break; case SolverSafeZone.AboveFingerTips: { direction = CameraCache.Main.transform.up; } break; case SolverSafeZone.BelowWrist: { direction = -CameraCache.Main.transform.up; } break; } return(new Ray(origin + direction, -direction)); }
/// <inheritdoc /> public override void Update() { using (UpdatePerfMarker.Auto()) { if (!IsEnabled) { return; } base.Update(); // Ensure that touch up and source lost events are at least one frame apart. for (int i = 0; i < touchesToRemove.Count; i++) { IMixedRealityController controller = touchesToRemove[i]; Service?.RaiseSourceLost(controller.InputSource, controller); } touchesToRemove.Clear(); int touchCount = UInput.touchCount; for (int i = 0; i < touchCount; i++) { Touch touch = UInput.touches[i]; // Construct a ray from the current touch coordinates Ray ray = CameraCache.Main.ScreenPointToRay(touch.position); switch (touch.phase) { case TouchPhase.Began: AddTouchController(touch, ray); break; case TouchPhase.Moved: case TouchPhase.Stationary: UpdateTouchData(touch, ray); break; case TouchPhase.Ended: case TouchPhase.Canceled: RemoveTouchController(touch); break; } } } }
/// <summary> /// Swaps out the currently tracked hand while triggered appropriate events. /// </summary> /// <param name="hand">Which hand to track now.</param> private void ChangeTrackedObjectType(IMixedRealityController hand) { if (hand != null) { if (SolverHandler.TrackedTargetType == TrackedObjectType.HandJoint || SolverHandler.TrackedTargetType == TrackedObjectType.MotionController) { if (SolverHandler.TrackedHandness != hand.ControllerHandedness) { SolverHandler.TrackedHandness = hand.ControllerHandedness; // Move the currently tracked hand to the top of the stack. handStack.Remove(hand); handStack.Insert(0, hand); } if (trackedHand == null) { trackedHand = hand; onHandActivate?.Invoke(); } else { StartCoroutine(ToggleCursor(true)); trackedHand = hand; } // Wait one frame to disable the cursor in case one hasn't been instantiated yet. StartCoroutine(ToggleCursor(false, true)); } else { Debug.LogWarning("ChangeTrackedObjectType failed because TrackedTargetType is not of type HandJoint or MotionController."); } } else { if (trackedHand != null) { StartCoroutine(ToggleCursor(true)); trackedHand = null; onHandDeactivate?.Invoke(); } } }
/// <summary> /// Determines if a controller meets the requirements for use with constraining the tracked object and determines if the /// palm is currently facing the user. /// </summary> /// <param name="controller">The hand to check against.</param> /// <returns>True if this hand should be used from tracking.</returns> protected override bool IsValidController(IMixedRealityController controller) { if (!base.IsValidController(controller)) { return(false); } MixedRealityPose palmPose; var jointedHand = controller as IMixedRealityHand; if (jointedHand != null) { if (jointedHand.TryGetJoint(TrackedHandJoint.Palm, out palmPose)) { if (requireFlatHand) { // Check if the triangle's normal formed from the palm, to index, to ring finger tip roughly matches the palm normal. MixedRealityPose indexTipPose, ringTipPose; if (jointedHand.TryGetJoint(TrackedHandJoint.IndexTip, out indexTipPose) && jointedHand.TryGetJoint(TrackedHandJoint.RingTip, out ringTipPose)) { var handNormal = Vector3.Cross(indexTipPose.Position - palmPose.Position, ringTipPose.Position - indexTipPose.Position).normalized; handNormal *= (jointedHand.ControllerHandedness == Handedness.Right) ? 1.0f : -1.0f; if (Vector3.Angle(palmPose.Up, handNormal) > flatHandThreshold) { return(false); } } } } else { Debug.LogError("HandConstraintPalmUp requires controllers of type IMixedRealityHand to perform hand activation tests."); } return(Vector3.Angle(palmPose.Up, CameraCache.Main.transform.forward) < facingThreshold); } return(true); }
/// <inheritdoc /> public override void Update() { Profiler.BeginSample("[MRTK] UnityTouchDeviceManager.Update"); base.Update(); // Ensure that touch up and source lost events are at least one frame apart. for (int i = 0; i < touchesToRemove.Count; i++) { IMixedRealityController controller = touchesToRemove[i]; Service?.RaiseSourceLost(controller.InputSource, controller); } touchesToRemove.Clear(); int touchCount = UInput.touchCount; for (int i = 0; i < touchCount; i++) { Touch touch = UInput.touches[i]; // Construct a ray from the current touch coordinates Ray ray = CameraCache.Main.ScreenPointToRay(touch.position); switch (touch.phase) { case TouchPhase.Began: AddTouchController(touch, ray); break; case TouchPhase.Moved: case TouchPhase.Stationary: UpdateTouchData(touch, ray); break; case TouchPhase.Ended: case TouchPhase.Canceled: RemoveTouchController(touch); break; } } Profiler.EndSample(); // Update }
public bool TryGetSpecificControllerPose(Handedness handedness, TrackedHandJoint handJointToTrack, out Vector3 position, out Quaternion rotation) { bool retrieved = false; position = Vector3.zero; rotation = Quaternion.identity; IMixedRealityHand currentHand = detectedHand; IMixedRealityController currentController = detectedController; if (handedness == Handedness.Left) { currentHand = leftHand; currentController = leftController; } else if (handedness == Handedness.Right) { currentHand = rightHand; currentController = rightController; } if (currentHand != null && currentHand.TryGetJoint(handJointToTrack, out handPose)) { position = handPose.Position; rotation = handPose.Rotation; retrieved = true; } else if (currentController != null) { try { position = currentController.InputSource.Pointers[0].Position; rotation = currentController.InputSource.Pointers[0].Rotation; retrieved = true; } catch (Exception) { retrieved = false; } } return(retrieved); }
/// <summary> /// Determines if a hand meets the requirements for use with constraining the tracked object. /// </summary> /// <param name="controller">The controller to check against.</param> /// <returns>True if this hand should be used from tracking.</returns> protected virtual bool IsValidController(IMixedRealityController controller) { if (controller == null) { return(false); } // Check to make sure none of the hand's pointer's a locked. We don't want to track a hand which is currently // interacting with something else. foreach (var pointer in controller.InputSource.Pointers) { if (pointer.IsFocusLocked) { return(false); } } return(true); }
/// <summary> /// Performs an intersection test to see if the left hand is near the right hand or vice versa. /// </summary> /// <param name="controller">The hand to check against.</param> /// <returns>True, when hands are near each other.</returns> protected virtual bool IsOppositeHandNear(IMixedRealityController controller) { if (controller != null) { if (handBounds.Bounds.TryGetValue(controller.ControllerHandedness.GetOppositeHandedness(), out Bounds oppositeHandBounds) && handBounds.Bounds.TryGetValue(controller.ControllerHandedness, out Bounds trackedHandBounds)) { // Double the size of the hand bounds to allow for greater tolerance. trackedHandBounds.Expand(trackedHandBounds.extents); oppositeHandBounds.Expand(oppositeHandBounds.extents); if (trackedHandBounds.Intersects(oppositeHandBounds)) { return(true); } } } return(false); }
/// <summary> /// Enables/disables all cursors on the currently tracked hand. /// </summary> /// <param name="controller">Controller target to search for pointers</param> /// <param name="visible">Is the cursor visible?</param> /// <param name="frameDelay">Delay one frame before performing the toggle to allow the pointers to instantiate their cursors.</param> protected virtual IEnumerator ToggleCursors(IMixedRealityController controller, bool visible, bool frameDelay = false) { if (controller == null) { yield break; } if (hideHandCursorsOnActivate) { if (frameDelay) { yield return(null); } foreach (var pointer in controller?.InputSource.Pointers) { pointer?.BaseCursor?.SetVisibility(visible); } } }
/// <summary> /// Performs an intersection test to see if the left hand is near the right hand or vice versa. /// </summary> /// <param name="hand">The hand to check against.</param> /// <returns>True, when hands are near each other.</returns> protected virtual bool IsOppositeHandNear(IMixedRealityController hand) { if (hand != null) { Bounds oppositeHandBounds, trackedHandBounds; if (handBounds.Bounds.TryGetValue((hand.ControllerHandedness == Handedness.Left) ? Handedness.Right : Handedness.Left, out oppositeHandBounds) && handBounds.Bounds.TryGetValue(hand.ControllerHandedness, out trackedHandBounds)) { // Double the size of the hand bounds to allow for greater tolerance. trackedHandBounds.Expand(trackedHandBounds.extents); oppositeHandBounds.Expand(oppositeHandBounds.extents); if (trackedHandBounds.Intersects(oppositeHandBounds)) { return(true); } } } return(false); }
/// <summary> /// Determines if a hand meets the requirements for use with constraining the tracked object. /// </summary> /// <param name="hand">The hand to check against.</param> /// <returns>True if this hand should be used from tracking.</returns> protected virtual bool IsHandActive(IMixedRealityController hand) { // If transitioning between hands is not allowed, make sure the TrackedObjectType matches the hand. if (!autoTransitionBetweenHands) { return((SolverHandler.TrackedTargetType == TrackedObjectType.HandJoint || SolverHandler.TrackedTargetType == TrackedObjectType.MotionController) && (SolverHandler.TrackedHandness == Handedness.Both || hand.ControllerHandedness == SolverHandler.TrackedHandness)); } // Check to make sure none of the hand's pointer's a locked. We don't want to track a hand which is currently // interacting with something else. foreach (var pointer in hand.InputSource.Pointers) { if (pointer.IsFocusLocked) { return(false); } } return(true); }
protected void AddController(IMixedRealityController controller) { activeControllers.Add(controller); }
/// <summary> /// Populates the event with data. /// </summary> /// <param name="inputSource"></param> /// <param name="controller"></param> public void Initialize(IMixedRealityInputSource inputSource, IMixedRealityController controller) { // NOTE: Source State events do not have an associated Input Action. BaseInitialize(inputSource, Definitions.InputSystem.MixedRealityInputAction.None); Controller = controller; }
/// <summary> /// Gets the <seealso cref="IMixedRealityController"/> instance matching the specified source type and hand. /// </summary> /// <param name="sourceType">Type type of the input source</param> /// <param name="hand">The handedness of the controller</param> /// <param name="controller">The <seealso cref="IMixedRealityController"/> instance being returned</param> /// <returns> /// True if the controller instance is beeing returned, false otherwise. /// </returns> private static bool TryGetControllerInstance(InputSourceType sourceType, Handedness hand, out IMixedRealityController controller) { controller = null; foreach (IMixedRealityController c in CoreServices.InputSystem.DetectedControllers) { if ((c.InputSource?.SourceType == sourceType) && (c.ControllerHandedness == hand)) { controller = c; return(true); } } return(false); }
/// <summary> /// Populates the event with data. /// </summary> /// <param name="inputSource"></param> /// <param name="controller"></param> /// <param name="data"></param> public void Initialize(IMixedRealityInputSource inputSource, IMixedRealityController controller, T data) { Initialize(inputSource, controller); SourceData = data; }
/// <summary> /// Determines if a controller meets the requirements for use with constraining the tracked object and determines if the /// palm is currently facing the user. /// </summary> /// <param name="controller">The hand to check against.</param> /// <returns>True if this hand should be used from tracking.</returns> protected override bool IsValidController(IMixedRealityController controller) { if (!base.IsValidController(controller)) { return(false); } MixedRealityPose palmPose; var jointedHand = controller as IMixedRealityHand; bool palmFacingThresholdMet = false; if (jointedHand != null) { if (jointedHand.TryGetJoint(TrackedHandJoint.Palm, out palmPose)) { float palmCameraAngle = Vector3.Angle(palmPose.Up, CameraCache.Main.transform.forward); if (requireFlatHand) { // Check if the triangle's normal formed from the palm, to index, to ring finger tip roughly matches the palm normal. MixedRealityPose indexTipPose, ringTipPose; if (jointedHand.TryGetJoint(TrackedHandJoint.IndexTip, out indexTipPose) && jointedHand.TryGetJoint(TrackedHandJoint.RingTip, out ringTipPose)) { var handNormal = Vector3.Cross(indexTipPose.Position - palmPose.Position, ringTipPose.Position - indexTipPose.Position).normalized; handNormal *= (jointedHand.ControllerHandedness == Handedness.Right) ? 1.0f : -1.0f; if (Vector3.Angle(palmPose.Up, handNormal) > flatHandThreshold) { return(false); } } } // Check if the palm angle meets the prescribed threshold palmFacingThresholdMet = palmCameraAngle < facingThreshold; // If using hybrid hand rotation, we proceed with additional checks if (useHybridHandRotation && palmFacingThresholdMet) { // If we are above the threshold angle, keep the menu mapped to the tracked object if (palmCameraAngle > hybridHandRotationThresholdAngle) { RotationBehavior = SolverRotationBehavior.LookAtTrackedObject; } // If we are within the threshold angle, we snap to follow the camera else { RotationBehavior = SolverRotationBehavior.LookAtMainCamera; } } } else { Debug.LogError("HandConstraintPalmUp requires controllers of type IMixedRealityHand to perform hand activation tests."); } return(palmFacingThresholdMet); } return(true); }
/// <summary> /// This function is called to fill the HandTrackingIntputEventData object with information /// </summary> /// <param name="inputSource">Reference to the HandTrackingInputSource that created the EventData</param> /// <param name="controller">Reference to the IMixedRealityController that created the EventData</param> /// <param name="sourceHandedness">Handedness of the HandTrackingInputSource that created the EventData</param> /// <param name="touchPoint">Global position of the HandTrackingInputSource that created the EventData</param> public void Initialize(IMixedRealityInputSource inputSource, IMixedRealityController controller, Handedness sourceHandedness, Vector3 touchPoint) { Initialize(inputSource, sourceHandedness, MixedRealityInputAction.None, touchPoint); Controller = controller; }