RayInteractor.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. using System.Collections.Generic;
  2. using Rokid.UXR.Utility;
  3. using UnityEngine;
  4. namespace Rokid.UXR.Interaction
  5. {
  6. public class RayInteractor : PointerInteractor<RayInteractor, RayInteractable>, IHeadHandDriver
  7. {
  8. [SerializeField]
  9. private HandType hand = HandType.None;
  10. [SerializeField, Interface(typeof(ISelector))]
  11. private MonoBehaviour _selector;
  12. [SerializeField]
  13. private Transform _rayOrigin;
  14. [SerializeField]
  15. private float _maxRayLength = 5f;
  16. [SerializeField]
  17. private float _noHoverCursorDistance = 5f;
  18. [SerializeField]
  19. [Tooltip("(Meters, World) The threshold below which distances to a surface " +
  20. "are treated as equal for the purposes of ranking.")]
  21. private float _equalDistanceThreshold = 0.001f;
  22. private RayCandidateProperties _rayCandidateProperties = null;
  23. private IMovement _movement;
  24. private SurfaceHit _movedHit;
  25. private Pose _movementHitDelta = Pose.identity;
  26. public Vector3 Origin { get; protected set; }
  27. public Quaternion Rotation { get; protected set; }
  28. public Vector3 Forward { get; protected set; }
  29. public Vector3 End { get; set; }
  30. public Transform GetRayOriginTsf()
  31. {
  32. return _rayOrigin;
  33. }
  34. public float NoHoverCursorDistance
  35. {
  36. get
  37. {
  38. return _noHoverCursorDistance;
  39. }
  40. set
  41. {
  42. _noHoverCursorDistance = value;
  43. }
  44. }
  45. public float MaxRayLength
  46. {
  47. get
  48. {
  49. return _maxRayLength;
  50. }
  51. set
  52. {
  53. _maxRayLength = value;
  54. }
  55. }
  56. private float _ProjectNoHoverCursorDistance;
  57. public SurfaceHit? CollisionInfo { get; protected set; }
  58. public Ray Ray { get; protected set; }
  59. public static List<RayInteractor> RayInteractors = new List<RayInteractor>();
  60. protected override void Awake()
  61. {
  62. base.Awake();
  63. Selector = _selector as ISelector;
  64. }
  65. protected override void Start()
  66. {
  67. base.Start();
  68. RayInteractors.Add(this);
  69. }
  70. protected override void OnDestroy()
  71. {
  72. base.OnDestroy();
  73. RayInteractors.Remove(this);
  74. }
  75. public static Ray GetRayByIdentifier(int identity)
  76. {
  77. for (int i = 0; i < RayInteractors.Count; i++)
  78. {
  79. if (RayInteractors[i].realId == identity)
  80. {
  81. return RayInteractors[i].Ray;
  82. }
  83. }
  84. return default(Ray);
  85. }
  86. public static HandType GetHandTypeByIdentifier(int identity)
  87. {
  88. for (int i = 0; i < RayInteractors.Count; i++)
  89. {
  90. if (RayInteractors[i].realId == identity)
  91. {
  92. return RayInteractors[i].hand;
  93. }
  94. }
  95. return HandType.None;
  96. }
  97. public static RayInteractor GetRayIntertorByIdentifier(int identity)
  98. {
  99. for (int i = 0; i < RayInteractors.Count; i++)
  100. {
  101. if (RayInteractors[i].realId == identity)
  102. {
  103. return RayInteractors[i];
  104. }
  105. }
  106. return null;
  107. }
  108. protected override void DoPreprocess()
  109. {
  110. Origin = _rayOrigin.transform.position;
  111. Rotation = _rayOrigin.transform.rotation;
  112. Forward = Rotation * Vector3.forward;
  113. Ray = new Ray(Origin, Forward);
  114. }
  115. public class RayCandidateProperties : ICandidatePosition
  116. {
  117. public RayInteractable ClosestInteractable { get; }
  118. public Vector3 CandidatePosition { get; }
  119. public RayCandidateProperties(RayInteractable closestInteractable, Vector3 candidatePosition)
  120. {
  121. ClosestInteractable = closestInteractable;
  122. CandidatePosition = candidatePosition;
  123. }
  124. }
  125. public override object CandidateProperties => _rayCandidateProperties;
  126. protected override RayInteractable ComputeCandidate()
  127. {
  128. CollisionInfo = null;
  129. RayInteractable closestInteractable = null;
  130. float closestDist = float.MaxValue;
  131. Vector3 candidatePosition = Vector3.zero;
  132. var interactables = RayInteractable.Registry.List(this);
  133. //使用射线检测关键的碰撞物体
  134. foreach (RayInteractable interactable in interactables)
  135. {
  136. if (interactable.Raycast(Ray, out SurfaceHit hit, MaxRayLength, false))
  137. {
  138. bool equal = Mathf.Abs(hit.Distance - closestDist) < _equalDistanceThreshold;
  139. if ((!equal && hit.Distance < closestDist) ||
  140. (equal && interactable.TiebreakerScore > closestInteractable.TiebreakerScore))
  141. {
  142. closestDist = hit.Distance;
  143. closestInteractable = interactable;
  144. CollisionInfo = hit;
  145. candidatePosition = hit.Point;
  146. }
  147. }
  148. }
  149. _ProjectNoHoverCursorDistance = NoHoverCursorDistance;
  150. if (closestInteractable == null && MainCameraCache.mainCamera != null)
  151. {
  152. Vector3 ProjectDir = Vector3.ProjectOnPlane(MainCameraCache.mainCamera.transform.forward, Vector3.up).normalized;
  153. float AngleY = Vector3.SignedAngle(MainCameraCache.mainCamera.transform.forward.normalized, ProjectDir, Vector3.up) * Mathf.Deg2Rad;
  154. _ProjectNoHoverCursorDistance = NoHoverCursorDistance / Mathf.Cos(AngleY);
  155. }
  156. float rayDist = (closestInteractable != null ? closestDist : _ProjectNoHoverCursorDistance);
  157. End = Origin + rayDist * Forward;
  158. _rayCandidateProperties = new RayCandidateProperties(closestInteractable, candidatePosition);
  159. return closestInteractable;
  160. }
  161. protected override void InteractableSelected(RayInteractable interactable)
  162. {
  163. if (interactable != null)
  164. {
  165. _movedHit = CollisionInfo.Value;
  166. Pose hitPose = new Pose(_movedHit.Point, Quaternion.LookRotation(_movedHit.Normal));
  167. Pose backHitPose = new Pose(_movedHit.Point, Quaternion.LookRotation(-_movedHit.Normal));
  168. _movement = interactable.GenerateMovement(_rayOrigin.GetPose(), backHitPose);
  169. if (_movement != null)
  170. {
  171. _movementHitDelta = PoseUtils.Delta(_movement.Pose, hitPose);
  172. }
  173. }
  174. base.InteractableSelected(interactable);
  175. }
  176. protected override void InteractableUnselected(RayInteractable interactable)
  177. {
  178. if (_movement != null)
  179. {
  180. _movement.StopAndSetPose(_movement.Pose);
  181. }
  182. base.InteractableUnselected(interactable);
  183. _movement = null;
  184. }
  185. protected override void DoSelectUpdate()
  186. {
  187. RayInteractable interactable = _selectedInteractable;
  188. if (_movement != null)
  189. {
  190. _movement.UpdateTarget(_rayOrigin.GetPose());
  191. _movement.Tick();
  192. Pose hitPoint = PoseUtils.Multiply(_movement.Pose, _movementHitDelta);
  193. _movedHit.Point = hitPoint.position;
  194. _movedHit.Normal = hitPoint.forward;
  195. CollisionInfo = _movedHit;
  196. End = _movedHit.Point;
  197. return;
  198. }
  199. CollisionInfo = null;
  200. if (interactable != null &&
  201. interactable.Raycast(Ray, out SurfaceHit hit, MaxRayLength, true))
  202. {
  203. End = hit.Point;
  204. CollisionInfo = hit;
  205. }
  206. else
  207. {
  208. // End = Origin + MaxRayLength * Forward;
  209. End = Origin + _ProjectNoHoverCursorDistance * Forward;
  210. }
  211. }
  212. protected override Pose ComputePointerPose()
  213. {
  214. if (_movement != null)
  215. {
  216. return _movement.Pose;
  217. }
  218. if (CollisionInfo != null)
  219. {
  220. Vector3 position = CollisionInfo.Value.Point;
  221. Quaternion rotation = Quaternion.LookRotation(CollisionInfo.Value.Normal);
  222. return new Pose(position, rotation);
  223. }
  224. return new Pose(Vector3.zero, Quaternion.identity);
  225. }
  226. public void OnChangeHoldHandType(HandType hand)
  227. {
  228. this.hand = hand;
  229. }
  230. public void OnHandPress(HandType hand)
  231. {
  232. }
  233. public void OnHandRelease()
  234. {
  235. }
  236. public void OnBeforeChangeHoldHandType(HandType hand)
  237. {
  238. }
  239. }
  240. }