/**************************************************************************** * Copyright 2019 Nreal Techonology Limited. All rights reserved. * * This file is part of NRSDK. * * https://www.nreal.ai/ * *****************************************************************************/ namespace NRKernal { using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; /// A nr pointer raycaster. [DisallowMultipleComponent] public class NRPointerRaycaster : EventCameraRaycaster { /// Values that represent mask type enums. public enum MaskTypeEnum { /// An enum constant representing the inclusive option. Inclusive, /// An enum constant representing the exclusive option. Exclusive } /// The hits. private static readonly RaycastHit[] hits = new RaycastHit[64]; /// Type of the mask. public MaskTypeEnum maskType = MaskTypeEnum.Exclusive; /// The mask. public LayerMask mask; /// Gets the raycast mask. /// The raycast mask. public int raycastMask { get { return maskType == MaskTypeEnum.Inclusive ? (int)mask : ~mask; } } /// True to show, false to hide the debug ray. public bool showDebugRay = true; /// True to enable, false to disable the physics raycast. public bool enablePhysicsRaycast = true; /// True to enable, false to disable the graphic raycast. public bool enableGraphicRaycast = true; /// List of button event data. protected readonly List buttonEventDataList = new List(); /// The sorted raycast results. protected readonly List sortedRaycastResults = new List(); /// The break points. protected readonly List breakPoints = new List(); /// Temporary raycast results. private readonly List temporaryRaycastResults = new List(); /// The related hand. private ControllerHandEnum m_RelatedHand; /// Gets or sets the related hand. /// The related hand. public ControllerHandEnum RelatedHand { get { return NRInput.RaycastMode == RaycastModeEnum.Gaze ? NRInput.DomainHand : m_RelatedHand; } internal set { m_RelatedHand = value; } } /// Gets the break points. /// The break points. public List BreakPoints { get { return breakPoints; } } /// Gets information describing the hover event. /// Information describing the hover event. public NRPointerEventData HoverEventData { get { return buttonEventDataList.Count > 0 ? buttonEventDataList[0] : null; } } /// Gets a list of button event data. /// A list of button event data. private ReadOnlyCollection readonlyButtonEventDataList; public ReadOnlyCollection ButtonEventDataList { get { if (readonlyButtonEventDataList == null) readonlyButtonEventDataList = buttonEventDataList.AsReadOnly(); return readonlyButtonEventDataList; } } /// See MonoBehaviour.Start. protected override void Start() { base.Start(); buttonEventDataList.Add(new NRPointerEventData(this, EventSystem.current)); } /// called by StandaloneInputModule, not supported. /// Information describing the event. /// List of result appends. public override void Raycast(PointerEventData eventData, List resultAppendList) { } /// Raycasts. public virtual void Raycast() { sortedRaycastResults.Clear(); breakPoints.Clear(); var zScale = transform.lossyScale.z; var amountDistance = (FarDistance - NearDistance) * zScale; if (!gameObject.activeInHierarchy) { amountDistance = 0.0001f; } var origin = transform.TransformPoint(0f, 0f, NearDistance); breakPoints.Add(origin); Vector3 direction; float distance; Ray ray; RaycastResult firstHit = default(RaycastResult); direction = transform.forward; distance = amountDistance; ray = new Ray(origin, direction); eventCamera.farClipPlane = eventCamera.nearClipPlane + distance; eventCamera.transform.position = ray.origin - (ray.direction * eventCamera.nearClipPlane); eventCamera.transform.rotation = Quaternion.LookRotation(ray.direction, transform.up); Raycast(ray, distance, sortedRaycastResults); firstHit = FirstRaycastResult(); breakPoints.Add(firstHit.isValid ? firstHit.worldPosition : ray.GetPoint(distance)); #if UNITY_EDITOR if (showDebugRay) { Debug.DrawLine(breakPoints[0], breakPoints[1], firstHit.isValid ? Color.green : Color.red); } #endif } /// Gets raycaster result comparer. /// The raycaster result comparer. protected virtual Comparison GetRaycasterResultComparer() { return NRInputModule.defaultRaycastComparer; } /// /// override OnEnable & OnDisable on purpose so that this BaseRaycaster won't be registered into /// RaycasterManager. protected override void OnEnable() { //base.OnEnable(); NRInputModule.AddRaycaster(this); } /// See MonoBehaviour.OnDisable. protected override void OnDisable() { //base.OnDisable(); NRInputModule.RemoveRaycaster(this); } /// Gets scroll delta. /// The scroll delta. public virtual Vector2 GetScrollDelta() { return Vector2.zero; } /// First raycast result. /// A RaycastResult. public RaycastResult FirstRaycastResult() { for (int i = 0, imax = sortedRaycastResults.Count; i < imax; ++i) { if (!sortedRaycastResults[i].isValid) continue; return sortedRaycastResults[i]; } return default(RaycastResult); } /// Raycasts. /// The ray. /// The distance. /// The raycast results. public void Raycast(Ray ray, float distance, List raycastResults) { temporaryRaycastResults.Clear(); if (enablePhysicsRaycast) { PhysicsRaycast(ray, distance, temporaryRaycastResults); } if (enableGraphicRaycast) { var tempCanvases = CanvasTargetCollector.GetCanvases(); for (int i = tempCanvases.Count - 1; i >= 0; --i) { var target = tempCanvases[i]; if (target == null || !target.enabled) continue; GraphicRaycast(target, target.ignoreReversedGraphics, ray, distance, this, temporaryRaycastResults); } } var comparer = GetRaycasterResultComparer(); if (comparer != null) { temporaryRaycastResults.Sort(comparer); } for (int i = 0, imax = temporaryRaycastResults.Count; i < imax; ++i) { raycastResults.Add(temporaryRaycastResults[i]); } } /// Physics raycast. /// The ray. /// The distance. /// The raycast results. public virtual void PhysicsRaycast(Ray ray, float distance, List raycastResults) { var hitCount = Physics.RaycastNonAlloc(ray, hits, distance, raycastMask); for (int i = 0; i < hitCount; ++i) { raycastResults.Add(new RaycastResult { gameObject = hits[i].collider.gameObject, module = this, distance = hits[i].distance, worldPosition = hits[i].point, worldNormal = hits[i].normal, screenPosition = NRInputModule.ScreenCenterPoint, index = raycastResults.Count, sortingLayer = 0, sortingOrder = 0 }); } } /// Graphic raycast. /// The canvas. /// True to ignore reversed graphics. /// The ray. /// The distance. /// The raycaster. /// The raycast results. public virtual void GraphicRaycast(ICanvasRaycastTarget raycastTarget, bool ignoreReversedGraphics, Ray ray, float distance, NRPointerRaycaster raycaster, List raycastResults) { if (raycastTarget.canvas == null) return; var eventCamera = raycaster.eventCamera; var screenCenterPoint = NRInputModule.ScreenCenterPoint; raycastTarget.GraphicRaycast(ignoreReversedGraphics, ray, distance, screenCenterPoint, raycaster, raycastResults); } } }