ARLocationManager.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. // Copyright (C) 2018 Daniel Fortes <daniel.fortes@gmail.com>
  2. // All rights reserved.
  3. //
  4. // See LICENSE.TXT for more info
  5. using System;
  6. using ARLocation.Session;
  7. using UnityEngine;
  8. using UnityEngine.Events;
  9. #if !ARGPS_USE_VUFORIA
  10. using UnityEngine.XR.ARFoundation;
  11. #endif
  12. namespace ARLocation
  13. {
  14. using Utils;
  15. /// <summary>
  16. /// This Component manages all positioned GameObjects, synchronizing their world position in the scene
  17. /// with their geographical coordinates. This is done by calculating their position relative to the device's position.
  18. ///
  19. /// Should be placed in a GameObject called "ARLocationRoot", whose parent is the "AR Session Origin".
  20. /// </summary>
  21. [RequireComponent(typeof(ARLocationOrientation))]
  22. [DisallowMultipleComponent]
  23. [AddComponentMenu("AR+GPS/AR Location Manager")]
  24. [HelpURL("https://http://docs.unity-ar-gps-location.com/guide/#arlocationmanager")]
  25. public class ARLocationManager : Singleton<ARLocationManager>
  26. {
  27. [Tooltip("The AR Camera that will be used for rendering the AR content. If this is not set, the camera tagger as 'MainCamera' will be used." +
  28. " Make sure either this is set, or a camera is tagged as 'MainCamera', or an error will be thrown.")]
  29. public Camera Camera;
  30. [Tooltip("If true, wait until the AR Tracking starts to start with location and orientation updates and object placement.")]
  31. public bool WaitForARTrackingToStart = true;
  32. [Tooltip("If true, every time the AR tracking is lost and regained, the AR+GPS system is restarted, repositioning all the objects.")]
  33. public bool RestartWhenARTrackingIsRestored;
  34. [Tooltip("If true, the manager will set 'Application.targetFrameRate' to 60.")]
  35. public bool SetTargetFrameRateTo60Mhz = true;
  36. [Header("Debug")]
  37. [Tooltip("When debug mode is enabled, this component will print relevant messages to the console. Filter by 'ARLocationManager' in the log output to see the messages.")]
  38. public bool DebugMode;
  39. [Header("AR Session Events")]
  40. public UnityEvent OnTrackingStarted = new UnityEvent();
  41. public UnityEvent OnTrackingLost = new UnityEvent();
  42. public UnityEvent OnTrackingRestored = new UnityEvent();
  43. /// <summary>
  44. /// The instance of the 'IARSessionManager'. Handles the interface with the underlying AR session (i.e., Vuforia or AR Foundation).
  45. /// </summary>
  46. public IARSessionManager SessionManager { get; private set; }
  47. /// <summary>
  48. /// The 'MainCamera' that is being used for rendering the AR content.
  49. /// </summary>
  50. public Camera MainCamera { get; private set; }
  51. /// <summary>
  52. /// Returns the Y world-coordinate of the detected plane which is nearest to the user/camera.
  53. /// </summary>
  54. public float CurrentGroundY => groundHeight ? groundHeight.CurrentGroundY : -ARLocation.Config.InitialGroundHeightGuess;
  55. private ARLocationOrientation arLocationOrientation;
  56. private ARLocationProvider arLocationProvider;
  57. private Action onARTrackingStartedAction;
  58. private GameObject groundHeightDummy;
  59. private GroundHeight groundHeight;
  60. private Vector3 cameraPositionAtLastUpdate;
  61. public override void Awake()
  62. {
  63. base.Awake();
  64. if (SetTargetFrameRateTo60Mhz)
  65. {
  66. Logger.LogFromMethod("ARLocationManager", "Awake", "Setting 'Application.targetFrameRate' to 60", DebugMode);
  67. Application.targetFrameRate = 60;
  68. }
  69. MainCamera = Camera ? Camera : Camera.main;
  70. if (MainCamera == null)
  71. {
  72. throw new NullReferenceException("[AR+GPS][ARLocationManager#Start]: Missing Camera. " +
  73. "Either set the 'Camera' property to the AR Camera, or tag it as a 'MainCamera'.");
  74. }
  75. transform.localPosition = new Vector3(0, 0, 0);
  76. }
  77. private void Start()
  78. {
  79. arLocationOrientation = GetComponent<ARLocationOrientation>();
  80. arLocationProvider = ARLocationProvider.Instance;
  81. if (WaitForARTrackingToStart)
  82. {
  83. arLocationProvider.Mute();
  84. }
  85. #if !ARGPS_USE_VUFORIA
  86. var arSession = FindObjectOfType<ARSession>();
  87. if (!arSession)
  88. {
  89. throw new NullReferenceException("[AR+GPS][ARLocationManager#Start]: No ARSession found in the scene!");
  90. }
  91. SessionManager = new ARFoundationSessionManager(arSession);
  92. #else
  93. SessionManager = new VuforiaSessionManager();
  94. #endif
  95. SessionManager.DebugMode = DebugMode;
  96. SessionManager.OnARTrackingStarted(ARTrackingStartedCallback);
  97. SessionManager.OnARTrackingRestored(ARTrackingRestoredCallback);
  98. SessionManager.OnARTrackingLost(ARTrackingLostCallback);
  99. groundHeightDummy = new GameObject("ARLocationGroundHeight");
  100. groundHeightDummy.transform.SetParent(MainCamera.transform);
  101. groundHeightDummy.transform.localPosition = new Vector3();
  102. groundHeight = groundHeightDummy.AddComponent<GroundHeight>();
  103. arLocationProvider.OnLocationUpdatedEvent(onLocationUpdated);
  104. }
  105. private void onLocationUpdated(LocationReading currentLocation, LocationReading lastLocation)
  106. {
  107. cameraPositionAtLastUpdate = MainCamera.transform.position;
  108. }
  109. private void ARTrackingLostCallback()
  110. {
  111. Logger.LogFromMethod("ARLocationManager", "ARTrackingLostCallback", "'ARTrackingLost' event received.", DebugMode);
  112. OnTrackingLost?.Invoke();
  113. }
  114. private void ARTrackingRestoredCallback()
  115. {
  116. Logger.LogFromMethod("ARLocationManager", "ARTrackingRestoredCallback", "'ARTrackingRestore' event received.", DebugMode);
  117. if (RestartWhenARTrackingIsRestored)
  118. {
  119. Logger.LogFromMethod("ARLocationManager", "ARTrackingRestoredCallback", "'RestartWhenARTrackingIsRestored' is enabled; restarting.", DebugMode);
  120. Restart();
  121. }
  122. OnTrackingRestored?.Invoke();
  123. }
  124. private void ARTrackingStartedCallback()
  125. {
  126. Logger.LogFromMethod("ARLocationManager", "ARTrackingStartedCallback", "'OnARTrackingStarted' event received.", DebugMode);
  127. if (WaitForARTrackingToStart)
  128. {
  129. arLocationProvider.Unmute();
  130. }
  131. OnTrackingStarted?.Invoke();
  132. onARTrackingStartedAction?.Invoke();
  133. }
  134. /// <summary>
  135. /// This will reset the AR Session and the AR+GPS system, repositioning all objects.
  136. /// </summary>
  137. /// <param name="cb">Optional callback, called when the system has restarted.</param>
  138. public void ResetARSession(Action cb = null)
  139. {
  140. Logger.LogFromMethod("ARLocationManager", "ResetARSession", "Resetting the AR Session...", DebugMode);
  141. SessionManager?.Reset(() =>
  142. {
  143. Logger.LogFromMethod("ARLocationManager", "ResetARSession", "ARSession restarted. Resetting AR+GPS location...", DebugMode);
  144. Restart();
  145. cb?.Invoke();
  146. });
  147. }
  148. /// <summary>
  149. /// This will restart the AR+GPS system, repositioning all the objects.
  150. /// </summary>
  151. public void Restart()
  152. {
  153. Logger.LogFromMethod("ARLocationManager", "Restart", "Resetting AR+GPS location...", DebugMode);
  154. arLocationOrientation.Restart();
  155. arLocationProvider.Restart();
  156. Logger.LogFromMethod("ARLocationManager", "Restart", "Done.", DebugMode);
  157. }
  158. /// <summary>
  159. /// Returns a string describing the current AR session tracking status
  160. /// </summary>
  161. /// <returns></returns>
  162. public string GetARSessionInfoString()
  163. {
  164. return SessionManager != null ? SessionManager.GetSessionInfoString() : "None";
  165. }
  166. /// <summary>
  167. /// Returns a string describing the current AR Session provider, e.g., AR Foundation or Vuforia.
  168. /// </summary>
  169. /// <returns></returns>
  170. public string GetARSessionProviderString()
  171. {
  172. return SessionManager != null ? SessionManager.GetProviderString() : "None";
  173. }
  174. /// <summary>
  175. /// Add a event listener for when the AR Tracking starts.
  176. /// </summary>
  177. /// <param name="o"></param>
  178. public void OnARTrackingStarted(Action o)
  179. {
  180. if (SessionManager == null)
  181. {
  182. onARTrackingStartedAction += o;
  183. }
  184. else
  185. {
  186. SessionManager.OnARTrackingStarted(o);
  187. }
  188. }
  189. /// <summary>
  190. /// Add a event listener for when the AR Tracking regained after it was lost.
  191. /// </summary>
  192. /// <param name="callback"></param>
  193. public void OnARTrackingRestored(Action callback)
  194. {
  195. SessionManager?.OnARTrackingRestored(callback);
  196. }
  197. /// <summary>
  198. /// Add a event listener for when the AR Tracking is lost.
  199. /// </summary>
  200. /// <param name="callback"></param>
  201. public void OnARTrackingLost(Action callback)
  202. {
  203. SessionManager?.OnARTrackingLost(callback);
  204. }
  205. /// <summary>
  206. /// Given a world position vector, return the corresponding geographical Location.
  207. /// </summary>
  208. /// <param name="position"></param>
  209. /// <returns></returns>
  210. public Location GetLocationForWorldPosition(Vector3 position)
  211. {
  212. return Location.GetLocationForWorldPosition(gameObject.transform, cameraPositionAtLastUpdate, arLocationProvider.CurrentLocation.ToLocation(), position);
  213. }
  214. }
  215. }