using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
using UnityEngine.XR.Interaction.Toolkit.UI;
using UnityEngine.EventSystems;
namespace Ximmerse.XR.InputSystems.GazeAndGestureInteraction
{
///
/// Eye reticle - 注视点交互射线控制器。
/// 需要场景中存在 XRUIInputModule 组件。
///
[DisallowMultipleComponent]
public class EyeReticle : XRRayInteractor
{
public class InteractingObjectDescription
{
public GameObject target;
public bool isUI;
}
///
/// If true, eye reticle cusor texture is not displayed when interacting nothing.
///
public bool DisplayEyeReticleCursorWhenIdle = true;
/////
///// The default reticle cursor texture.
/////
//public Texture2D defaultReticleTexture;
/////
///// The reticle cursor texture when eye reticle hover interactable objects.
/////
//public Texture2D hoverReticleTexture;
/////
///// The reticle cursor texture when eye reticle select interactable object.
/////
//public Texture2D selectStateReticleTexture;
XRUIInputModule m_CurrentXRInputModule;
public enum EyeReticleTransformMode : byte
{
LockToHead = 0,
LockToTarget,
}
///
/// The current transform mode of the eye reticle object.
///
public EyeReticleTransformMode TransformMode
{
get; private set;
}
///
/// 当前 raycast hovering 目标对象
///
public InteractingObjectDescription CurrentHoveringTarget
{
get; private set;
}
///
/// 当前交互中的目标对象
///
public InteractingObjectDescription CurrentInteractingTarget
{
get; private set;
}
private GameObject target;
//public GameObject plam;
Vector3 targetaxis;
private bool _select = false;
float defaultRaycastingDistance = 0;
protected override void Awake()
{
base.Awake();
CurrentHoveringTarget = new InteractingObjectDescription();
CurrentInteractingTarget = new InteractingObjectDescription();
defaultRaycastingDistance = this.maxRaycastDistance;
}
protected override void OnEnable()
{
base.OnEnable();
if (!m_CurrentXRInputModule)
{
m_CurrentXRInputModule = FindObjectOfType();
}
//UI:
if (m_CurrentXRInputModule)
{
m_CurrentXRInputModule.pointerEnter += onXRUIInputPointerEnter;
m_CurrentXRInputModule.pointerExit += onXRUIInputPointerExit;
m_CurrentXRInputModule.pointerDown += onXRUIInputPointerDown;
m_CurrentXRInputModule.pointerUp += onXRUIInputPointerUp;
}
//3D object:
XimmerseXR.DisplayReticle = this.DisplayEyeReticleCursorWhenIdle;
this.hoverEntered.AddListener(OnFirstHoverEntered);
this.hoverExited.AddListener(OnLastHoverExited);
this.selectEntered.AddListener(OnFirstSelectEntered);
this.selectExited.AddListener(OnLastSelectExited);
}
protected override void OnDisable()
{
base.OnDisable();
//UI:
if (m_CurrentXRInputModule)
{
m_CurrentXRInputModule.pointerEnter -= onXRUIInputPointerEnter;
m_CurrentXRInputModule.pointerExit -= onXRUIInputPointerExit;
m_CurrentXRInputModule.pointerDown -= onXRUIInputPointerDown;
m_CurrentXRInputModule.pointerUp -= onXRUIInputPointerUp;
}
//3D object:
this.hoverEntered.RemoveListener(OnFirstHoverEntered);
this.hoverExited.RemoveListener(OnLastHoverExited);
this.selectEntered.RemoveListener(OnFirstSelectEntered);
this.selectExited.RemoveListener(OnLastSelectExited);
}
#region Pointer Enter/Exit (UI), Hover Enter/Exit(3D Object)
private void onXRUIInputPointerEnter(GameObject targetGameObject, PointerEventData pointerEvent)
{
Component interactionComponent = null;
if (pointerEvent is TrackedDeviceEventData)
{
TrackedDeviceEventData tracEvntDta = pointerEvent as TrackedDeviceEventData;
interactionComponent = tracEvntDta.interactor as Component;
}
if (ReferenceEquals(this, interactionComponent))
{
OnEyeRayEnterInternal(targetGameObject, true); //This event called when with UI object
}
// Debug.LogFormat("Raycaster: {0} enter: {1}", interactionComponent ? interactionComponent.name : "", targetGameObject.name);
}
private void onXRUIInputPointerExit(GameObject targetGameObject, PointerEventData pointerEvent)
{
Component interactionComponent = null;
if (pointerEvent is TrackedDeviceEventData)
{
TrackedDeviceEventData tracEvntDta = pointerEvent as TrackedDeviceEventData;
interactionComponent = tracEvntDta.interactor as Component;
}
if (ReferenceEquals(this, interactionComponent))
{
OnEyeRayExitInternal(targetGameObject, true); //This event called when with UI object
}
// Debug.LogFormat("Raycaster: {0} exit: {1}", interactionComponent ? interactionComponent.name : "", targetGameObject);
}
///
/// Hover enter : 显示reticle texture,示意此物体可以交互.
/// 此方法在进入3D object的时候回调。等同于 UI 对象的 Pointer Enter
///
///
protected virtual void OnFirstHoverEntered(HoverEnterEventArgs args)
{
OnEyeRayEnterInternal(args.interactableObject.transform.gameObject, false); //This event called when with 3D object
// Debug.LogFormat(args.interactorObject.transform, "On First Hover Enter: {0}", args.interactorObject.transform.name);
}
///
/// Hover exit : hide / switch reticle texture,示意已经离开交互区间
/// 此方法在离开 3D object的时候回调。等同于 UI 对象的 Pointer Exit
///
///
protected virtual void OnLastHoverExited(HoverExitEventArgs args)
{
OnEyeRayExitInternal(args.interactableObject.transform.gameObject, false);
// Debug.LogFormat(args.interactorObject.transform, "On Last Hover Enter: {0}", args.interactorObject.transform.name);
}
private void OnEyeRayEnterInternal(GameObject target, bool isUI)
{
this.CurrentHoveringTarget.target = target;
this.CurrentHoveringTarget.isUI = isUI;
}
private void OnEyeRayExitInternal(GameObject target, bool isUI)
{
this.CurrentHoveringTarget.target = null;
this.CurrentHoveringTarget.isUI = isUI;
}
#endregion
#region Pointer Down/Up
///
/// On GUI pointer down
///
///
///
private void onXRUIInputPointerDown(GameObject targetGameObject, PointerEventData pointerEvent)
{
_select = true;
Component interactionComponent = null;
if (pointerEvent is TrackedDeviceEventData)
{
TrackedDeviceEventData tracEvntDta = pointerEvent as TrackedDeviceEventData;
interactionComponent = tracEvntDta.interactor as Component;
}
if (ReferenceEquals(this, interactionComponent))
{
OnEyeReticlePointerDown(targetGameObject, true); //This event called when with UI object
}
}
///
/// On GUI pointer up
///
///
///
private void onXRUIInputPointerUp(GameObject targetGameObject, PointerEventData pointerEvent)
{
_select = false;
Component interactionComponent = null;
if (pointerEvent is TrackedDeviceEventData)
{
TrackedDeviceEventData tracEvntDta = pointerEvent as TrackedDeviceEventData;
interactionComponent = tracEvntDta.interactor as Component;
}
if (ReferenceEquals(this, interactionComponent))
{
OnEyeReticlePointerUp(targetGameObject, true); //This event called when with UI object
}
}
protected void OnFirstSelectEntered(SelectEnterEventArgs args)
{
Debug.Log("OnFirstSelectEntered");
OnEyeReticlePointerDown(args.interactorObject.transform.gameObject, false);
Debug.LogFormat(args.interactorObject.transform, "On First Select Enter: {0}", args.interactorObject.transform.name);
}
protected void OnLastSelectExited(SelectExitEventArgs args)
{
OnEyeReticlePointerUp(args.interactorObject.transform.gameObject, false);
Debug.LogFormat(args.interactorObject.transform, "On Last Select Exit: {0}", args.interactorObject.transform.name);
}
bool isselect = true;
protected override void OnSelectEntering(SelectEnterEventArgs args)
{
_select = true;
base.OnSelectEntering(args);
}
protected override void OnSelectExited(SelectExitEventArgs args)
{
_select = false;
base.OnSelectExited(args);
}
private bool _hover;
protected override void OnHoverEntering(HoverEnterEventArgs args)
{
base.OnHoverEntering(args);
}
protected override void OnHoverExiting(HoverExitEventArgs args)
{
base.OnHoverExiting(args);
}
private void OnEyeReticlePointerDown(GameObject target, bool isUI)
{
_select = true;
if (target && isUI)
{
this.CurrentInteractingTarget.target = target;
this.CurrentInteractingTarget.isUI = isUI;
if (isUI)
{
//SetTransformMode(EyeReticleTransformMode.LockToTarget);
}
Debug.LogFormat("On Eye Reticle Pointer down at UI :{0}", target);
}
}
private void OnEyeReticlePointerUp(GameObject target, bool isUI)
{
_select = false;
this.CurrentInteractingTarget.target = null;
}
#endregion
//internal void SetTransformMode(EyeReticleTransformMode mode)
//{
// this.TransformMode = mode;
// switch (mode)
// {
// case EyeReticleTransformMode.LockToHead:
// //anchor to head transform:
// transform.SetParent(Camera.main.transform, true);
// transform.localPosition = Vector3.zero;
// transform.localRotation = Quaternion.identity;
// Debug.LogFormat("EyeReticle : lock to head !");
// break;
// case EyeReticleTransformMode.LockToTarget:
// var targetTransform = CurrentInteractingTarget.target.transform;
// if (targetTransform)
// {
// transform.position = targetTransform.position + -targetTransform.forward;
// transform.forward = targetTransform.forward;
// transform.SetParent(targetTransform, true);
// Debug.LogFormat("EyeReticle : lock to target UI !");
// }
// else
// {
// //unsupport
// }
// break;
// }
//}
private void LateUpdate()
{
var currentHandGestureTrackingState = GazeAndHandInteractionSystem.instance.TrackingState;
//无手势数据的时候,清空交互对象引用:
if (!currentHandGestureTrackingState.IsTracking || CurrentInteractingTarget.target)
{
CurrentInteractingTarget.target = null;
}
if (HandTracking.HandTrackingInfo.IsTracking)
{
if (_select)
{
SelectState();
}
else if (this.CurrentHoveringTarget.target)
{
HoverState();
}
else
{
TrackingState();
}
}
else
{
if (this.CurrentHoveringTarget.target)
{
CursorManager.Instance.HideCursor();
CursorManager.Instance.NormalReticle();
}
else
{
NormalState();
}
}
XimmerseXR.DisplayReticle = true;
}
#region cursorstate
private void TrackingState()
{
CursorManager.Instance.TrackingCursor();
}
private void NormalState()
{
CursorManager.Instance.NormalCursor();
//CursorManager.Instance.HideReticle();
}
private void SelectState()
{
CursorManager.Instance.HideCursor();
CursorManager.Instance.HideReticle();
}
private void HoverState()
{
CursorManager.Instance.HideCursor();
CursorManager.Instance.TrackingReticle();
}
#endregion
}
}