NRHMDPoseTracker.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. /****************************************************************************
  2. * Copyright 2019 Nreal Techonology Limited. All rights reserved.
  3. *
  4. * This file is part of NRSDK.
  5. *
  6. * https://www.nreal.ai/
  7. *
  8. *****************************************************************************/
  9. namespace NRKernal
  10. {
  11. using UnityEngine;
  12. using System.Collections;
  13. using System;
  14. using System.Collections.Generic;
  15. #if USING_XR_SDK
  16. using UnityEngine.XR;
  17. #endif
  18. /// <summary> Hmd pose tracker event. </summary>
  19. public delegate void HMDPoseTrackerEvent();
  20. public delegate void HMDPoseTrackerModeChangeEvent(NRHMDPoseTracker.TrackingType origin, NRHMDPoseTracker.TrackingType target);
  21. public delegate void OnTrackingModeChanged(NRHMDPoseTracker.TrackingModeChangedResult result);
  22. public delegate void OnWorldPoseResetEvent();
  23. /// <summary>
  24. /// Interface of external slam provider.
  25. /// </summary>
  26. public interface IExternSlamProvider
  27. {
  28. /// <summary>
  29. /// Get head pose at the time of timeStamp
  30. /// </summary>
  31. /// <param name="timeStamp"> The specified time. </param>
  32. /// <returns></returns>
  33. Pose GetHeadPoseAtTime(UInt64 timeStamp);
  34. }
  35. /// <summary>
  36. /// HMDPoseTracker update the infomations of pose tracker. This component is used to initialize
  37. /// the camera parameter, update the device posture, In addition, application can change
  38. /// TrackingType through this component. </summary>
  39. [HelpURL("https://developer.nreal.ai/develop/discover/introduction-nrsdk")]
  40. public class NRHMDPoseTracker : MonoBehaviour
  41. {
  42. /// <summary> Event queue for all listeners interested in OnHMDPoseReady events. </summary>
  43. public static event HMDPoseTrackerEvent OnHMDPoseReady;
  44. /// <summary> Event queue for all listeners interested in OnHMDLostTracking events. </summary>
  45. public static event HMDPoseTrackerEvent OnHMDLostTracking;
  46. /// <summary> Event queue for all listeners interested in OnChangeTrackingMode events. </summary>
  47. public static event HMDPoseTrackerModeChangeEvent OnChangeTrackingMode;
  48. /// <summary> Event queue for all listeners interested in OnWorldPoseReset events. </summary>
  49. public static event OnWorldPoseResetEvent OnWorldPoseReset;
  50. public struct TrackingModeChangedResult
  51. {
  52. public bool success;
  53. public TrackingType trackingType;
  54. }
  55. /// <summary> HMD tracking type. </summary>
  56. public enum TrackingType
  57. {
  58. /// <summary>
  59. /// Track the position an rotation.
  60. /// </summary>
  61. Tracking6Dof = 0,
  62. /// <summary>
  63. /// Track the rotation only.
  64. /// </summary>
  65. Tracking3Dof = 1,
  66. /// <summary>
  67. /// Track nothing.
  68. /// </summary>
  69. Tracking0Dof = 2,
  70. /// <summary>
  71. /// Track nothing. Use rotation to make tracking smoothly.
  72. /// </summary>
  73. Tracking0DofStable = 3
  74. }
  75. /// <summary> Type of the tracking. </summary>
  76. [SerializeField]
  77. private TrackingType m_TrackingType = TrackingType.Tracking6Dof;
  78. /// <summary> Gets the tracking mode. </summary>
  79. /// <value> The tracking mode. </value>
  80. public TrackingType TrackingMode
  81. {
  82. get
  83. {
  84. return m_TrackingType;
  85. }
  86. }
  87. /// <summary> Auto adapt trackingType while not supported. </summary>
  88. public bool TrackingModeAutoAdapt = true;
  89. /// <summary> Use relative coordinates or not. </summary>
  90. public bool UseRelative = false;
  91. /// <summary> The last reason. </summary>
  92. private LostTrackingReason m_LastReason = LostTrackingReason.INITIALIZING;
  93. private IExternSlamProvider m_externSlamProvider = null;
  94. /// <summary> The left camera. </summary>
  95. public Camera leftCamera;
  96. /// <summary> The center camera. </summary>
  97. public Camera centerCamera;
  98. public Transform centerAnchor;
  99. Pose HeadRotFromCenter = Pose.identity;
  100. /// <summary> The right camera. </summary>
  101. public Camera rightCamera;
  102. private bool m_ModeChangeLock = false;
  103. public bool IsTrackModeChanging
  104. {
  105. get { return m_ModeChangeLock; }
  106. }
  107. #if USING_XR_SDK
  108. static internal List<XRNodeState> nodeStates = new List<XRNodeState>();
  109. static internal void GetNodePoseData(XRNode node, out Pose resultPose)
  110. {
  111. InputTracking.GetNodeStates(nodeStates);
  112. for (int i = 0; i < nodeStates.Count; i++)
  113. {
  114. var nodeState = nodeStates[i];
  115. if (nodeState.nodeType == node)
  116. {
  117. nodeState.TryGetPosition(out resultPose.position);
  118. nodeState.TryGetRotation(out resultPose.rotation);
  119. return;
  120. }
  121. }
  122. resultPose = Pose.identity;
  123. }
  124. #endif
  125. /// <summary> Awakes this object. </summary>
  126. void Awake()
  127. {
  128. #if UNITY_EDITOR || USING_XR_SDK
  129. if (leftCamera != null)
  130. leftCamera.enabled = false;
  131. if (rightCamera != null)
  132. rightCamera.enabled = false;
  133. centerCamera.depth = 1;
  134. centerCamera.enabled = true;
  135. #else
  136. if (leftCamera != null)
  137. leftCamera.enabled = true;
  138. if (rightCamera != null)
  139. rightCamera.enabled = true;
  140. centerCamera.enabled = false;
  141. #endif
  142. StartCoroutine(Initialize());
  143. }
  144. /// <summary> Executes the 'enable' action. </summary>
  145. void OnEnable()
  146. {
  147. #if USING_XR_SDK && !UNITY_EDITOR
  148. Application.onBeforeRender += OnUpdate;
  149. #else
  150. NRKernalUpdater.OnUpdate += OnUpdate;
  151. #endif
  152. }
  153. /// <summary> Executes the 'disable' action. </summary>
  154. void OnDisable()
  155. {
  156. #if USING_XR_SDK && !UNITY_EDITOR
  157. Application.onBeforeRender -= OnUpdate;
  158. #else
  159. NRKernalUpdater.OnUpdate -= OnUpdate;
  160. #endif
  161. }
  162. /// <summary> Executes the 'update' action. </summary>
  163. void OnUpdate()
  164. {
  165. CheckHMDPoseState();
  166. UpdatePoseByTrackingType();
  167. }
  168. /// <summary> Auto adaption for current working trackingType based on supported feature on current device. </summary>
  169. public void AutoAdaptTrackingType()
  170. {
  171. if (TrackingModeAutoAdapt)
  172. {
  173. TrackingType adjustTrackingType = AdaptTrackingType(m_TrackingType);
  174. if (adjustTrackingType != m_TrackingType)
  175. {
  176. NRDebugger.Warning("[NRHMDPoseTracker] AutoAdaptTrackingType : {0} => {1}", m_TrackingType, adjustTrackingType);
  177. m_TrackingType = adjustTrackingType;
  178. }
  179. }
  180. }
  181. /// <summary> Auto adaption for trackingType based on supported feature on current device. </summary>
  182. /// <returns> fallback trackingType. </returns>
  183. public static TrackingType AdaptTrackingType(TrackingType mode)
  184. {
  185. switch (mode)
  186. {
  187. case TrackingType.Tracking6Dof:
  188. {
  189. if (NRDevice.Subsystem.IsFeatureSupported(NRSupportedFeature.NR_FEATURE_TRACKING_6DOF))
  190. return TrackingType.Tracking6Dof;
  191. else if (NRDevice.Subsystem.IsFeatureSupported(NRSupportedFeature.NR_FEATURE_TRACKING_3DOF))
  192. return TrackingType.Tracking3Dof;
  193. else
  194. return TrackingType.Tracking0Dof;
  195. }
  196. case TrackingType.Tracking3Dof:
  197. {
  198. if (NRDevice.Subsystem.IsFeatureSupported(NRSupportedFeature.NR_FEATURE_TRACKING_3DOF))
  199. return TrackingType.Tracking3Dof;
  200. else
  201. return TrackingType.Tracking0Dof;
  202. }
  203. case TrackingType.Tracking0DofStable:
  204. {
  205. if (NRDevice.Subsystem.IsFeatureSupported(NRSupportedFeature.NR_FEATURE_TRACKING_3DOF))
  206. return TrackingType.Tracking0DofStable;
  207. else
  208. return TrackingType.Tracking0Dof;
  209. }
  210. }
  211. return mode;
  212. }
  213. /// <summary> Change mode. </summary>
  214. /// <param name="trackingtype"> The trackingtype.</param>
  215. /// <param name="OnModeChanged"> The mode changed call back and return the result.</param>
  216. private bool ChangeMode(TrackingType trackingtype, OnTrackingModeChanged OnModeChanged)
  217. {
  218. NRDebugger.Info("[NRHMDPoseTracker] Begin ChangeMode to:" + trackingtype);
  219. TrackingModeChangedResult result = new TrackingModeChangedResult();
  220. if (trackingtype == m_TrackingType || m_ModeChangeLock)
  221. {
  222. result.success = false;
  223. result.trackingType = m_TrackingType;
  224. OnModeChanged?.Invoke(result);
  225. NRDebugger.Warning("[NRHMDPoseTracker] Change tracking mode faild...");
  226. return false;
  227. }
  228. OnChangeTrackingMode?.Invoke(m_TrackingType, trackingtype);
  229. NRSessionManager.OnChangeTrackingMode?.Invoke(m_TrackingType, trackingtype);
  230. #if !UNITY_EDITOR
  231. m_ModeChangeLock = true;
  232. AsyncTaskExecuter.Instance.RunAction(() =>
  233. {
  234. result.success = NRSessionManager.Instance.NativeAPI.NativeTracking.SwitchTrackingMode((TrackingMode)trackingtype);
  235. if (result.success)
  236. {
  237. m_TrackingType = trackingtype;
  238. }
  239. result.trackingType = m_TrackingType;
  240. OnModeChanged?.Invoke(result);
  241. m_ModeChangeLock = false;
  242. NRDebugger.Info("[NRHMDPoseTracker] End ChangeMode, result:" + result.success);
  243. });
  244. #else
  245. m_TrackingType = trackingtype;
  246. result.success = true;
  247. result.trackingType = m_TrackingType;
  248. OnModeChanged?.Invoke(result);
  249. #endif
  250. return true;
  251. }
  252. private void OnApplicationPause(bool pause)
  253. {
  254. NRDebugger.Info("[NRHMDPoseTracker] OnApplicationPause : pause={0}, headPos={1}, cachedWorldMatrix={2}",
  255. pause, NRFrame.HeadPose.ToString("F2"), cachedWorldMatrix.ToString());
  256. if (pause)
  257. {
  258. this.CacheWorldMatrix();
  259. }
  260. }
  261. Pose GetCachPose()
  262. {
  263. Pose cachePose;
  264. if (UseRelative)
  265. cachePose = new Pose(transform.localPosition, transform.localRotation);
  266. else
  267. cachePose = new Pose(transform.position, transform.rotation);
  268. // remove the neck mode relative position.
  269. if (m_TrackingType != TrackingType.Tracking6Dof)
  270. {
  271. cachePose.position = ConversionUtility.GetPositionFromTMatrix(cachedWorldMatrix);
  272. }
  273. return cachePose;
  274. }
  275. /// <summary> Change to 6 degree of freedom. </summary>
  276. /// <param name="OnModeChanged"> The mode changed call back and return the result.</param>
  277. /// <param name="autoAdapt"> Auto trackingType adaption based on supported features on current device.</param>
  278. public bool ChangeTo6Dof(OnTrackingModeChanged OnModeChanged, bool autoAdapt = false)
  279. {
  280. var trackType = TrackingType.Tracking6Dof;
  281. if (autoAdapt)
  282. trackType = AdaptTrackingType(trackType);
  283. Pose cachePose = GetCachPose();
  284. return ChangeMode(trackType, (NRHMDPoseTracker.TrackingModeChangedResult result) =>
  285. {
  286. if (result.success)
  287. CacheWorldMatrix(cachePose);
  288. if (OnModeChanged != null)
  289. OnModeChanged(result);
  290. });
  291. }
  292. /// <summary> Change to 3 degree of freedom. </summary>
  293. /// <param name="OnModeChanged"> The mode changed call back and return the result.</param>
  294. /// <param name="autoAdapt"> Auto trackingType adaption based on supported features on current device.</param>
  295. public bool ChangeTo3Dof(OnTrackingModeChanged OnModeChanged, bool autoAdapt = false)
  296. {
  297. var trackType = TrackingType.Tracking3Dof;
  298. if (autoAdapt)
  299. trackType = AdaptTrackingType(trackType);
  300. Pose cachePose = GetCachPose();
  301. return ChangeMode(trackType, (NRHMDPoseTracker.TrackingModeChangedResult result) =>
  302. {
  303. if (result.success)
  304. CacheWorldMatrix(cachePose);
  305. if (OnModeChanged != null)
  306. OnModeChanged(result);
  307. });
  308. }
  309. /// <summary> Change to 0 degree of freedom. </summary>
  310. /// <param name="OnModeChanged"> The mode changed call back and return the result.</param>
  311. /// <param name="autoAdapt"> Auto trackingType adaption based on supported features on current device.</param>
  312. public bool ChangeTo0Dof(OnTrackingModeChanged OnModeChanged, bool autoAdapt = false)
  313. {
  314. var trackType = TrackingType.Tracking0Dof;
  315. if (autoAdapt)
  316. trackType = AdaptTrackingType(trackType);
  317. Pose cachePose = GetCachPose();
  318. return ChangeMode(trackType, (NRHMDPoseTracker.TrackingModeChangedResult result) =>
  319. {
  320. if (result.success)
  321. CacheWorldMatrix(cachePose);
  322. if (OnModeChanged != null)
  323. OnModeChanged(result);
  324. });
  325. }
  326. /// <summary> Change to 3 degree of freedom. </summary>
  327. /// <param name="OnModeChanged"> The mode changed call back and return the result.</param>
  328. /// <param name="autoAdapt"> Auto trackingType adaption based on supported features on current device.</param>
  329. public bool ChangeTo0DofStable(OnTrackingModeChanged OnModeChanged, bool autoAdapt = false)
  330. {
  331. var trackType = TrackingType.Tracking0DofStable;
  332. if (autoAdapt)
  333. trackType = AdaptTrackingType(trackType);
  334. Pose cachePose = GetCachPose();
  335. return ChangeMode(trackType, (NRHMDPoseTracker.TrackingModeChangedResult result) =>
  336. {
  337. if (result.success)
  338. CacheWorldMatrix(cachePose);
  339. if (OnModeChanged != null)
  340. OnModeChanged(result);
  341. });
  342. }
  343. private Matrix4x4 cachedWorldMatrix = Matrix4x4.identity;
  344. private float cachedWorldPitch = 0;
  345. /// <summary> Cache the world matrix. </summary>
  346. public void CacheWorldMatrix()
  347. {
  348. Pose cachePose = GetCachPose();
  349. CacheWorldMatrix(cachePose);
  350. NRFrame.ResetHeadPose();
  351. }
  352. public void CacheWorldMatrix(Pose pose)
  353. {
  354. NRDebugger.Info("[NRHMDPoseTracker] CacheWorldMatrix : UseRelative={0}, trackType={1}, pos={2}", UseRelative, m_TrackingType, pose.ToString("F2"));
  355. Plane horizontal_plane = new Plane(Vector3.up, Vector3.zero);
  356. Vector3 forward_use_gravity = horizontal_plane.ClosestPointOnPlane(pose.forward).normalized;
  357. Quaternion rotation_use_gravity = Quaternion.LookRotation(forward_use_gravity, Vector3.up);
  358. cachedWorldMatrix = ConversionUtility.GetTMatrix(pose.position, rotation_use_gravity);
  359. cachedWorldPitch = 0;
  360. NRDebugger.Info("CacheWorldMatrix Adjust : pos={0}, {1}, cachedWorldMatrix={2}",
  361. pose.position.ToString("F2"), rotation_use_gravity.ToString("F2"), cachedWorldMatrix.ToString());
  362. OnWorldPoseReset?.Invoke();
  363. }
  364. /// <summary>
  365. /// Reset the camera to position:(0,0,0) and yaw or pitch orientation.
  366. /// </summary>
  367. /// <param name="resetPitch">
  368. /// Whether to reset the pitch direction.
  369. /// if resetPitch is false, reset camera to rotation(x,0,z). Where x&z is the pitch&roll of the HMD device.
  370. /// if resetPitch is true, reset camera to rotation(0,0,z); Where z is the roll of the HMD device.
  371. /// </param>
  372. public void ResetWorldMatrix(bool resetPitch = false)
  373. {
  374. Pose pose;
  375. if (UseRelative)
  376. pose = new Pose(transform.localPosition, transform.localRotation);
  377. else
  378. pose = new Pose(transform.position, transform.rotation);
  379. // Get src pose which is not affected by cachedWorldMatrix
  380. Matrix4x4 cachedWorldInverse = Matrix4x4.Inverse(cachedWorldMatrix);
  381. var worldMatrix = ConversionUtility.GetTMatrix(pose.position, pose.rotation);
  382. var objectMatrix = cachedWorldInverse * worldMatrix;
  383. var srcPose = new Pose(ConversionUtility.GetPositionFromTMatrix(objectMatrix), ConversionUtility.GetRotationFromTMatrix(objectMatrix));
  384. Quaternion rotation = Quaternion.identity;
  385. if (resetPitch)
  386. {
  387. // reset on degree of yaw and pitch, so only roll of HMD is not affect.
  388. Vector3 forward = srcPose.forward;
  389. Vector3 right = Vector3.Cross(forward, Vector3.up);
  390. Vector3 up = Vector3.Cross(right, forward);
  391. rotation = Quaternion.LookRotation(forward, up);
  392. Debug.LogFormat("ResetWorldMatrix: forward={0}, right={1}, up={2}", forward.ToString("F4"), right.ToString("F4"), up.ToString("F4"));
  393. }
  394. else
  395. {
  396. // only reset on degree of yaw, so the pitch and roll of HMD is not affect.
  397. Plane horizontal_plane = new Plane(Vector3.up, Vector3.zero);
  398. Vector3 forward_use_gravity = horizontal_plane.ClosestPointOnPlane(srcPose.forward).normalized;
  399. rotation = Quaternion.LookRotation(forward_use_gravity, Vector3.up);
  400. }
  401. var matrix = ConversionUtility.GetTMatrix(srcPose.position, rotation);
  402. cachedWorldMatrix = Matrix4x4.Inverse(matrix);
  403. cachedWorldPitch = -rotation.eulerAngles.x;
  404. // update pose immediately
  405. UpdatePoseByTrackingType();
  406. // log out
  407. {
  408. var correctPos = ConversionUtility.GetPositionFromTMatrix(cachedWorldMatrix);
  409. var correctRot = ConversionUtility.GetRotationFromTMatrix(cachedWorldMatrix);
  410. NRDebugger.Info("[NRHMDPoseTracker] ResetWorldMatrix : resetPitch={0}, curPos={1},{2} srcPose={3},{4}, cachedWorldPitch={5}, correctPos={6},{7}",
  411. resetPitch, pose.position.ToString("F4"), pose.rotation.eulerAngles.ToString("F4"),
  412. srcPose.position.ToString("F4"), srcPose.rotation.eulerAngles.ToString("F4"),
  413. cachedWorldPitch, correctPos.ToString("F4"), correctRot.eulerAngles.ToString("F4"));
  414. }
  415. OnWorldPoseReset?.Invoke();
  416. }
  417. /// <summary>
  418. /// Get the world offset matrix from native.
  419. /// </summary>
  420. /// <returns></returns>
  421. public Matrix4x4 GetWorldOffsetMatrixFromNative()
  422. {
  423. Matrix4x4 parentTransformMatrix;
  424. if (UseRelative)
  425. {
  426. if (transform.parent == null)
  427. {
  428. parentTransformMatrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3.one);
  429. }
  430. else
  431. {
  432. parentTransformMatrix = Matrix4x4.TRS(transform.parent.position, transform.parent.rotation, Vector3.one);
  433. }
  434. }
  435. else
  436. {
  437. parentTransformMatrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, Vector3.one);
  438. }
  439. return parentTransformMatrix * cachedWorldMatrix;
  440. }
  441. public float GetCachedWorldPitch()
  442. {
  443. return cachedWorldPitch;
  444. }
  445. private Pose ApplyWorldMatrix(Pose pose)
  446. {
  447. var objectMatrix = ConversionUtility.GetTMatrix(pose.position, pose.rotation);
  448. var object_in_world = cachedWorldMatrix * objectMatrix;
  449. return new Pose(ConversionUtility.GetPositionFromTMatrix(object_in_world),
  450. ConversionUtility.GetRotationFromTMatrix(object_in_world));
  451. }
  452. /// <summary> Initializes this object. </summary>
  453. /// <returns> An IEnumerator. </returns>
  454. private IEnumerator Initialize()
  455. {
  456. while (NRFrame.SessionStatus != SessionState.Running)
  457. {
  458. NRDebugger.Debug("[NRHMDPoseTracker] Waitting to initialize.");
  459. yield return new WaitForEndOfFrame();
  460. }
  461. #if !UNITY_EDITOR && !USING_XR_SDK
  462. leftCamera.enabled = false;
  463. rightCamera.enabled = false;
  464. bool result;
  465. var matrix_data = NRFrame.GetEyeProjectMatrix(out result, leftCamera.nearClipPlane, leftCamera.farClipPlane);
  466. Debug.Assert(result, "[NRHMDPoseTracker] GetEyeProjectMatrix failed.");
  467. if (result)
  468. {
  469. NRDebugger.Info("[NRHMDPoseTracker] Left Camera Project Matrix : {0}", matrix_data.LEyeMatrix.ToString());
  470. NRDebugger.Info("[NRHMDPoseTracker] RightCamera Project Matrix : {0}", matrix_data.REyeMatrix.ToString());
  471. leftCamera.projectionMatrix = matrix_data.LEyeMatrix;
  472. rightCamera.projectionMatrix = matrix_data.REyeMatrix;
  473. // set center camera's projection matrix with LEyeMatrix, in case some logic is using it
  474. centerCamera.projectionMatrix = matrix_data.LEyeMatrix;
  475. var eyeposeFromHead = NRFrame.EyePoseFromHead;
  476. leftCamera.transform.localPosition = eyeposeFromHead.LEyePose.position;
  477. leftCamera.transform.localRotation = eyeposeFromHead.LEyePose.rotation;
  478. rightCamera.transform.localPosition = eyeposeFromHead.REyePose.position;
  479. rightCamera.transform.localRotation = eyeposeFromHead.REyePose.rotation;
  480. centerAnchor.localPosition = centerCamera.transform.localPosition = (leftCamera.transform.localPosition + rightCamera.transform.localPosition) * 0.5f;
  481. centerAnchor.localRotation = centerCamera.transform.localRotation = Quaternion.Lerp(leftCamera.transform.localRotation, rightCamera.transform.localRotation, 0.5f);
  482. var centerRotMatrix = ConversionUtility.GetTMatrix(Vector3.zero, centerAnchor.localRotation).inverse;
  483. HeadRotFromCenter = new Pose(Vector3.zero, ConversionUtility.GetRotationFromTMatrix(centerRotMatrix));
  484. }
  485. #endif
  486. NRDebugger.Info("[NRHMDPoseTracker] Initialized success.");
  487. }
  488. public void RegisterSlamProvider(IExternSlamProvider provider)
  489. {
  490. NRDebugger.Info("[NRHMDPoseTracker] RegisterSlamProvider");
  491. m_externSlamProvider = provider;
  492. }
  493. public bool GetHeadPoseByTimeInUnityWorld(ref Pose headPose, ulong timeStamp)
  494. {
  495. var nativeHeadPose = Pose.identity;
  496. if (m_TrackingType == TrackingType.Tracking0Dof)
  497. {
  498. nativeHeadPose = HeadRotFromCenter;
  499. }
  500. else
  501. {
  502. if (m_externSlamProvider != null)
  503. {
  504. nativeHeadPose = m_externSlamProvider.GetHeadPoseAtTime(timeStamp);
  505. }
  506. else
  507. {
  508. if (timeStamp == NRFrame.CurrentPoseTimeStamp)
  509. {
  510. nativeHeadPose = NRFrame.HeadPose;
  511. }
  512. else
  513. {
  514. if (!NRFrame.GetHeadPoseByTime(ref nativeHeadPose, timeStamp))
  515. return false;
  516. }
  517. }
  518. if (m_TrackingType == TrackingType.Tracking0DofStable)
  519. {
  520. nativeHeadPose.rotation = HeadRotFromCenter.rotation * nativeHeadPose.rotation;
  521. }
  522. }
  523. headPose = nativeHeadPose;
  524. headPose = cachedWorldMatrix.Equals(Matrix4x4.identity) ? headPose : ApplyWorldMatrix(headPose);
  525. return true;
  526. }
  527. /// <summary> Updates the pose by tracking type. </summary>
  528. private void UpdatePoseByTrackingType()
  529. {
  530. Pose headPose = Pose.identity;
  531. #if USING_XR_SDK && !UNITY_EDITOR
  532. Pose centerPose;
  533. GetNodePoseData(XRNode.Head, out headPose);
  534. headPose = cachedWorldMatrix.Equals(Matrix4x4.identity) ? headPose : ApplyWorldMatrix(headPose);
  535. GetNodePoseData(XRNode.CenterEye, out centerPose);
  536. centerCamera.transform.localPosition = Vector3.zero;
  537. centerCamera.transform.localRotation = Quaternion.identity;
  538. centerAnchor.localPosition = centerPose.position;
  539. centerAnchor.localRotation = centerPose.rotation;
  540. #else
  541. if (!GetHeadPoseByTimeInUnityWorld(ref headPose, NRFrame.CurrentPoseTimeStamp))
  542. return;
  543. // NRDebugger.Info("[NRHMDPoseTracker] UpdatePose: trackType={2}, pos={0} --> {1}", NRFrame.HeadPose.ToString("F2"), headPose.ToString("F2"), m_TrackingType);
  544. #endif
  545. #if !UNITY_EDITOR
  546. if (UseRelative)
  547. {
  548. transform.localRotation = headPose.rotation;
  549. transform.localPosition = headPose.position;
  550. }
  551. else
  552. {
  553. transform.rotation = headPose.rotation;
  554. transform.position = headPose.position;
  555. }
  556. #endif
  557. }
  558. /// <summary> Check hmd pose state. </summary>
  559. private void CheckHMDPoseState()
  560. {
  561. if (NRFrame.SessionStatus != SessionState.Running
  562. || TrackingMode == TrackingType.Tracking0Dof
  563. || TrackingMode == TrackingType.Tracking0DofStable
  564. || IsTrackModeChanging)
  565. {
  566. return;
  567. }
  568. var currentReason = NRFrame.LostTrackingReason;
  569. // When LostTrackingReason changed.
  570. if (currentReason != m_LastReason)
  571. {
  572. if (currentReason != LostTrackingReason.NONE && m_LastReason == LostTrackingReason.NONE)
  573. {
  574. OnHMDLostTracking?.Invoke();
  575. NRSessionManager.OnHMDLostTracking?.Invoke();
  576. }
  577. else if (currentReason == LostTrackingReason.NONE && m_LastReason != LostTrackingReason.NONE)
  578. {
  579. OnHMDPoseReady?.Invoke();
  580. NRSessionManager.OnHMDPoseReady?.Invoke();
  581. }
  582. m_LastReason = currentReason;
  583. }
  584. }
  585. }
  586. }