|
|
- namespace VRTK
- {
- using UnityEngine;
- #if VRTK_DEFINE_SDK_WINDOWSMR && UNITY_2017_2_OR_NEWER
- using System.Collections;
- using UnityEngine.XR.WSA.Input;
- using VRTK.WindowsMixedReality.Utilities;
- #endif
- #if VRTK_DEFINE_WINDOWSMR_CONTROLLER_VISUALIZATION
- using VRTK.WindowsMixedReality;
- #endif
-
- public class WindowsMR_TrackedObject : MonoBehaviour
- {
- #if VRTK_DEFINE_SDK_WINDOWSMR && UNITY_2017_2_OR_NEWER
- private struct ButtonState
- {
- //
- // Summary:
- // ///
- // Normalized amount ([0, 1]) representing how much select is pressed.
- // ///
- public float SelectPressedAmount { get; set; }
- //
- // Summary:
- // ///
- // Depending on the InteractionSourceType of the interaction source, this returning
- // true could represent a number of equivalent things: main button on a blicker,
- // air-tap on a hand, and the trigger on a motion controller.
- // ///
- public bool SelectPressed { get; set; }
- //
- // Summary:
- // ///
- // Whether or not the menu button is pressed.
- // ///
- public bool MenuPressed { get; set; }
- //
- // Summary:
- // ///
- // Whether the controller is grasped.
- // ///
- public bool Grasped { get; set; }
- //
- // Summary:
- // ///
- // Whether or not the touchpad is touched.
- // ///
- public bool TouchpadTouched { get; set; }
- //
- // Summary:
- // ///
- // Whether or not the touchpad is pressed, as if a button.
- // ///
- public bool TouchpadPressed { get; set; }
- //
- // Summary:
- // ///
- // Normalized coordinates for the position of a touchpad interaction.
- // ///
- public Vector2 TouchpadPosition { get; set; }
- //
- // Summary:
- // ///
- // Normalized coordinates for the position of a thumbstick.
- // ///
- public Vector2 ThumbstickPosition { get; set; }
- //
- // Summary:
- // ///
- // Whether or not the thumbstick is pressed.
- // ///
- public bool ThumbstickPressed { get; set; }
- }
-
- [SerializeField]
- [Tooltip("Defines the controllers hand.")]
- private InteractionSourceHandedness handedness;
-
- public Vector3 AngularVelocity { get { return angularVelocity; } }
- public InteractionSourceHandedness Handedness { get { return handedness; } }
- public uint Index { get { return index; } }
-
- private uint index = uint.MaxValue;
- private ButtonState currentButtonState;
- private ButtonState prevButtonState;
- private Vector3 angularVelocity;
-
- private float hairTriggerDelta = 0.1f; // amount trigger must be pulled or released to change state
- private float hairTriggerLimit;
- private bool hairTriggerState;
- private bool hairTriggerPrevState;
- private bool isDetected;
-
- public float GetPressAmount(InteractionSourcePressType button)
- {
- switch (button)
- {
- case InteractionSourcePressType.Select:
- return currentButtonState.SelectPressedAmount;
- }
- return 0;
- }
-
- public bool GetPress(InteractionSourcePressType button)
- {
- switch (button)
- {
- case InteractionSourcePressType.Select:
- return currentButtonState.SelectPressed;
- case InteractionSourcePressType.Grasp:
- return currentButtonState.Grasped;
- case InteractionSourcePressType.Menu:
- return currentButtonState.MenuPressed;
- case InteractionSourcePressType.Touchpad:
- return currentButtonState.TouchpadPressed;
- case InteractionSourcePressType.Thumbstick:
- return currentButtonState.ThumbstickPressed;
- }
- return false;
- }
-
- public bool GetPressDown(InteractionSourcePressType button)
- {
- switch (button)
- {
- case InteractionSourcePressType.Select:
- return (prevButtonState.SelectPressed == false && currentButtonState.SelectPressed == true);
- case InteractionSourcePressType.Grasp:
- return (prevButtonState.Grasped == false && currentButtonState.Grasped == true);
- case InteractionSourcePressType.Menu:
- return (prevButtonState.MenuPressed == false && currentButtonState.MenuPressed == true);
- case InteractionSourcePressType.Touchpad:
- return (prevButtonState.TouchpadPressed == false && currentButtonState.TouchpadPressed == true);
- case InteractionSourcePressType.Thumbstick:
- return (prevButtonState.ThumbstickPressed == false && currentButtonState.ThumbstickPressed == true);
- }
- return false;
- }
-
- public bool GetPressUp(InteractionSourcePressType button)
- {
- switch (button)
- {
- case InteractionSourcePressType.Select:
- return (prevButtonState.SelectPressed == true && currentButtonState.SelectPressed == false);
- case InteractionSourcePressType.Grasp:
- return (prevButtonState.Grasped == true && currentButtonState.Grasped == false);
- case InteractionSourcePressType.Menu:
- return (prevButtonState.MenuPressed == true && currentButtonState.MenuPressed == false);
- case InteractionSourcePressType.Touchpad:
- return (prevButtonState.TouchpadPressed == true && currentButtonState.TouchpadPressed == false);
- case InteractionSourcePressType.Thumbstick:
- return (prevButtonState.ThumbstickPressed == true && currentButtonState.ThumbstickPressed == false);
- }
- return false;
- }
-
- public bool GetTouch(InteractionSourcePressType button)
- {
- switch (button)
- {
- case InteractionSourcePressType.Touchpad:
- return currentButtonState.TouchpadTouched;
- }
- return false;
- }
-
- public bool GetTouchDown(InteractionSourcePressType button)
- {
- switch (button)
- {
- case InteractionSourcePressType.Touchpad:
- return (prevButtonState.TouchpadTouched == false && currentButtonState.TouchpadTouched == true);
- }
- return false;
- }
-
- public bool GetTouchUp(InteractionSourcePressType button)
- {
- switch (button)
- {
- case InteractionSourcePressType.Touchpad:
- return (prevButtonState.TouchpadTouched == true && currentButtonState.TouchpadTouched == false);
- }
- return false;
- }
-
- public Vector2 GetAxis(InteractionSourcePressType button)
- {
- switch (button)
- {
- case InteractionSourcePressType.Select:
- return new Vector2(currentButtonState.SelectPressedAmount, 0f);
- case InteractionSourcePressType.Touchpad:
- return currentButtonState.TouchpadPosition;
- case InteractionSourcePressType.Thumbstick:
- return currentButtonState.ThumbstickPosition;
- }
- return Vector2.zero;
- }
-
- public bool GetHairTrigger()
- {
- return hairTriggerState;
- }
-
- public bool GetHairTriggerDown()
- {
- return (hairTriggerState && !hairTriggerPrevState);
- }
-
- public bool GetHairTriggerUp()
- {
- return !hairTriggerState && hairTriggerPrevState;
- }
-
- public void StartHaptics(float intensity = 0.5f, float duration = 0.4f)
- {
- InteractionSourceState[] states = InteractionManager.GetCurrentReading();
-
- foreach (InteractionSourceState state in states)
- {
- if (state.source.kind == InteractionSourceKind.Controller && state.source.handedness == handedness)
- {
- state.source.StartHaptics(intensity, duration);
- }
- }
- }
-
- protected virtual void OnEnable()
- {
- switch (handedness)
- {
- case InteractionSourceHandedness.Left:
- index = 1;
- break;
-
- case InteractionSourceHandedness.Right:
- index = 2;
- break;
-
- case InteractionSourceHandedness.Unknown:
- Debug.LogError("Handedness of " + gameObject.name + " is not set.");
- break;
- }
-
- InitController();
- }
-
- protected virtual void OnDisable()
- {
- InteractionManager.InteractionSourceDetected -= InteractionManager_InteractionSourceDetected;
- InteractionManager.InteractionSourceLost -= InteractionManager_InteractionSourceLost;
- InteractionManager.InteractionSourceUpdated -= InteractionManager_InteractionSourceUpdated;
- InteractionManager.InteractionSourcePressed -= InteractionManager_InteractionSourcePressed;
- InteractionManager.InteractionSourceReleased -= InteractionManager_InteractionSourceReleased;
- }
-
- protected virtual void Update()
- {
- if (isDetected)
- {
- InteractionSourceState[] states = InteractionManager.GetCurrentReading();
-
- foreach (InteractionSourceState state in states)
- {
- if (state.source.kind == InteractionSourceKind.Controller && state.source.handedness == handedness)
- {
- // Necessary to update Select Button State in Update Loop since it causes issues with PressDown and PressUp
- // Will be changed in a future iteration (probably VRTK 4)
- UpdateSelectButton(state);
- UpdateTouchpadTouch(state);
- }
- }
- }
- }
-
- protected virtual void InitController()
- {
- InteractionManager.InteractionSourceDetected += InteractionManager_InteractionSourceDetected;
- InteractionManager.InteractionSourceLost += InteractionManager_InteractionSourceLost;
- InteractionManager.InteractionSourceUpdated += InteractionManager_InteractionSourceUpdated;
- InteractionManager.InteractionSourcePressed += InteractionManager_InteractionSourcePressed;
- InteractionManager.InteractionSourceReleased += InteractionManager_InteractionSourceReleased;
-
- #if VRTK_DEFINE_WINDOWSMR_CONTROLLER_VISUALIZATION
- if (MotionControllerVisualizer.Instance != null)
- {
- MotionControllerVisualizer.Instance.OnControllerModelLoaded += AttachControllerModel;
- }
- #endif
- }
-
- protected virtual void SetupController(InteractionSource source)
- {
- index = source.id;
- currentButtonState = new ButtonState();
- prevButtonState = new ButtonState();
- isDetected = true;
- }
-
- #if VRTK_DEFINE_WINDOWSMR_CONTROLLER_VISUALIZATION
- protected virtual void AttachControllerModel(MotionControllerInfo controllerInfo)
- {
- if (controllerInfo.Handedness == Handedness)
- {
- Transform controllerTransform = controllerInfo.ControllerParent.transform;
- controllerTransform.SetParent(transform);
- controllerTransform.localPosition = Vector3.zero;
- controllerTransform.localRotation = Quaternion.identity;
- controllerTransform.localScale = Vector3.one;
- }
- }
- #endif
- protected virtual void InteractionManager_InteractionSourceDetected(InteractionSourceDetectedEventArgs args)
- {
- InteractionSourceState state = args.state;
- InteractionSource source = state.source;
-
- if (source.kind == InteractionSourceKind.Controller && source.handedness == handedness)
- {
- SetupController(source);
- }
- }
-
- protected virtual void InteractionManager_InteractionSourceLost(InteractionSourceLostEventArgs args)
- {
- InteractionSourceState state = args.state;
- InteractionSource source = state.source;
-
- if (source.kind == InteractionSourceKind.Controller && source.handedness == handedness)
- {
- index = uint.MaxValue;
- currentButtonState = new ButtonState();
- isDetected = false;
- }
- }
-
- protected virtual void InteractionManager_InteractionSourceUpdated(InteractionSourceUpdatedEventArgs args)
- {
- InteractionSourceState state = args.state;
- InteractionSource source = state.source;
-
- if (source.kind == InteractionSourceKind.Controller && source.handedness == handedness)
- {
- if (!isDetected)
- {
- SetupController(source);
- }
-
- UpdateAxis(state);
- UpdatePose(state);
- }
- }
-
- protected virtual void InteractionManager_InteractionSourcePressed(InteractionSourcePressedEventArgs args)
- {
- InteractionSourceState state = args.state;
- InteractionSource source = state.source;
-
- if (source.kind == InteractionSourceKind.Controller && source.handedness == handedness)
- {
- UpdateButtonState(args.pressType, state);
- }
- }
-
- protected virtual void InteractionManager_InteractionSourceReleased(InteractionSourceReleasedEventArgs args)
- {
- InteractionSourceState state = args.state;
- InteractionSource source = state.source;
-
- if (source.kind == InteractionSourceKind.Controller && source.handedness == handedness)
- {
- UpdateButtonState(args.pressType, state);
- }
- }
-
- protected virtual void UpdatePose(InteractionSourceState state)
- {
- UpdateAngularVelocity(state.sourcePose);
- UpdateControllerPose(state.sourcePose);
- }
-
- // Workaround for Select Button
- // Issue: Pressed and Released event only recognize Select once and Select is pressed when selectPressedAmount==1,
- // so on press Select State is not always true and therefore not 'pressed'.
- // Updating SelectPressed in UpdateEvent of WSA.XR causes issues because the event and Unity Update are not synched
- // and therefore VRTK's polling of GetPressDown and GetPressUp might already been overwritten.
- protected virtual void UpdateSelectButton(InteractionSourceState state)
- {
- prevButtonState.SelectPressed = currentButtonState.SelectPressed;
- currentButtonState.SelectPressed = state.selectPressed;
- }
-
- protected virtual void UpdateTouchpadTouch(InteractionSourceState state)
- {
- if (state.source.supportsTouchpad)
- {
- prevButtonState.TouchpadTouched = currentButtonState.TouchpadTouched;
- currentButtonState.TouchpadTouched = state.touchpadTouched;
- }
- }
-
- protected virtual void UpdateButtonState(InteractionSourcePressType button, InteractionSourceState state)
- {
- switch (button)
- {
- case InteractionSourcePressType.Grasp:
- prevButtonState.Grasped = currentButtonState.Grasped;
- currentButtonState.Grasped = state.grasped;
- break;
- case InteractionSourcePressType.Menu:
- prevButtonState.MenuPressed = currentButtonState.MenuPressed;
- currentButtonState.MenuPressed = state.menuPressed;
- break;
- case InteractionSourcePressType.Touchpad:
- prevButtonState.TouchpadPressed = currentButtonState.TouchpadPressed;
- currentButtonState.TouchpadPressed = state.touchpadPressed;
- break;
- case InteractionSourcePressType.Thumbstick:
- prevButtonState.ThumbstickPressed = currentButtonState.ThumbstickPressed;
- currentButtonState.ThumbstickPressed = state.thumbstickPressed;
- break;
- }
-
- StartCoroutine(UpdateButtonStateAfterNextFrame(button));
- }
-
- protected virtual IEnumerator UpdateButtonStateAfterNextFrame(InteractionSourcePressType button)
- {
- yield return new WaitForEndOfFrame();
-
- switch (button)
- {
- case InteractionSourcePressType.Grasp:
- prevButtonState.Grasped = currentButtonState.Grasped;
- break;
- case InteractionSourcePressType.Menu:
- prevButtonState.MenuPressed = currentButtonState.MenuPressed;
- break;
- case InteractionSourcePressType.Touchpad:
- prevButtonState.TouchpadPressed = currentButtonState.TouchpadPressed;
- break;
- case InteractionSourcePressType.Thumbstick:
- prevButtonState.ThumbstickPressed = currentButtonState.ThumbstickPressed;
- break;
- }
- }
-
- protected virtual void UpdateControllerPose(InteractionSourcePose pose)
- {
- Quaternion newRotation;
- if (pose.TryGetRotation(out newRotation, InteractionSourceNode.Grip))
- {
- transform.localRotation = newRotation;
- }
-
- Vector3 newPosition;
- if (pose.TryGetPosition(out newPosition, InteractionSourceNode.Grip))
- {
- transform.localPosition = newPosition;
- }
- }
-
- protected virtual void UpdateAxis(InteractionSourceState state)
- {
- InteractionSource source = state.source;
-
- prevButtonState.SelectPressedAmount = currentButtonState.SelectPressedAmount;
- currentButtonState.SelectPressedAmount = state.selectPressedAmount;
-
- UpdateHairTrigger();
-
- if (source.supportsTouchpad)
- {
- currentButtonState.TouchpadPosition = state.touchpadPosition;
- }
-
- if (source.supportsThumbstick)
- {
- currentButtonState.ThumbstickPosition = state.thumbstickPosition;
- }
- }
-
- protected virtual void UpdateAngularVelocity(InteractionSourcePose pose)
- {
- Vector3 newAngularVelocity;
- if (pose.TryGetAngularVelocity(out newAngularVelocity))
- {
- angularVelocity = newAngularVelocity;
- }
- }
-
- protected virtual void UpdateHairTrigger()
- {
- hairTriggerPrevState = hairTriggerState;
- float value = currentButtonState.SelectPressedAmount;
-
- if (hairTriggerState)
- {
- if (value < hairTriggerLimit - hairTriggerDelta || value <= 0.0f)
- hairTriggerState = false;
- }
- else
- {
- if (value > hairTriggerLimit + hairTriggerDelta || value >= 1.0f)
- hairTriggerState = true;
- }
-
- hairTriggerLimit = hairTriggerState ? Mathf.Max(hairTriggerLimit, value) : Mathf.Min(hairTriggerLimit, value);
- }
- #endif
- }
- }
|