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