WorldTracker.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.Events;
  5. using System.Runtime.InteropServices;
  6. #if ENABLE_INPUT_SYSTEM
  7. using UnityEngine.InputSystem;
  8. #endif
  9. namespace Imagine.WebAR
  10. {
  11. [System.Serializable]
  12. public class PlacementIndicatorSettings
  13. {
  14. public float minZ = 0.5f, maxZ = 5;
  15. public GameObject placementIndicator;
  16. public bool placed = false;
  17. [Space()]
  18. public UnityEvent OnPlacementIndicatorShown, OnPlacementIndicatorHidden;
  19. }
  20. [System.Serializable]
  21. public class EventSettings{
  22. public UnityEvent OnPlacedOrigin, OnResetOrigin;
  23. public List<GameObject> ShowGameObjectsWhenPlaced = new List<GameObject>();
  24. public List<GameObject> ShowGameObjectsWhenReset = new List<GameObject>();
  25. }
  26. public partial class WorldTracker : MonoBehaviour
  27. {
  28. [DllImport("__Internal")] private static extern void WebGLResetOrigin();
  29. [DllImport("__Internal")] private static extern void StartWebGLwTracker(string name);
  30. [DllImport("__Internal")] private static extern void StopWebGLwTracker();
  31. [DllImport("__Internal")] private static extern void SetWebGLwTrackerSettings(string settings);
  32. [DllImport("__Internal")] private static extern bool IsWebGLwTrackerReady();
  33. [SerializeField] ARCamera trackerCamera;
  34. public enum TrackingMode { MODE_3DOF, MODE_6DOF, MODE_3DOF_ORBIT }
  35. [SerializeField] public TrackingMode mode;
  36. public enum PlaneMode {HORIZONTAL, VERTICAL_EXPERIMENTAL}
  37. [SerializeField] public PlaneMode planeMode;
  38. [SerializeField] public Settings3DOF s3dof;
  39. [SerializeField] public Settings3DOFOrbit s3dof_orbit;
  40. [SerializeField] public Settings6DOF s6dof;
  41. [SerializeField] public GameObject mainObject;
  42. [SerializeField] [Range(50,200)] private float debugCamMoveSensitivity = 100;
  43. [SerializeField] [Range(50,200)] private float debugCamTiltSensitivity = 100;
  44. [SerializeField] private float cameraStartHeight = 1.25f;
  45. [SerializeField] private bool usePlacementIndicator = true;
  46. [SerializeField] private PlacementIndicatorSettings placementIndicatorSettings;
  47. [SerializeField] public EventSettings eventSettings;
  48. [SerializeField] public bool useCompass = false;
  49. private Vector3 origPos, origScale;
  50. private Quaternion origRot;
  51. private Vector3 trackerCamPos, trackerMainObjectScale;
  52. private Quaternion trackerCamRot;
  53. private Vector2 trackerCamSSPos;
  54. private void Awake()
  55. {
  56. if(trackerCamera == null){
  57. trackerCamera = FindObjectOfType<ARCamera>();
  58. }
  59. var camPos = trackerCamera.transform.position;
  60. camPos.y = cameraStartHeight;
  61. trackerCamera.transform.position = camPos;
  62. //Debug.Log(trackerCamera.transform.position);
  63. origPos = trackerCamera.transform.position;
  64. origRot = trackerCamera.transform.rotation;
  65. origScale = mainObject.transform.localScale;
  66. targetPos3DOF = origPos;
  67. targetRot3DOF = origRot;
  68. if (mode == TrackingMode.MODE_3DOF)
  69. {
  70. Awake_3DOF();
  71. }
  72. else if (mode == TrackingMode.MODE_3DOF_ORBIT)
  73. {
  74. Awake_3DOF_Orbit();
  75. }
  76. else if (mode == TrackingMode.MODE_6DOF)
  77. {
  78. Awake_6DOF();
  79. }
  80. }
  81. IEnumerator Start()
  82. {
  83. #if UNITY_WEBGL && !UNITY_EDITOR
  84. while(!IsWebGLwTrackerReady()){
  85. yield return new WaitForEndOfFrame();
  86. }
  87. StartWebGLwTracker(name);
  88. #endif
  89. if (mode == TrackingMode.MODE_3DOF)
  90. {
  91. Start_3DOF();
  92. }
  93. else if (mode == TrackingMode.MODE_3DOF_ORBIT)
  94. {
  95. Start_3DOF_Orbit();
  96. }
  97. else if (mode == TrackingMode.MODE_6DOF)
  98. {
  99. Start_6DOF();
  100. }
  101. ResetOrigin();
  102. StartGPS();
  103. yield break;
  104. }
  105. void OnDestroy()
  106. {
  107. //ResetOrigin();
  108. #if UNITY_WEBGL && !UNITY_EDITOR
  109. StopWebGLwTracker();
  110. #endif
  111. OnDestroyGPS();
  112. }
  113. void Update()
  114. {
  115. if (usePlacementIndicator && !placementIndicatorSettings.placed)
  116. {
  117. UpdatePlacementIndicator();
  118. }
  119. if (mode == TrackingMode.MODE_3DOF)
  120. {
  121. Update_3DOF();
  122. }
  123. else if (mode == TrackingMode.MODE_3DOF_ORBIT)
  124. {
  125. Update_3DOF_Orbit();
  126. }
  127. else if (mode == TrackingMode.MODE_6DOF)
  128. {
  129. Update_6DOF();
  130. }
  131. //Geolocation
  132. if(useGeolocation){
  133. UpdateGPS();
  134. }
  135. //Debug
  136. #if UNITY_EDITOR
  137. if(useGeolocation){
  138. Update_DebugGeolocation();
  139. }
  140. else{
  141. Update_Debug();
  142. }
  143. #else
  144. Update_Debug();
  145. #endif
  146. }
  147. void UpdatePlacementIndicator()
  148. {
  149. var ps = placementIndicatorSettings;
  150. //move this transform along z, in front of the camera
  151. var camPos = trackerCamera.transform.position;
  152. var colliderPlane = new Plane();
  153. if(planeMode == PlaneMode.HORIZONTAL){
  154. camPos.y = 0;
  155. //xz plane
  156. colliderPlane = new Plane(Vector3.up, camPos);
  157. placementIndicatorSettings.placementIndicator.transform.eulerAngles = Vector3.zero;
  158. // mainObject.transform.GetChild(0).eulerAngles = new Vector3(0, 0, 0);
  159. }
  160. else if(planeMode == PlaneMode.VERTICAL_EXPERIMENTAL){
  161. camPos.z += startZ;
  162. //xy plane
  163. colliderPlane = new Plane(Vector3.back, camPos);
  164. placementIndicatorSettings.placementIndicator.transform.eulerAngles = new Vector3(-90, 0, 0);
  165. // mainObject.transform.GetChild(0).eulerAngles = new Vector3(-90, 0, 0);
  166. }
  167. var ray = new Ray(trackerCamera.transform.position, trackerCamera.transform.forward);
  168. Debug.DrawRay(ray.origin, ray.direction, Color.magenta, 1);
  169. float enter = 0;
  170. if (colliderPlane.Raycast(ray, out enter))
  171. {
  172. //Debug.Log("hit!");
  173. if (!ps.placementIndicator.activeSelf)
  174. ps.OnPlacementIndicatorShown?.Invoke();
  175. ps.placementIndicator.SetActive(true);
  176. var hitPoint = ray.GetPoint(enter);
  177. var d = Vector3.Distance(hitPoint, camPos);
  178. if (d > ps.minZ && d < ps.maxZ)
  179. {
  180. //mainObject.transform.position = hitPoint;
  181. ps.placementIndicator.transform.position = hitPoint;
  182. }
  183. else if (d < ps.minZ)
  184. {
  185. //mainObject.transform.position = camPos + Vector3.Normalize(hitPoint - camPos) * ps.minZ;
  186. ps.placementIndicator.transform.position = camPos + Vector3.Normalize(hitPoint - camPos) * ps.minZ;
  187. }
  188. else if (d > ps.maxZ)
  189. {
  190. //mainObject.transform.position = camPos + Vector3.Normalize(hitPoint - camPos) * ps.maxZ;
  191. ps.placementIndicator.transform.position = camPos + Vector3.Normalize(hitPoint - camPos) * ps.maxZ;
  192. //TODO: BUG HERE - Object is off-center
  193. }
  194. //ps.placementIndicator.transform.position = mainObject.transform.position;
  195. }
  196. else
  197. {
  198. //Debug.Log("no hit!");
  199. if (ps.placementIndicator.activeSelf)
  200. ps.OnPlacementIndicatorHidden?.Invoke();
  201. ps.placementIndicator.SetActive(false);
  202. }
  203. }
  204. public void Update_Debug()
  205. {
  206. #if ENABLE_INPUT_SYSTEM
  207. var x_left = Keyboard.current != null && Keyboard.current.aKey.isPressed;
  208. var x_right = Keyboard.current != null && Keyboard.current.dKey.isPressed;
  209. var z_forward = Keyboard.current != null && Keyboard.current.wKey.isPressed;
  210. var z_back = Keyboard.current != null && Keyboard.current.sKey.isPressed;
  211. var y_up = Keyboard.current != null && Keyboard.current.rKey.isPressed;
  212. var y_down = Keyboard.current != null && Keyboard.current.fKey.isPressed;
  213. #else
  214. var x_left = Input.GetKey(KeyCode.A);
  215. var x_right = Input.GetKey(KeyCode.D);
  216. var z_forward = Input.GetKey(KeyCode.W);
  217. var z_back = Input.GetKey(KeyCode.S);
  218. var y_up = Input.GetKey(KeyCode.R);
  219. var y_down = Input.GetKey(KeyCode.F);
  220. #endif
  221. float speed = 0.025f * Time.deltaTime * debugCamMoveSensitivity;
  222. float dx = (x_right ? speed : 0) + (x_left ? -speed : 0);
  223. float dy = (y_up ? speed : 0) + (y_down ? -speed : 0);
  224. float dz = (z_forward ? speed : 0) + (z_back ? -speed : 0);
  225. //float dsca = 1 + (z_forward ? speed : 0) + (z_back ? -speed : 0);
  226. #if ENABLE_INPUT_SYSTEM
  227. var y_rot_left = Keyboard.current != null && Keyboard.current.leftArrowKey.isPressed;
  228. var y_rot_right = Keyboard.current != null && Keyboard.current.rightArrowKey.isPressed;
  229. var x_rot_up = Keyboard.current != null && Keyboard.current.upArrowKey.isPressed;
  230. var x_rot_down = Keyboard.current != null && Keyboard.current.downArrowKey.isPressed;
  231. var z_rot_cw = Keyboard.current != null && Keyboard.current.commaKey.isPressed;
  232. var z_rot_ccw = Keyboard.current != null && Keyboard.current.periodKey.isPressed;
  233. #else
  234. var y_rot_left = Input.GetKey(KeyCode.LeftArrow);
  235. var y_rot_right = Input.GetKey(KeyCode.RightArrow);
  236. var x_rot_up = Input.GetKey(KeyCode.UpArrow);
  237. var x_rot_down = Input.GetKey(KeyCode.DownArrow);
  238. var z_rot_cw = Input.GetKey(KeyCode.Comma);
  239. var z_rot_ccw = Input.GetKey(KeyCode.Period);
  240. #endif
  241. var angularSpeed = 0.5f * Time.deltaTime * debugCamTiltSensitivity; //degrees per frame
  242. var d_rotx = (x_rot_up ? angularSpeed : 0) + (x_rot_down ? -angularSpeed : 0);
  243. var d_roty = (y_rot_right ? angularSpeed : 0) + (y_rot_left ? -angularSpeed : 0);
  244. var d_rotz = (z_rot_ccw ? angularSpeed : 0) + (z_rot_cw ? -angularSpeed : 0);
  245. var w = trackerCamera.transform.rotation.w;
  246. var i = trackerCamera.transform.rotation.x;
  247. var j = trackerCamera.transform.rotation.y;
  248. var k = trackerCamera.transform.rotation.z;
  249. var rot = new Quaternion(i, j, k, w);
  250. var dq = Quaternion.Euler(d_rotx, d_roty, d_rotz);
  251. rot *= dq;
  252. //rot *= Quaternion.AngleAxis(d_rotz, trackerCamera.transform.forward);
  253. //rot *= Quaternion.AngleAxis(d_roty, trackerCamera.transform.up);
  254. //rot *= Quaternion.AngleAxis(d_rotx, trackerCamera.transform.right);
  255. //Debug.Log(dx + "," + dy + "," + dsca);
  256. trackerCamera.transform.rotation = rot;
  257. var dp = trackerCamera.transform.right * dx + trackerCamera.transform.up * dy + trackerCamera.transform.forward * dz;
  258. trackerCamera.transform.position += dp;
  259. }
  260. public void SetCameraFov(float fov)
  261. {
  262. trackerCamera.GetComponent<Camera>().fieldOfView = fov;
  263. }
  264. public void StartTracker(){
  265. StartWebGLwTracker(gameObject.name);
  266. }
  267. public void StopTracker(){
  268. StopWebGLwTracker();
  269. }
  270. public void PlaceOrigin()
  271. {
  272. //ResetOrigin();
  273. if (usePlacementIndicator)
  274. {
  275. var ps = placementIndicatorSettings;
  276. if (ps.placed)
  277. {
  278. Debug.LogError("Origin is already placed. Call ResetOrigin() first");
  279. return;
  280. }
  281. if(mode == TrackingMode.MODE_3DOF){
  282. Place_3DOF(ps.placementIndicator.transform.position);
  283. }
  284. else if(mode == TrackingMode.MODE_6DOF){
  285. Place_6DOF();
  286. }
  287. ps.placed = true;
  288. ps.placementIndicator.SetActive(false);
  289. mainObject.SetActive(true);
  290. //mainObject.transform.LookAt(new Vector3(trackerCamera.transform.position.x, 0, trackerCamera.transform.position.z), Vector3.up);
  291. }
  292. eventSettings.OnPlacedOrigin?.Invoke();
  293. foreach(var g in eventSettings.ShowGameObjectsWhenPlaced){
  294. g.gameObject.SetActive(true);
  295. }
  296. foreach(var g in eventSettings.ShowGameObjectsWhenReset){
  297. g.gameObject.SetActive(false);
  298. }
  299. StartCoroutine(WaitAndInvoke(0.25f, ()=>{
  300. //Billboard the object to always face the camera
  301. mainObject.transform.LookAt(new Vector3(trackerCamera.transform.position.x, 0, trackerCamera.transform.position.z), Vector3.up);
  302. }));
  303. trackerCamPos = origPos;
  304. trackerCamRot = origRot;
  305. trackerMainObjectScale = origScale;
  306. }
  307. public void ResetOrigin()
  308. {
  309. trackerCamera.transform.rotation = origRot;
  310. trackerCamera.transform.position = origPos;
  311. if (mode == TrackingMode.MODE_3DOF)
  312. {
  313. Reset_3DOF();
  314. }
  315. else if (mode == TrackingMode.MODE_3DOF_ORBIT)
  316. {
  317. Reset_3DOF_Orbit();
  318. }
  319. else if (mode == TrackingMode.MODE_6DOF)
  320. {
  321. Reset_6DOF();
  322. }
  323. if (usePlacementIndicator)
  324. {
  325. var ps = placementIndicatorSettings;
  326. if (!ps.placed)
  327. {
  328. Debug.LogError("Origin not placed. Call PlaceOrigin() first");
  329. return;
  330. }
  331. ps.placed = false;
  332. ps.placementIndicator.SetActive(true);
  333. mainObject.SetActive(false);
  334. }
  335. else{
  336. if(mode == TrackingMode.MODE_6DOF){
  337. var camPos = new Vector3(origPos.x, 0, origPos.z);
  338. trackerCamera.transform.position = camPos;
  339. }
  340. }
  341. #if UNITY_WEBGL && !UNITY_EDITOR
  342. WebGLResetOrigin();
  343. #endif
  344. eventSettings.OnResetOrigin?.Invoke();
  345. foreach(var g in eventSettings.ShowGameObjectsWhenPlaced){
  346. if(g == null)
  347. {
  348. Debug.LogError("A null object ignored in ShowGameObjectsWhenPlaced list");
  349. continue;
  350. }
  351. g.gameObject.SetActive(false);
  352. }
  353. foreach(var g in eventSettings.ShowGameObjectsWhenReset){
  354. if(g == null)
  355. {
  356. Debug.LogError("A null object ignored in ShowGameObjectsWhenReset list");
  357. continue;
  358. }
  359. //Debug.Log(g.name);
  360. g.gameObject.SetActive(true);
  361. }
  362. }
  363. IEnumerator WaitAndInvoke(float delay, UnityAction action){
  364. yield return new WaitForSeconds(delay);
  365. action.Invoke();
  366. }
  367. }
  368. }