ControllerTracker.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. using System.Numerics;
  2. /****************************************************************************
  3. * Copyright 2019 Nreal Techonology Limited. All rights reserved.
  4. *
  5. * This file is part of NRSDK.
  6. *
  7. * https://www.nreal.ai/
  8. *
  9. *****************************************************************************/
  10. namespace NRKernal
  11. {
  12. using System.Collections;
  13. using System.Collections.Generic;
  14. using UnityEngine;
  15. /// <summary> A controller tracker. </summary>
  16. public class ControllerTracker : MonoBehaviour
  17. {
  18. /// <summary> The default hand enum. </summary>
  19. public ControllerHandEnum defaultHandEnum;
  20. /// <summary> The raycaster. </summary>
  21. public NRPointerRaycaster raycaster;
  22. /// <summary> The model anchor. </summary>
  23. public Transform modelAnchor;
  24. /// <summary> True if is enabled, false if not. </summary>
  25. private bool m_IsEnabled;
  26. /// <summary> True if is 6dof, false if not. </summary>
  27. private bool m_Is6dof;
  28. /// <summary> The default local offset. </summary>
  29. private Vector3 m_DefaultLocalOffset;
  30. /// <summary> Cache world matrix. </summary>
  31. private Matrix4x4 m_CachedWorldMatrix = Matrix4x4.identity;
  32. /// <summary> Gets the camera center. </summary>
  33. /// <value> The camera center. </value>
  34. private Transform CameraCenter
  35. {
  36. get
  37. {
  38. return NRInput.CameraCenter;
  39. }
  40. }
  41. /// <summary> Awakes this object. </summary>
  42. private void Awake()
  43. {
  44. m_DefaultLocalOffset = transform.localPosition;
  45. raycaster.RelatedHand = defaultHandEnum;
  46. }
  47. /// <summary> Executes the 'enable' action. </summary>
  48. private void OnEnable()
  49. {
  50. NRInput.OnControllerRecentering += OnRecentering;
  51. NRInput.OnControllerStatesUpdated += OnControllerStatesUpdated;
  52. NRHMDPoseTracker.OnWorldPoseReset += OnWorldPoseReset;
  53. }
  54. /// <summary> Executes the 'disable' action. </summary>
  55. private void OnDisable()
  56. {
  57. NRInput.OnControllerRecentering -= OnRecentering;
  58. NRInput.OnControllerStatesUpdated -= OnControllerStatesUpdated;
  59. NRHMDPoseTracker.OnWorldPoseReset -= OnWorldPoseReset;
  60. }
  61. private void Start()
  62. {
  63. m_Is6dof = NRInput.GetControllerAvailableFeature(ControllerAvailableFeature.CONTROLLER_AVAILABLE_FEATURE_POSITION)
  64. && NRInput.GetControllerAvailableFeature(ControllerAvailableFeature.CONTROLLER_AVAILABLE_FEATURE_ROTATION);
  65. }
  66. /// <summary> Executes the 'controller states updated' action. </summary>
  67. private void OnControllerStatesUpdated()
  68. {
  69. UpdateTracker();
  70. }
  71. /// <summary> Updates the tracker. </summary>
  72. private void UpdateTracker()
  73. {
  74. if (CameraCenter == null)
  75. return;
  76. m_IsEnabled = NRInput.CheckControllerAvailable(defaultHandEnum) && !NRInput.Hands.IsRunning;
  77. raycaster.gameObject.SetActive(m_IsEnabled && NRInput.RaycastersActive && NRInput.RaycastMode == RaycastModeEnum.Laser);
  78. modelAnchor.gameObject.SetActive(m_IsEnabled);
  79. if (m_IsEnabled)
  80. {
  81. TrackPose();
  82. }
  83. }
  84. /// <summary> Track pose. </summary>
  85. private void TrackPose()
  86. {
  87. Pose poseInAPIWorld = new Pose(NRInput.GetPosition(defaultHandEnum), NRInput.GetRotation(defaultHandEnum));
  88. Pose pose = ApplyWorldMatrix(poseInAPIWorld);
  89. transform.position = m_Is6dof ? pose.position : CameraCenter.TransformPoint(m_DefaultLocalOffset);
  90. transform.rotation = pose.rotation;
  91. }
  92. /// <summary> Apply world transform. </summary>
  93. private Pose ApplyWorldMatrix(Pose pose)
  94. {
  95. var objectMatrix = ConversionUtility.GetTMatrix(pose.position, pose.rotation);
  96. var object_in_world = m_CachedWorldMatrix * objectMatrix;
  97. return new Pose(ConversionUtility.GetPositionFromTMatrix(object_in_world),
  98. ConversionUtility.GetRotationFromTMatrix(object_in_world));
  99. }
  100. /// <summary>
  101. /// Recenter the φ coordinate of laser to make sure the laser is pointing to forward of camera. But the θ coordinate of the laser keeps in sync with controller device.
  102. /// </summary>
  103. private void OnRecentering()
  104. {
  105. Plane horizontal_plane = new Plane(Vector3.up, Vector3.zero);
  106. Vector3 horizontalFoward = horizontal_plane.ClosestPointOnPlane(CameraCenter.forward).normalized;
  107. var horizontalRotEuler = Quaternion.LookRotation(horizontalFoward, Vector3.up).eulerAngles;
  108. // var worldMatrix = NRSessionManager.Instance.NRHMDPoseTracker.GetWorldOffsetMatrixFromNative();
  109. // var worldRot = ConversionUtility.GetRotationFromTMatrix(worldMatrix);
  110. // Quaternion correctRot = worldRot * Quaternion.Euler(0, horizontalRotEuler.y, 0);
  111. var verticalDegree = NRSessionManager.Instance.NRHMDPoseTracker.GetCachedWorldPitch();
  112. // Use the yaw of camera and the pitch of the world offset from native.
  113. Quaternion correctRot = Quaternion.Euler(verticalDegree, 0, 0) * Quaternion.Euler(0, horizontalRotEuler.y, 0);
  114. // For 6dof controller, the position should be cached as pose of controller device is reset.
  115. Vector3 position = m_Is6dof ? transform.position : Vector3.zero;
  116. m_CachedWorldMatrix = ConversionUtility.GetTMatrix(position, correctRot);
  117. NRDebugger.Info("[ControllerTracker] OnRecentering : forward={0}, horRot={1}, vertRot={2}, correctRot={3}",
  118. CameraCenter.forward.ToString("F4"), horizontalRotEuler.ToString("F4"), verticalDegree.ToString("F4"), correctRot.eulerAngles.ToString("F4"));
  119. }
  120. private void OnWorldPoseReset()
  121. {
  122. NRInput.RecenterController();
  123. }
  124. }
  125. }