ZEDPlaneDetectionManager.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. //======= Copyright (c) Stereolabs Corporation, All rights reserved. ===============
  2. using UnityEngine;
  3. using System.Collections.Generic;
  4. #if UNITY_EDITOR
  5. using UnityEditor;
  6. #endif
  7. /// <summary>
  8. /// Manages the ZED SDK's plane detection feature.
  9. /// This allows you to check a point on the screen to see if it's part of a real-life plane, such as
  10. /// a floor, wall, tabletop, etc. If it is, this component will create a GameObject representing that
  11. /// plane with its proper world position and boundaries.
  12. /// If this component exists in your scene, you can also click the screen to detect planes there.
  13. /// By default it adds a MeshCollider, so that physics objects can interact with it properly, and a
  14. /// MeshRenderer, so that it's visible.
  15. /// Planes are rendered with ZEDPlaneRenderer, so they aren't occluded, thereby avoiding Z-fighting with the
  16. /// surfaces they represent.
  17. /// </summary>
  18. [DisallowMultipleComponent]
  19. public class ZEDPlaneDetectionManager : MonoBehaviour
  20. {
  21. /// <summary>
  22. /// GameObject all planes are parented to. Created at runtime, called '[ZED Planes]' in Hierarchy.
  23. /// </summary>
  24. private GameObject holder;
  25. /// <summary>
  26. /// Whether a floor plane has been detected during runtime.
  27. /// This won't happen unless DetectFloorPlane() is called.
  28. /// </summary>
  29. private bool hasDetectedFloor = false;
  30. /// <summary>
  31. /// Public accessor for hasDetectedFloor, which is whether a floor plane has been detected during runtime.
  32. /// </summary>
  33. public bool HasDetectedFloor
  34. {
  35. get { return hasDetectedFloor; }
  36. }
  37. /// <summary>
  38. /// GameObject holding floorPlane, which representing the floor plane, if one has been detected.
  39. /// </summary>
  40. private GameObject floorPlaneGO;
  41. /// <summary>
  42. /// ZEDPlaneGameObject representing the floor plane, if one has been detected.
  43. /// This reference is used to clear the existing floor plane if a new one is detected.
  44. /// </summary>
  45. private ZEDPlaneGameObject floorPlane = null;
  46. /// <summary>
  47. /// Returns the ZEDPlaneGameObject representing the floor, if the floor has been detected.
  48. /// </summary>
  49. public ZEDPlaneGameObject getFloorPlane
  50. {
  51. get { return floorPlane; }
  52. }
  53. /// <summary>
  54. /// How many hit planes have been detected. Used to assign the index of hitPlaneList
  55. /// to the ZEDPlaneGameObject's themselves, and to name their GameObjects.
  56. /// </summary>
  57. private int planeHitCount = 0;
  58. /// <summary>
  59. /// All the hit planes that have been detected using DetectPlaneAtHit().
  60. /// </summary>
  61. public List<ZEDPlaneGameObject> hitPlaneList = null;
  62. /// <summary>
  63. /// Buffer for holding a new plane's vertex data from the SDK.
  64. /// </summary>
  65. private Vector3[] planeMeshVertices;
  66. /// <summary>
  67. /// Buffer for holding a new plane's triangle data from the SDK.
  68. /// </summary>
  69. private int[] planeMeshTriangles;
  70. /// <summary>
  71. /// Whether we're displaying the planes in the Scene view using ZEDPlaneRenderer. Usually the same as isVisibleInSceneOption.
  72. /// </summary>
  73. public static bool isSceneDisplay = true;
  74. /// <summary>
  75. /// Whether we're displaying the planes in the Game view using ZEDPlaneRenderer. Usually the same as isVisibleInGameOption.
  76. /// Used by ZEDRenderingPlane to know if it should draw the meshes in its OnRenderImage() method.
  77. /// </summary>
  78. public static bool isGameDisplay = false;
  79. /// <summary>
  80. /// Whether the planes can collide with virtual objects (with colliders). Changing this enables/disables
  81. /// mesh colliders on all new and existing planes.
  82. /// </summary>
  83. public bool planesHavePhysics
  84. {
  85. get
  86. {
  87. return addPhysicsOption;
  88. }
  89. set
  90. {
  91. if (addPhysicsOption != value)
  92. {
  93. willUpdatePhysics = true;
  94. addPhysicsOption = value;
  95. }
  96. }
  97. }
  98. /// <summary>
  99. /// Whether the planes can collide with virtual objects (with colliders).
  100. /// To update publicly or at runtime, use planesHavePhysics instead.
  101. /// </summary>
  102. [SerializeField]
  103. private bool addPhysicsOption = true;
  104. /// <summary>
  105. /// If true, existing planes will have their colliders updated
  106. /// based on addPhhysicsOption in the next Update() step.
  107. /// </summary>
  108. private bool willUpdatePhysics = false;
  109. /// <summary>
  110. /// Whether the planes are drawn. Changing this setting enables/disables the plane's MeshRenderers.
  111. /// Note that if disabled, planes will not be drawn in the Game view regardless of the planesVisibleInGame setting.
  112. /// </summary>
  113. public bool planesVisibleInScene
  114. {
  115. get
  116. {
  117. return isVisibleInSceneOption;
  118. }
  119. set
  120. {
  121. if (value != isVisibleInSceneOption)
  122. {
  123. isVisibleInSceneOption = value;
  124. willUpdateSceneVisibility = true;
  125. }
  126. }
  127. }
  128. /// <summary>
  129. /// Whether the planes are drawn.
  130. /// To update publicly or at runtime, use planesVisibleInScene instead.
  131. /// </summary>
  132. [SerializeField]
  133. private bool isVisibleInSceneOption = true;
  134. /// <summary>
  135. /// If true, existing planes will have their visibility updated
  136. /// based on isVisibleInSceneOption in the next Update() step.
  137. /// </summary>
  138. private bool willUpdateSceneVisibility = true;
  139. /// <summary>
  140. /// Whether the planes are drawn in the ZED's final output, viewable in Unity's Game window or a build.
  141. /// </summary>
  142. public bool planesVisibleInGame
  143. {
  144. get
  145. {
  146. return isVisibleInGameOption;
  147. }
  148. set
  149. {
  150. if (value != isVisibleInGameOption)
  151. {
  152. isVisibleInGameOption = value;
  153. willUpdateGameVisibility = true;
  154. }
  155. }
  156. }
  157. /// <summary>
  158. /// Whether the planes are drawn in the ZED's final output, viewable in Unity's Game window or a build.
  159. /// To update publicly or at runtime, use planesVisibleInGame instead.
  160. /// </summary>
  161. [SerializeField]
  162. private bool isVisibleInGameOption = true;
  163. /// <summary>
  164. /// If true, existing planes will have their in-game visibility updated
  165. /// based on isVisibleInGameOption in the next Update() step.
  166. /// </summary>
  167. private bool willUpdateGameVisibility = true;
  168. /// <summary>
  169. /// Overrides the default wireframe material used to draw planes in the Scene and Game view.
  170. /// Leave this setting to null to draw the default wireframes.
  171. /// </summary>
  172. public Material overrideMaterial = null; //If null, shows wireframe. Otherwise, displays your custom material.
  173. /// <summary>
  174. /// How high the player's head is from the floor. Filled in when DetectFloorPlane() is called.
  175. /// </summary>
  176. private float estimatedPlayerHeight = 0.0f;
  177. /// <summary>
  178. /// Public accessor for estimatedPlayerHeight, which is how high the player's head was when DetectFloorPlane() was last called.
  179. /// </summary>
  180. public float GetEstimatedPlayerHeight
  181. {
  182. get { return estimatedPlayerHeight; }
  183. }
  184. /// <summary>
  185. /// Assign references, create the holder gameobject, and other misc. initialization.
  186. /// </summary>
  187. private void Start()
  188. {
  189. //Create a holder for all the planes
  190. holder = new GameObject();
  191. holder.name = "[ZED Planes]";
  192. holder.transform.parent = this.transform;
  193. holder.transform.position = Vector3.zero;
  194. holder.transform.rotation = Quaternion.identity;
  195. StaticBatchingUtility.Combine(holder);
  196. //initialize Vertices/Triangles with enough length
  197. planeMeshVertices = new Vector3[65000];
  198. planeMeshTriangles = new int[65000];
  199. //floorPlaneGO = holder.AddComponent<ZEDPlaneGameObject> ();
  200. hitPlaneList = new List<ZEDPlaneGameObject>();
  201. }
  202. public void OnDisable()
  203. {
  204. foreach (Transform child in holder.transform)
  205. {
  206. Destroy(child.gameObject);
  207. Destroy(holder);
  208. }
  209. }
  210. /// <summary>
  211. /// Transforms the plane mesh from Camera frame to local frame, where each vertex is relative to the plane's center.
  212. /// Used because plane data from the ZED SDK is relative to the camera, not the world.
  213. /// </summary>
  214. /// <param name="camera">Camera transform.</param>
  215. /// <param name="srcVertices">Source vertices (in camera space).</param>
  216. /// <param name="srcTriangles">Source triangles (in camera space).</param>
  217. /// <param name="dstVertices">Dst vertices (in world space).</param>
  218. /// <param name="dstTriangles">Dst triangles (in world space).</param>
  219. /// <param name="numVertices">Number of vertices.</param>
  220. /// <param name="numTriangles">Number of triangles.</param>
  221. private void TransformCameraToLocalMesh(Transform camera, Vector3[] srcVertices, int[] srcTriangles, Vector3[] dstVertices, int[] dstTriangles, int numVertices, int numTriangles, Vector3 centerpos)
  222. {
  223. if (numVertices == 0 || numTriangles == 0)
  224. return; //Plane is empty.
  225. System.Array.Copy(srcVertices, dstVertices, numVertices);
  226. System.Buffer.BlockCopy(srcTriangles, 0, dstTriangles, 0, numTriangles * sizeof(int));
  227. for (int i = 0; i < numVertices; i++)
  228. {
  229. dstVertices[i] -= centerpos;
  230. dstVertices[i] = camera.transform.rotation * dstVertices[i];
  231. }
  232. }
  233. /// <summary>
  234. /// Detects the floor plane. Replaces the current floor plane, if there is one, unlike DetectPlaneAtHit().
  235. /// If a floor is detected, also assigns the user's height from the floor to estimatedPlayerHeight.
  236. /// <para>Uses the first available ZEDManager in the scene.</para>
  237. /// </summary>
  238. /// <returns><c>true</c>, if floor plane was detected, <c>false</c> otherwise.</returns>
  239. public bool DetectFloorPlane(bool auto)
  240. {
  241. //Find the first available ZEDManager.
  242. List<ZEDManager> managers = ZEDManager.GetInstances();
  243. if (managers.Count == 0) return false; //No ZEDManager to use.
  244. else return DetectFloorPlane(managers[0], auto);
  245. }
  246. /// <summary>
  247. /// Detects the floor plane. Replaces the current floor plane, if there is one, unlike DetectPlaneAtHit().
  248. /// If a floor is detected, also assigns the user's height from the floor to estimatedPlayerHeight.
  249. /// <para>Note that this can't be called the first frame the ZED is ready. Use a coroutine to wait one frame,
  250. /// or until ZEDManager.isZEDReady is true.</para>
  251. /// </summary>
  252. /// <returns><c>true</c>, if floor plane was detected, <c>false</c> otherwise.</returns>
  253. public bool DetectFloorPlane(ZEDManager manager, bool auto)
  254. {
  255. if (!manager.IsZEDReady)
  256. return false; //Do nothing if the ZED isn't finished initializing.
  257. sl.ZEDCamera zedcam = manager.zedCamera;
  258. Camera cam = manager.GetMainCamera();
  259. ZEDPlaneGameObject.PlaneData plane = new ZEDPlaneGameObject.PlaneData();
  260. if (zedcam.findFloorPlane(ref plane, out estimatedPlayerHeight, Quaternion.identity, Vector3.zero) == sl.ERROR_CODE.SUCCESS) //We found a plane.
  261. {
  262. int numVertices, numTriangles = 0;
  263. zedcam.convertFloorPlaneToMesh(planeMeshVertices, planeMeshTriangles, out numVertices, out numTriangles);
  264. if (numVertices > 0 && numTriangles > 0)
  265. {
  266. Vector3[] worldPlaneVertices = new Vector3[numVertices];
  267. int[] worldPlaneTriangles = new int[numTriangles];
  268. TransformCameraToLocalMesh(cam.transform, planeMeshVertices, planeMeshTriangles, worldPlaneVertices, worldPlaneTriangles, numVertices, numTriangles, plane.PlaneCenter);
  269. hasDetectedFloor = true;
  270. if (!floorPlaneGO)
  271. { //Make the GameObject.
  272. floorPlaneGO = new GameObject("Floor Plane");
  273. floorPlaneGO.transform.SetParent(holder.transform);
  274. }
  275. if (!floorPlaneGO) //Make the GameObject.
  276. {
  277. floorPlaneGO = new GameObject("Floor Plane");
  278. floorPlaneGO.transform.SetParent(holder.transform);
  279. }
  280. //Move the GameObject to the center of the plane. Note that the plane data's center is relative to the camera.
  281. floorPlaneGO.transform.position = cam.transform.position; //Add the camera's world position
  282. floorPlaneGO.transform.position += cam.transform.rotation * plane.PlaneCenter; //Add the center of the plane
  283. if (!floorPlane) //Add a new ZEDPlaneGameObject to the floor plane if it doesn't already exist.
  284. {
  285. floorPlane = floorPlaneGO.AddComponent<ZEDPlaneGameObject>();
  286. }
  287. if (!floorPlane.IsCreated) //Call ZEDPlaneGameObject.Create() on the floor ZEDPlaneGameObject if it hasn't yet been run.
  288. {
  289. if (overrideMaterial != null) floorPlane.Create(cam, plane, worldPlaneVertices, worldPlaneTriangles, 0, overrideMaterial);
  290. else floorPlane.Create(cam, plane, worldPlaneVertices, worldPlaneTriangles, 0);
  291. floorPlane.SetPhysics(addPhysicsOption);
  292. }
  293. else //Update the ZEDPlaneGameObject with the new plane's data.
  294. {
  295. floorPlane.UpdateFloorPlane(!auto, plane, worldPlaneVertices, worldPlaneTriangles, overrideMaterial);
  296. floorPlane.SetPhysics(addPhysicsOption);
  297. }
  298. return true;
  299. }
  300. }
  301. return false;
  302. }
  303. /// <summary>
  304. /// Detects the plane around screen-space coordinates specified.
  305. /// <para>Uses the first available ZEDManager in the scene.</para>
  306. /// </summary>
  307. /// <returns><c>true</c>, if plane at hit was detected, <c>false</c> otherwise.</returns>
  308. /// <param name="screenPos">Position of the pixel in screen space (2D).</param>
  309. public bool DetectPlaneAtHit(Vector2 screenPos)
  310. {
  311. //Find the first available ZEDManager.
  312. List<ZEDManager> managers = ZEDManager.GetInstances();
  313. if (managers.Count == 0) return false; //No ZEDManager to use.
  314. else if (managers.Count > 1) //They're using multiple cameras but using the first available manager. Not ideal.
  315. {
  316. Debug.LogWarning("Using DetectPlaneAtHit without specifying a manager while multiple ZEDManagers are present. " +
  317. "This can cause planes to be calculated by the wrong camera. It's recommended to use the (ZEDManager, Vector2) overload.");
  318. }
  319. return DetectPlaneAtHit(managers[0], screenPos);
  320. }
  321. /// <summary>
  322. /// Detects the plane around screen-space coordinates specified.
  323. /// </summary>
  324. /// <returns><c>true</c>, if plane at hit was detected, <c>false</c> otherwise.</returns>
  325. /// <param name="screenPos">Position of the pixel in screen space (2D).</param>
  326. public bool DetectPlaneAtHit(ZEDManager manager, Vector2 screenPos)
  327. {
  328. if (!manager.IsZEDReady)
  329. return false; //Do nothing if the ZED isn't finished initializing.
  330. sl.ZEDCamera zedcam = manager.zedCamera;
  331. Camera cam = manager.GetMainCamera();
  332. ZEDPlaneGameObject.PlaneData plane = new ZEDPlaneGameObject.PlaneData();
  333. if (zedcam.findPlaneAtHit(ref plane, screenPos) == sl.ERROR_CODE.SUCCESS) //We found a plane.
  334. {
  335. int numVertices, numTriangles = 0;
  336. zedcam.convertHitPlaneToMesh(planeMeshVertices, planeMeshTriangles, out numVertices, out numTriangles);
  337. if (numVertices > 0 && numTriangles > 0)
  338. {
  339. GameObject newhitGO = new GameObject(); //Make a new GameObject to hold the new plane.
  340. newhitGO.transform.SetParent(holder.transform);
  341. Vector3[] worldPlaneVertices = new Vector3[numVertices];
  342. int[] worldPlaneTriangles = new int[numTriangles];
  343. TransformCameraToLocalMesh(cam.transform, planeMeshVertices, planeMeshTriangles, worldPlaneVertices, worldPlaneTriangles, numVertices, numTriangles, plane.PlaneCenter);
  344. //Move the GameObject to the center of the plane. Note that the plane data's center is relative to the camera.
  345. newhitGO.transform.position = cam.transform.position; //Add the camera's world position
  346. newhitGO.transform.position += cam.transform.rotation * plane.PlaneCenter; //Add the center of the plane
  347. ZEDPlaneGameObject hitPlane = newhitGO.AddComponent<ZEDPlaneGameObject>();
  348. if (overrideMaterial != null) hitPlane.Create(cam, plane, worldPlaneVertices, worldPlaneTriangles, planeHitCount + 1, overrideMaterial);
  349. else hitPlane.Create(cam, plane, worldPlaneVertices, worldPlaneTriangles, planeHitCount + 1);
  350. hitPlane.SetPhysics(addPhysicsOption);
  351. //hitPlane.SetVisible(isVisibleInSceneOption);
  352. hitPlaneList.Add(hitPlane);
  353. planeHitCount++;
  354. return true;
  355. }
  356. }
  357. return false;
  358. }
  359. /// <summary>
  360. /// Check if the screen was clicked. If so, check for a plane where the click happened using DetectPlaneAtHit().
  361. /// </summary>
  362. void Update()
  363. {
  364. //Detect hits when you click on the screen.
  365. if (Input.GetMouseButtonDown(0))
  366. {
  367. Vector2 ScreenPosition = Input.mousePosition;
  368. List<ZEDManager> managers = ZEDManager.GetInstances();
  369. if (managers.Count == 1) //There's only one ZEDManager, so use that one.
  370. DetectPlaneAtHit(managers[0], ScreenPosition);
  371. else if (managers.Count > 1)
  372. {
  373. //There are at least two ZEDManagers rendering. Find the one that's likely the last to render, so it's the one the user clicked on.
  374. float highestdepth = Mathf.NegativeInfinity;
  375. ZEDManager highestmanager = managers[0];
  376. foreach (ZEDManager manager in managers)
  377. {
  378. float depth = manager.GetMainCamera().depth;
  379. if (depth >= highestdepth)
  380. {
  381. highestdepth = depth;
  382. highestmanager = manager;
  383. }
  384. }
  385. DetectPlaneAtHit(highestmanager, ScreenPosition);
  386. }
  387. }
  388. //Update plane physics if needed.
  389. if (willUpdatePhysics)
  390. {
  391. if (floorPlane != null && floorPlane.IsCreated)
  392. {
  393. floorPlane.SetPhysics(addPhysicsOption);
  394. }
  395. if (hitPlaneList != null)
  396. {
  397. foreach (ZEDPlaneGameObject c in hitPlaneList)
  398. {
  399. if (c.IsCreated)
  400. c.SetPhysics(addPhysicsOption);
  401. }
  402. }
  403. willUpdatePhysics = false;
  404. }
  405. //Update visibility if needed.
  406. if (willUpdateSceneVisibility)
  407. {
  408. /*if (floorPlane != null && floorPlane.IsCreated)
  409. {
  410. floorPlane.SetVisible(isVisibleInSceneOption);
  411. }
  412. if (hitPlaneList != null)
  413. {
  414. foreach (ZEDPlaneGameObject c in hitPlaneList)
  415. {
  416. c.SetVisible(isVisibleInSceneOption);
  417. }
  418. }*/
  419. SwitchSceneDisplay();
  420. willUpdateSceneVisibility = false;
  421. }
  422. //Update in-game visibility if needed.
  423. if (willUpdateGameVisibility)
  424. {
  425. SwitchGameDisplay();
  426. willUpdateGameVisibility = false;
  427. }
  428. }
  429. /// <summary>
  430. /// Switches the isGameDisplay setting, used to know if planes should be rendered to the Scene window.
  431. /// </summary>
  432. public void SwitchSceneDisplay()
  433. {
  434. isSceneDisplay = isVisibleInSceneOption;
  435. }
  436. /// <summary>
  437. /// Switches the isGameDisplay setting, used to know if planes should be rendered to the Game window.
  438. /// </summary>
  439. public void SwitchGameDisplay()
  440. {
  441. isGameDisplay = isVisibleInGameOption;
  442. }
  443. #if UNITY_EDITOR
  444. /// <summary>
  445. /// Called when the Inspector is visible or changes. Updates plane physics and visibility settings.
  446. /// </summary>
  447. void OnValidate()
  448. {
  449. if (floorPlane != null && floorPlane.IsCreated)
  450. {
  451. floorPlane.SetPhysics(addPhysicsOption);
  452. //floorPlane.SetVisible(isVisibleInSceneOption);
  453. }
  454. if (hitPlaneList != null)
  455. foreach (ZEDPlaneGameObject c in hitPlaneList)
  456. {
  457. if (c.IsCreated)
  458. c.SetPhysics(addPhysicsOption);
  459. //c.SetVisible(isVisibleInSceneOption);
  460. }
  461. SwitchSceneDisplay();
  462. SwitchGameDisplay();
  463. }
  464. #endif
  465. }
  466. #if UNITY_EDITOR
  467. /// <summary>
  468. /// Custom Inspector editor for ZEDPlaneDetectionManager.
  469. /// Adds a button to detect the floor, and causes planes to get updated instantly when their visibility settings change.
  470. /// </summary>
  471. [CustomEditor(typeof(ZEDPlaneDetectionManager))]
  472. public class ZEDPlaneDetectionEditor : Editor
  473. {
  474. /// <summary>
  475. /// The ZEDPlaneDetectionManager component that this editor is displaying.
  476. /// </summary>
  477. private ZEDPlaneDetectionManager planeDetector;
  478. // private GUILayoutOption[] optionsButtonBrowse = { GUILayout.MaxWidth(30) };
  479. /// <summary>
  480. /// Serializable version of ZEDPlaneDetectionManager's addPhysicsOption property.
  481. /// </summary>
  482. private SerializedProperty addPhysicsOption;
  483. /// <summary>
  484. /// Serializable version of ZEDPlaneDetectionManager's isVisibleInSceneOption property.
  485. /// </summary>
  486. private SerializedProperty isVisibleInSceneOption;
  487. /// <summary>
  488. /// Serializable version of ZEDPlaneDetectionManager's isVisibleInGameOption property.
  489. /// </summary>
  490. private SerializedProperty isVisibleInGameOption;
  491. /// <summary>
  492. /// Serializable version of ZEDPlaneDetectionManager's overrideMaterialOption property.
  493. /// </summary>
  494. private SerializedProperty overrideMaterialOption;
  495. private ZEDPlaneDetectionManager Target
  496. {
  497. get { return (ZEDPlaneDetectionManager)target; }
  498. }
  499. public void OnEnable()
  500. {
  501. //Assign the serialized properties to their appropriate properties.
  502. planeDetector = (ZEDPlaneDetectionManager)target;
  503. addPhysicsOption = serializedObject.FindProperty("addPhysicsOption");
  504. isVisibleInSceneOption = serializedObject.FindProperty("isVisibleInSceneOption");
  505. isVisibleInGameOption = serializedObject.FindProperty("isVisibleInGameOption");
  506. overrideMaterialOption = serializedObject.FindProperty("overrideMaterial");
  507. }
  508. public override void OnInspectorGUI()
  509. {
  510. //bool cameraIsReady = planeDetector.Manager != null ? planeDetector.Manager.zedCamera.IsCameraReady : false;
  511. serializedObject.Update();
  512. GUILayout.Space(20);
  513. EditorGUILayout.BeginHorizontal();
  514. GUILayout.Label("Detection Parameters", EditorStyles.boldLabel);
  515. GUILayout.FlexibleSpace();
  516. EditorGUILayout.EndHorizontal();
  517. //GUI.enabled = cameraIsReady;
  518. EditorGUILayout.BeginHorizontal();
  519. GUIContent floordetectionlabel = new GUIContent("Single-shot Floor Detection", "Attempt to detect a floor plane in the current view.");
  520. GUILayout.Label(floordetectionlabel); GUILayout.Space(20);
  521. GUIContent floordetectbuttonlabel = new GUIContent("Detect", "Attempt to detect a floor plane in the current view.");
  522. if (GUILayout.Button(floordetectbuttonlabel))
  523. {
  524. planeDetector.DetectFloorPlane(false);
  525. }
  526. GUILayout.FlexibleSpace();
  527. EditorGUILayout.EndHorizontal();
  528. GUI.enabled = true;
  529. GUILayout.Space(20);
  530. EditorGUILayout.BeginHorizontal();
  531. GUILayout.Label("Visualization", EditorStyles.boldLabel);
  532. GUILayout.FlexibleSpace();
  533. EditorGUILayout.EndHorizontal();
  534. GUIContent visiblescenelabel = new GUIContent("Visible in Scene", "Whether the planes are drawn in Unity's Scene view.");
  535. GUIContent visiblegamelabel = new GUIContent("Visible in Game", "Whether the planes are drawn in Unity's Game view.");
  536. isVisibleInSceneOption.boolValue = EditorGUILayout.Toggle(visiblescenelabel, isVisibleInSceneOption.boolValue);
  537. #if !UNITY_2018_1_OR_NEWER
  538. if (!isVisibleInSceneOption.boolValue)
  539. {
  540. //Older Unity versions have a bug that will spam errors if Visible In Scene is disabled. Warn the user.
  541. GUIStyle warningmessagestyle = new GUIStyle(EditorStyles.label);
  542. warningmessagestyle.normal.textColor = Color.gray;
  543. warningmessagestyle.wordWrap = true;
  544. warningmessagestyle.fontSize = 9;
  545. string warningtext = "Warning: Disabling Visible in Scene causes Unity versions 2017 and lower to spam error messages. This is due to a Unity bug and does not effect the scene.";
  546. Rect labelrect = GUILayoutUtility.GetRect(new GUIContent(warningtext, ""), warningmessagestyle);
  547. EditorGUI.LabelField(labelrect, warningtext, warningmessagestyle);
  548. }
  549. #endif
  550. isVisibleInGameOption.boolValue = EditorGUILayout.Toggle(visiblegamelabel, isVisibleInGameOption.boolValue);
  551. GUIContent overridematlabel = new GUIContent("Override Material: ", "Material applied to all planes if visible. If left empty, default materials will be applied depending on the plane type.");
  552. planeDetector.overrideMaterial = (Material)EditorGUILayout.ObjectField(overridematlabel, planeDetector.overrideMaterial, typeof(Material), false);
  553. planeDetector.SwitchGameDisplay();
  554. GUILayout.Space(20);
  555. GUI.enabled = true;
  556. EditorGUILayout.BeginHorizontal();
  557. GUILayout.Label("Physics", EditorStyles.boldLabel);
  558. GUILayout.FlexibleSpace();
  559. EditorGUILayout.EndHorizontal();
  560. GUIContent physicslabel = new GUIContent("Collisions", "Whether the planes can be collided with using physics.");
  561. addPhysicsOption.boolValue = EditorGUILayout.Toggle(physicslabel, addPhysicsOption.boolValue);
  562. serializedObject.ApplyModifiedProperties(); //Applies all changes to serializedproperties to the actual properties they're connected to.
  563. //if (!cameraIsReady) Repaint();
  564. Repaint();
  565. }
  566. }
  567. #endif