ARTemplateMenuManager.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. using System.Collections.Generic;
  2. using UnityEngine.EventSystems;
  3. using UnityEngine.UI;
  4. using UnityEngine.XR.ARFoundation;
  5. using UnityEngine.XR.Interaction.Toolkit.Inputs.Readers;
  6. using UnityEngine.XR.Interaction.Toolkit.Interactors;
  7. using UnityEngine.XR.Interaction.Toolkit.Samples.StarterAssets;
  8. namespace UnityEngine.XR.Templates.AR
  9. {
  10. /// <summary>
  11. /// Handles dismissing the object menu when clicking out the UI bounds, and showing the
  12. /// menu again when the create menu button is clicked after dismissal. Manages object deletion in the AR demo scene,
  13. /// and also handles the toggling between the object creation menu button and the delete button.
  14. /// </summary>
  15. public class ARTemplateMenuManager : MonoBehaviour
  16. {
  17. [SerializeField]
  18. [Tooltip("Button that opens the create menu.")]
  19. Button m_CreateButton;
  20. /// <summary>
  21. /// Button that opens the create menu.
  22. /// </summary>
  23. public Button createButton
  24. {
  25. get => m_CreateButton;
  26. set => m_CreateButton = value;
  27. }
  28. [SerializeField]
  29. [Tooltip("Button that deletes a selected object.")]
  30. Button m_DeleteButton;
  31. /// <summary>
  32. /// Button that deletes a selected object.
  33. /// </summary>
  34. public Button deleteButton
  35. {
  36. get => m_DeleteButton;
  37. set => m_DeleteButton = value;
  38. }
  39. [SerializeField]
  40. [Tooltip("The menu with all the creatable objects.")]
  41. GameObject m_ObjectMenu;
  42. /// <summary>
  43. /// The menu with all the creatable objects.
  44. /// </summary>
  45. public GameObject objectMenu
  46. {
  47. get => m_ObjectMenu;
  48. set => m_ObjectMenu = value;
  49. }
  50. [SerializeField]
  51. [Tooltip("The modal with debug options.")]
  52. GameObject m_ModalMenu;
  53. /// <summary>
  54. /// The modal with debug options.
  55. /// </summary>
  56. public GameObject modalMenu
  57. {
  58. get => m_ModalMenu;
  59. set => m_ModalMenu = value;
  60. }
  61. [SerializeField]
  62. [Tooltip("The animator for the object creation menu.")]
  63. Animator m_ObjectMenuAnimator;
  64. /// <summary>
  65. /// The animator for the object creation menu.
  66. /// </summary>
  67. public Animator objectMenuAnimator
  68. {
  69. get => m_ObjectMenuAnimator;
  70. set => m_ObjectMenuAnimator = value;
  71. }
  72. [SerializeField]
  73. [Tooltip("The object spawner component in charge of spawning new objects.")]
  74. ObjectSpawner m_ObjectSpawner;
  75. /// <summary>
  76. /// The object spawner component in charge of spawning new objects.
  77. /// </summary>
  78. public ObjectSpawner objectSpawner
  79. {
  80. get => m_ObjectSpawner;
  81. set => m_ObjectSpawner = value;
  82. }
  83. [SerializeField]
  84. [Tooltip("Button that closes the object creation menu.")]
  85. Button m_CancelButton;
  86. /// <summary>
  87. /// Button that closes the object creation menu.
  88. /// </summary>
  89. public Button cancelButton
  90. {
  91. get => m_CancelButton;
  92. set => m_CancelButton = value;
  93. }
  94. [SerializeField]
  95. [Tooltip("The interaction group for the AR demo scene.")]
  96. XRInteractionGroup m_InteractionGroup;
  97. /// <summary>
  98. /// The interaction group for the AR demo scene.
  99. /// </summary>
  100. public XRInteractionGroup interactionGroup
  101. {
  102. get => m_InteractionGroup;
  103. set => m_InteractionGroup = value;
  104. }
  105. [SerializeField]
  106. [Tooltip("The slider for activating plane debug visuals.")]
  107. DebugSlider m_DebugPlaneSlider;
  108. /// <summary>
  109. /// The slider for activating plane debug visuals.
  110. /// </summary>
  111. public DebugSlider debugPlaneSlider
  112. {
  113. get => m_DebugPlaneSlider;
  114. set => m_DebugPlaneSlider = value;
  115. }
  116. [SerializeField]
  117. [Tooltip("The plane manager in the AR demo scene.")]
  118. ARPlaneManager m_PlaneManager;
  119. /// <summary>
  120. /// The plane manager in the AR demo scene.
  121. /// </summary>
  122. public ARPlaneManager planeManager
  123. {
  124. get => m_PlaneManager;
  125. set => m_PlaneManager = value;
  126. }
  127. [SerializeField]
  128. [Tooltip("Determines whether or not to fade the AR Planes when visualization is toggled.")]
  129. bool m_UseARPlaneFading = true;
  130. /// <summary>
  131. /// Determines whether or not to fade the AR Planes when visualization is toggled.
  132. /// </summary>
  133. public bool useARPlaneFading
  134. {
  135. get => m_UseARPlaneFading;
  136. set => m_UseARPlaneFading = value;
  137. }
  138. [SerializeField]
  139. [Tooltip("The AR debug menu.")]
  140. ARDebugMenu m_ARDebugMenu;
  141. /// <summary>
  142. /// The AR debug menu.
  143. /// </summary>
  144. public ARDebugMenu arDebugMenu
  145. {
  146. get => m_ARDebugMenu;
  147. set => m_ARDebugMenu = value;
  148. }
  149. [SerializeField]
  150. [Tooltip("The slider for activating the debug menu.")]
  151. DebugSlider m_DebugMenuSlider;
  152. /// <summary>
  153. /// The slider for activating the debug menu.
  154. /// </summary>
  155. public DebugSlider debugMenuSlider
  156. {
  157. get => m_DebugMenuSlider;
  158. set => m_DebugMenuSlider = value;
  159. }
  160. [SerializeField]
  161. XRInputValueReader<Vector2> m_TapStartPositionInput = new XRInputValueReader<Vector2>("Tap Start Position");
  162. /// <summary>
  163. /// Input to use for the screen tap start position.
  164. /// </summary>
  165. /// <seealso cref="TouchscreenGestureInputController.tapStartPosition"/>
  166. public XRInputValueReader<Vector2> tapStartPositionInput
  167. {
  168. get => m_TapStartPositionInput;
  169. set => XRInputReaderUtility.SetInputProperty(ref m_TapStartPositionInput, value, this);
  170. }
  171. [SerializeField]
  172. XRInputValueReader<Vector2> m_DragCurrentPositionInput = new XRInputValueReader<Vector2>("Drag Current Position");
  173. /// <summary>
  174. /// Input to use for the screen tap start position.
  175. /// </summary>
  176. /// <seealso cref="TouchscreenGestureInputController.dragCurrentPosition"/>
  177. public XRInputValueReader<Vector2> dragCurrentPositionInput
  178. {
  179. get => m_DragCurrentPositionInput;
  180. set => XRInputReaderUtility.SetInputProperty(ref m_DragCurrentPositionInput, value, this);
  181. }
  182. bool m_IsPointerOverUI;
  183. bool m_ShowObjectMenu;
  184. bool m_ShowOptionsModal;
  185. bool m_VisualizePlanes = true;
  186. bool m_ShowDebugMenu;
  187. bool m_InitializingDebugMenu;
  188. float m_DebugMenuPlanesButtonValue = 0f;
  189. Vector2 m_ObjectButtonOffset = Vector2.zero;
  190. Vector2 m_ObjectMenuOffset = Vector2.zero;
  191. readonly List<ARPlane> m_ARPlanes = new List<ARPlane>();
  192. readonly Dictionary<ARPlane, ARPlaneMeshVisualizer> m_ARPlaneMeshVisualizers = new Dictionary<ARPlane, ARPlaneMeshVisualizer>();
  193. readonly Dictionary<ARPlane, ARPlaneMeshVisualizerFader> m_ARPlaneMeshVisualizerFaders = new Dictionary<ARPlane, ARPlaneMeshVisualizerFader>();
  194. /// <summary>
  195. /// See <see cref="MonoBehaviour"/>.
  196. /// </summary>
  197. void OnEnable()
  198. {
  199. m_CreateButton.onClick.AddListener(ShowMenu);
  200. m_CancelButton.onClick.AddListener(HideMenu);
  201. m_DeleteButton.onClick.AddListener(DeleteFocusedObject);
  202. m_PlaneManager.trackablesChanged.AddListener(OnPlaneChanged);
  203. }
  204. /// <summary>
  205. /// See <see cref="MonoBehaviour"/>.
  206. /// </summary>
  207. void OnDisable()
  208. {
  209. m_ShowObjectMenu = false;
  210. m_CreateButton.onClick.RemoveListener(ShowMenu);
  211. m_CancelButton.onClick.RemoveListener(HideMenu);
  212. m_DeleteButton.onClick.RemoveListener(DeleteFocusedObject);
  213. m_PlaneManager.trackablesChanged.RemoveListener(OnPlaneChanged);
  214. }
  215. /// <summary>
  216. /// See <see cref="MonoBehaviour"/>.
  217. /// </summary>
  218. void Start()
  219. {
  220. // Auto turn on/off debug menu. We want it initially active so it calls into 'Start', which will
  221. // allow us to move the menu properties later if the debug menu is turned on.
  222. if (m_ARDebugMenu != null)
  223. {
  224. m_ARDebugMenu.gameObject.SetActive(true);
  225. m_InitializingDebugMenu = true;
  226. InitializeDebugMenuOffsets();
  227. }
  228. HideMenu();
  229. m_DebugMenuSlider.value = m_ShowDebugMenu ? 1 : 0;
  230. m_DebugPlaneSlider.value = m_VisualizePlanes ? 1 : 0;
  231. }
  232. /// <summary>
  233. /// See <see cref="MonoBehaviour"/>.
  234. /// </summary>
  235. void Update()
  236. {
  237. if (m_InitializingDebugMenu)
  238. {
  239. m_ARDebugMenu.gameObject.SetActive(false);
  240. m_InitializingDebugMenu = false;
  241. }
  242. if (m_ShowObjectMenu || m_ShowOptionsModal)
  243. {
  244. if (!m_IsPointerOverUI && (m_TapStartPositionInput.TryReadValue(out _) || m_DragCurrentPositionInput.TryReadValue(out _)))
  245. {
  246. if (m_ShowObjectMenu)
  247. HideMenu();
  248. if (m_ShowOptionsModal)
  249. m_ModalMenu.SetActive(false);
  250. }
  251. if (m_ShowObjectMenu)
  252. {
  253. m_DeleteButton.gameObject.SetActive(false);
  254. }
  255. else
  256. {
  257. m_DeleteButton.gameObject.SetActive(m_InteractionGroup?.focusInteractable != null);
  258. }
  259. m_IsPointerOverUI = EventSystem.current != null && EventSystem.current.IsPointerOverGameObject(-1);
  260. }
  261. else
  262. {
  263. m_IsPointerOverUI = false;
  264. m_CreateButton.gameObject.SetActive(true);
  265. m_DeleteButton.gameObject.SetActive(m_InteractionGroup?.focusInteractable != null);
  266. }
  267. if (!m_IsPointerOverUI && m_ShowOptionsModal)
  268. {
  269. m_IsPointerOverUI = EventSystem.current != null && EventSystem.current.IsPointerOverGameObject(-1);
  270. }
  271. }
  272. /// <summary>
  273. /// Set the index of the object in the list on the ObjectSpawner to a specific value.
  274. /// This is effectively an override of the default behavior or randomly spawning an object.
  275. /// </summary>
  276. /// <param name="objectIndex">The index in the array of the object to spawn with the ObjectSpawner</param>
  277. public void SetObjectToSpawn(int objectIndex)
  278. {
  279. if (m_ObjectSpawner == null)
  280. {
  281. Debug.LogWarning("Object Spawner not configured correctly: no ObjectSpawner set.");
  282. }
  283. else
  284. {
  285. if (m_ObjectSpawner.objectPrefabs.Count > objectIndex)
  286. {
  287. m_ObjectSpawner.spawnOptionIndex = objectIndex;
  288. }
  289. else
  290. {
  291. Debug.LogWarning("Object Spawner not configured correctly: object index larger than number of Object Prefabs.");
  292. }
  293. }
  294. HideMenu();
  295. }
  296. void ShowMenu()
  297. {
  298. m_ShowObjectMenu = true;
  299. m_ObjectMenu.SetActive(true);
  300. if (!m_ObjectMenuAnimator.GetBool("Show"))
  301. {
  302. m_ObjectMenuAnimator.SetBool("Show", true);
  303. }
  304. AdjustARDebugMenuPosition();
  305. }
  306. /// <summary>
  307. /// Shows or hides the menu modal when the options button is clicked.
  308. /// </summary>
  309. public void ShowHideModal()
  310. {
  311. if (m_ModalMenu.activeSelf)
  312. {
  313. m_ShowOptionsModal = false;
  314. m_ModalMenu.SetActive(false);
  315. }
  316. else
  317. {
  318. m_ShowOptionsModal = true;
  319. m_ModalMenu.SetActive(true);
  320. }
  321. }
  322. /// <summary>
  323. /// Shows or hides the plane debug visuals.
  324. /// </summary>
  325. public void ShowHideDebugPlane()
  326. {
  327. m_VisualizePlanes = !m_VisualizePlanes;
  328. m_DebugPlaneSlider.value = m_VisualizePlanes ? 1 : 0;
  329. ChangePlaneVisibility(m_VisualizePlanes);
  330. }
  331. /// <summary>
  332. /// Shows or hides the AR debug menu.
  333. /// </summary>
  334. public void ShowHideDebugMenu()
  335. {
  336. m_ShowDebugMenu = !m_ShowDebugMenu;
  337. m_DebugMenuSlider.value = m_ShowDebugMenu ? 1 : 0;
  338. // There is a bug in the ARDebugMenu that when the debug menu is enabled, it will always
  339. // turn off the line visualizers regardless of previous state. This means that the toggle
  340. // UI can appear "on" while the vizualizers are "off" and the toggle will behave opposite
  341. // of the value shown in the UI.
  342. // In the code below, we capture the previous value and only set the value back to 1 if it
  343. // is different than what the ARDebugMenu is tracking for that UI element. Otherwise it will
  344. // cause the same toggle behavior described above.
  345. if (m_ShowDebugMenu)
  346. {
  347. m_ARDebugMenu.gameObject.SetActive(true);
  348. AdjustARDebugMenuPosition();
  349. if (m_ARDebugMenu.showPlanesButton.value != m_DebugMenuPlanesButtonValue)
  350. m_ARDebugMenu.showPlanesButton.value = m_DebugMenuPlanesButtonValue;
  351. }
  352. else
  353. {
  354. m_DebugMenuPlanesButtonValue = m_ARDebugMenu.showPlanesButton.value;
  355. if (m_DebugMenuPlanesButtonValue == 1f)
  356. m_ARDebugMenu.showPlanesButton.value = 0f;
  357. m_ARDebugMenu.gameObject.SetActive(false);
  358. }
  359. }
  360. /// <summary>
  361. /// Clear all created objects in the scene.
  362. /// </summary>
  363. public void ClearAllObjects()
  364. {
  365. foreach (Transform child in m_ObjectSpawner.transform)
  366. {
  367. Destroy(child.gameObject);
  368. }
  369. }
  370. /// <summary>
  371. /// Triggers hide animation for menu.
  372. /// </summary>
  373. public void HideMenu()
  374. {
  375. m_ObjectMenuAnimator.SetBool("Show", false);
  376. m_ShowObjectMenu = false;
  377. AdjustARDebugMenuPosition();
  378. }
  379. void ChangePlaneVisibility(bool setVisible)
  380. {
  381. foreach (var plane in m_ARPlanes)
  382. {
  383. if (m_ARPlaneMeshVisualizers.TryGetValue(plane, out var visualizer))
  384. {
  385. visualizer.enabled = m_UseARPlaneFading ? true : setVisible;
  386. }
  387. if (m_ARPlaneMeshVisualizerFaders.TryGetValue(plane, out var fader))
  388. {
  389. if (m_UseARPlaneFading)
  390. fader.visualizeSurfaces = setVisible;
  391. else
  392. fader.SetVisualsImmediate(1f);
  393. }
  394. }
  395. }
  396. void DeleteFocusedObject()
  397. {
  398. var currentFocusedObject = m_InteractionGroup.focusInteractable;
  399. if (currentFocusedObject != null)
  400. {
  401. Destroy(currentFocusedObject.transform.gameObject);
  402. }
  403. }
  404. void InitializeDebugMenuOffsets()
  405. {
  406. if (m_CreateButton.TryGetComponent<RectTransform>(out var buttonRect))
  407. m_ObjectButtonOffset = new Vector2(0f, buttonRect.anchoredPosition.y + buttonRect.rect.height + 10f);
  408. else
  409. m_ObjectButtonOffset = new Vector2(0f, 200f);
  410. if (m_ObjectMenu.TryGetComponent<RectTransform>(out var menuRect))
  411. m_ObjectMenuOffset = new Vector2(0f, menuRect.anchoredPosition.y + menuRect.rect.height + 10f);
  412. else
  413. m_ObjectMenuOffset = new Vector2(0f, 345f);
  414. }
  415. void AdjustARDebugMenuPosition()
  416. {
  417. if (m_ARDebugMenu == null)
  418. return;
  419. float screenWidthInInches = Screen.width / Screen.dpi;
  420. if (screenWidthInInches < 5)
  421. {
  422. Vector2 menuOffset = m_ShowObjectMenu ? m_ObjectMenuOffset : m_ObjectButtonOffset;
  423. if (m_ARDebugMenu.toolbar.TryGetComponent<RectTransform>(out var rect))
  424. {
  425. rect.anchorMin = new Vector2(0.5f, 0);
  426. rect.anchorMax = new Vector2(0.5f, 0);
  427. rect.eulerAngles = new Vector3(rect.eulerAngles.x, rect.eulerAngles.y, 90);
  428. rect.anchoredPosition = new Vector2(0, 20) + menuOffset;
  429. }
  430. if (m_ARDebugMenu.displayInfoMenuButton.TryGetComponent<RectTransform>(out var infoMenuButtonRect))
  431. infoMenuButtonRect.localEulerAngles = new Vector3(infoMenuButtonRect.localEulerAngles.x, infoMenuButtonRect.localEulerAngles.y, -90);
  432. if (m_ARDebugMenu.displayConfigurationsMenuButton.TryGetComponent<RectTransform>(out var configurationsMenuButtonRect))
  433. configurationsMenuButtonRect.localEulerAngles = new Vector3(configurationsMenuButtonRect.localEulerAngles.x, configurationsMenuButtonRect.localEulerAngles.y, -90);
  434. if (m_ARDebugMenu.displayCameraConfigurationsMenuButton.TryGetComponent<RectTransform>(out var cameraConfigurationsMenuButtonRect))
  435. cameraConfigurationsMenuButtonRect.localEulerAngles = new Vector3(cameraConfigurationsMenuButtonRect.localEulerAngles.x, cameraConfigurationsMenuButtonRect.localEulerAngles.y, -90);
  436. if (m_ARDebugMenu.displayDebugOptionsMenuButton.TryGetComponent<RectTransform>(out var debugOptionsMenuButtonRect))
  437. debugOptionsMenuButtonRect.localEulerAngles = new Vector3(debugOptionsMenuButtonRect.localEulerAngles.x, debugOptionsMenuButtonRect.localEulerAngles.y, -90);
  438. if (m_ARDebugMenu.infoMenu.TryGetComponent<RectTransform>(out var infoMenuRect))
  439. {
  440. infoMenuRect.anchorMin = new Vector2(0.5f, 0);
  441. infoMenuRect.anchorMax = new Vector2(0.5f, 0);
  442. infoMenuRect.pivot = new Vector2(0.5f, 0);
  443. infoMenuRect.anchoredPosition = new Vector2(0, 150) + menuOffset;
  444. }
  445. if (m_ARDebugMenu.configurationMenu.TryGetComponent<RectTransform>(out var configurationsMenuRect))
  446. {
  447. configurationsMenuRect.anchorMin = new Vector2(0.5f, 0);
  448. configurationsMenuRect.anchorMax = new Vector2(0.5f, 0);
  449. configurationsMenuRect.pivot = new Vector2(0.5f, 0);
  450. configurationsMenuRect.anchoredPosition = new Vector2(0, 150) + menuOffset;
  451. }
  452. if (m_ARDebugMenu.cameraConfigurationMenu.TryGetComponent<RectTransform>(out var cameraConfigurationsMenuRect))
  453. {
  454. cameraConfigurationsMenuRect.anchorMin = new Vector2(0.5f, 0);
  455. cameraConfigurationsMenuRect.anchorMax = new Vector2(0.5f, 0);
  456. cameraConfigurationsMenuRect.pivot = new Vector2(0.5f, 0);
  457. cameraConfigurationsMenuRect.anchoredPosition = new Vector2(0, 150) + menuOffset;
  458. }
  459. if (m_ARDebugMenu.debugOptionsMenu.TryGetComponent<RectTransform>(out var debugOptionsMenuRect))
  460. {
  461. debugOptionsMenuRect.anchorMin = new Vector2(0.5f, 0);
  462. debugOptionsMenuRect.anchorMax = new Vector2(0.5f, 0);
  463. debugOptionsMenuRect.pivot = new Vector2(0.5f, 0);
  464. debugOptionsMenuRect.anchoredPosition = new Vector2(0, 150) + menuOffset;
  465. }
  466. }
  467. }
  468. void OnPlaneChanged(ARTrackablesChangedEventArgs<ARPlane> eventArgs)
  469. {
  470. if (eventArgs.added.Count > 0)
  471. {
  472. foreach (var plane in eventArgs.added)
  473. {
  474. m_ARPlanes.Add(plane);
  475. if (plane.TryGetComponent<ARPlaneMeshVisualizer>(out var vizualizer))
  476. {
  477. m_ARPlaneMeshVisualizers.Add(plane, vizualizer);
  478. if (!m_UseARPlaneFading)
  479. {
  480. vizualizer.enabled = m_VisualizePlanes;
  481. }
  482. }
  483. if (!plane.TryGetComponent<ARPlaneMeshVisualizerFader>(out var visualizer))
  484. {
  485. visualizer = plane.gameObject.AddComponent<ARPlaneMeshVisualizerFader>();
  486. }
  487. m_ARPlaneMeshVisualizerFaders.Add(plane, visualizer);
  488. visualizer.visualizeSurfaces = m_VisualizePlanes;
  489. }
  490. }
  491. if (eventArgs.removed.Count > 0)
  492. {
  493. foreach (var plane in eventArgs.removed)
  494. {
  495. var planeGameObject = plane.Value;
  496. if (planeGameObject == null)
  497. continue;
  498. if (m_ARPlanes.Contains(planeGameObject))
  499. m_ARPlanes.Remove(planeGameObject);
  500. if (m_ARPlaneMeshVisualizers.ContainsKey(planeGameObject))
  501. m_ARPlaneMeshVisualizers.Remove(planeGameObject);
  502. if (m_ARPlaneMeshVisualizerFaders.ContainsKey(planeGameObject))
  503. m_ARPlaneMeshVisualizerFaders.Remove(planeGameObject);
  504. }
  505. }
  506. // Fallback if the counts do not match after an update
  507. if (m_PlaneManager.trackables.count != m_ARPlanes.Count)
  508. {
  509. m_ARPlanes.Clear();
  510. m_ARPlaneMeshVisualizers.Clear();
  511. m_ARPlaneMeshVisualizerFaders.Clear();
  512. foreach (var plane in m_PlaneManager.trackables)
  513. {
  514. m_ARPlanes.Add(plane);
  515. if (plane.TryGetComponent<ARPlaneMeshVisualizer>(out var vizualizer))
  516. {
  517. m_ARPlaneMeshVisualizers.Add(plane, vizualizer);
  518. if (!m_UseARPlaneFading)
  519. {
  520. vizualizer.enabled = m_VisualizePlanes;
  521. }
  522. }
  523. if (!plane.TryGetComponent<ARPlaneMeshVisualizerFader>(out var fader))
  524. {
  525. fader = plane.gameObject.AddComponent<ARPlaneMeshVisualizerFader>();
  526. }
  527. m_ARPlaneMeshVisualizerFaders.Add(plane, fader);
  528. fader.visualizeSurfaces = m_VisualizePlanes;
  529. }
  530. }
  531. }
  532. }
  533. }