BoundingBox.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.EventSystems;
  5. using SC.XR.Unity.Module_InputSystem;
  6. using UnityEngine.Events;
  7. using System;
  8. using SC.XR.Unity;
  9. [AddComponentMenu("SDK/BoundingBox")]
  10. public class BoundingBox : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler
  11. {
  12. [SerializeField]
  13. [Tooltip("Type of activation method for showing/hiding bounding box handles and controls")]
  14. private BoundingBoxActivationType activation = BoundingBoxActivationType.ActivateOnStart;
  15. public BoundingBoxActivationType ActivationType
  16. {
  17. get
  18. {
  19. return activation;
  20. }
  21. }
  22. [SerializeField]
  23. [Tooltip("Flatten bounds in the specified axis or flatten the smallest one if 'auto' is selected")]
  24. private FlattenModeType flattenAxis = FlattenModeType.DoNotFlatten;
  25. public FlattenModeType FlattenAxis
  26. {
  27. get
  28. {
  29. return flattenAxis;
  30. }
  31. set
  32. {
  33. flattenAxis = value;
  34. Redraw();
  35. }
  36. }
  37. [SerializeField]
  38. private HandleType activeHandle = ~HandleType.None;
  39. public HandleType ActiveHandle
  40. {
  41. get
  42. {
  43. return activeHandle;
  44. }
  45. set
  46. {
  47. activeHandle = value;
  48. Redraw();
  49. }
  50. }
  51. [SerializeField]
  52. private BoundingBoxAssets m_HandlerAssets;
  53. public BoundingBoxAssets BoundingBoxAssets {
  54. get {
  55. if (m_HandlerAssets == null) {
  56. m_HandlerAssets = Resources.Load<BoundingBoxAssets>("HandlerAssets/DefaultAssets");
  57. }
  58. return m_HandlerAssets;
  59. }
  60. }
  61. //[SerializeField]
  62. //[AssetPreAssign("Assets/SDK/Common/StandardAssets/Materials/BoundingBox.mat", typeof(Material))]
  63. private Material m_boxFocusDisplayMat;
  64. public Material boxFocusDisplayMat {
  65. get {
  66. if (m_boxFocusDisplayMat == null) {
  67. if (BoundingBoxAssets) {
  68. m_boxFocusDisplayMat = BoundingBoxAssets.boxFocusDisplayMat;
  69. }
  70. }
  71. return m_boxFocusDisplayMat;
  72. }
  73. }
  74. //[SerializeField]
  75. //[AssetPreAssign("Assets/SDK/Common/StandardAssets/Materials/BoundingBoxGrabbed.mat", typeof(Material))]
  76. private Material m_boxGrabDisplayMat;
  77. public Material boxGrabDisplayMat {
  78. get {
  79. if (m_boxGrabDisplayMat == null) {
  80. if (BoundingBoxAssets) {
  81. m_boxGrabDisplayMat = BoundingBoxAssets.boxGrabDisplayMat;
  82. }
  83. }
  84. return m_boxGrabDisplayMat;
  85. }
  86. }
  87. //[SerializeField]
  88. //[AssetPreAssign("Assets/SDK/Common/StandardAssets/Materials/BoundingBoxHandleWhite.mat", typeof(Material))]
  89. private Material m_HandleMaterial;
  90. public Material HandleMaterial {
  91. get {
  92. if (m_HandleMaterial == null) {
  93. if (BoundingBoxAssets) {
  94. m_HandleMaterial = BoundingBoxAssets.HandleMaterial;
  95. }
  96. }
  97. return m_HandleMaterial;
  98. }
  99. }
  100. //[SerializeField]
  101. //[AssetPreAssign("Assets/SDK/Common/StandardAssets/Materials/BoundingBoxHandleBlueGrabbed.mat", typeof(Material))]
  102. private Material m_HandleGrabMaterial;
  103. public Material HandleGrabMaterial {
  104. get {
  105. if (m_HandleGrabMaterial == null) {
  106. if (BoundingBoxAssets) {
  107. m_HandleGrabMaterial = BoundingBoxAssets.HandleGrabMaterial;
  108. }
  109. }
  110. return m_HandleGrabMaterial;
  111. }
  112. }
  113. //[SerializeField]
  114. //[Header("Scale Handles")]
  115. //[AssetPreAssign("Assets/SDK/Common/StandardAssets/Prefabs/BoundingBox_ScaleHandle.prefab", typeof(GameObject))]
  116. private GameObject m_CornerPrefab;
  117. public GameObject CornerPrefab {
  118. get {
  119. if (m_CornerPrefab == null) {
  120. if (BoundingBoxAssets) {
  121. m_CornerPrefab = BoundingBoxAssets.CornerPrefab;
  122. }
  123. }
  124. return m_CornerPrefab;
  125. }
  126. }
  127. //[SerializeField]
  128. //[AssetPreAssign("Assets/SDK/Common/StandardAssets/Prefabs/BoundingBox_ScaleHandle_Slate.prefab", typeof(GameObject))]
  129. private GameObject m_CornerSlatePrefab;
  130. public GameObject CornerSlatePrefab {
  131. get {
  132. if (m_CornerSlatePrefab == null) {
  133. if (BoundingBoxAssets) {
  134. m_CornerSlatePrefab = BoundingBoxAssets.CornerSlatePrefab;
  135. }
  136. }
  137. return m_CornerSlatePrefab;
  138. }
  139. }
  140. public bool activeScaleMinRestrict = true;
  141. [Tooltip("Minimum scaling allowed relative to the world size Unit of m")]
  142. public float scaleMinimum = 0.05f;
  143. public bool activeScaleMaxRestrict = false;
  144. [Tooltip("Maximum scaling allowed relative to the world size Unit of m")]
  145. public float scaleMaximum = 2.0f;
  146. public Vector3 boundingBoxInitScale { get; private set; }
  147. public Vector3 calculateMinScale {
  148. get {
  149. Vector3 temp = (CurrentBoundsExtents * 2 / scaleMinimum);
  150. return new Vector3(boundingBoxInitScale.x / temp.x, boundingBoxInitScale.y / temp.y, boundingBoxInitScale.z / temp.z);
  151. }
  152. }
  153. public Vector3 calculateMaxScale {
  154. get {
  155. Vector3 temp = (CurrentBoundsExtents * 2 / scaleMaximum);
  156. return new Vector3(boundingBoxInitScale.x / temp.x, boundingBoxInitScale.y / temp.y, boundingBoxInitScale.z / temp.z);
  157. }
  158. }
  159. //[SerializeField]
  160. //[Tooltip("Size of the cube collidable used in scale handles")]
  161. //private float scaleHandleSize = 0.016f; // 1.6cm default handle size
  162. //public float ScaleHandleSize
  163. //{
  164. // get
  165. // {
  166. // return scaleHandleSize;
  167. // }
  168. // set
  169. // {
  170. // scaleHandleSize = value;
  171. // Redraw();
  172. // }
  173. //}
  174. [HideInInspector]
  175. private BoxCollider BoundBoxCollider;
  176. // Half the size of the current bounds
  177. private Vector3 currentBoundsExtents;
  178. public Vector3 CurrentBoundsExtents
  179. {
  180. get
  181. {
  182. return currentBoundsExtents;
  183. }
  184. }
  185. //[SerializeField]
  186. //[Header("Rotation Handles")]
  187. //[AssetPreAssign("Assets/SDK/Common/StandardAssets/Prefabs/BoundingBox_RotateHandle.prefab", typeof(GameObject))]
  188. private GameObject m_SidePrefab;
  189. public GameObject SidePrefab {
  190. get {
  191. if (m_SidePrefab == null) {
  192. if (BoundingBoxAssets) {
  193. m_SidePrefab = BoundingBoxAssets.SidePrefab;
  194. }
  195. }
  196. return m_SidePrefab;
  197. }
  198. }
  199. //[SerializeField]
  200. //[Tooltip("Radius of the handle geometry of rotation handles")]
  201. //private float rotationHandleSize = 0.016f; // 1.6cm default handle size
  202. //public float RotationHandleSize
  203. //{
  204. // get
  205. // {
  206. // return rotationHandleSize;
  207. // }
  208. // set
  209. // {
  210. // rotationHandleSize = value;
  211. // Redraw();
  212. // }
  213. //}
  214. [SerializeField]
  215. [Tooltip("Check to show rotation handles for the X axis")]
  216. private bool showRotationHandleForX = true;
  217. public bool ShowRotationHandleForX
  218. {
  219. get
  220. {
  221. return showRotationHandleForX;
  222. }
  223. set
  224. {
  225. showRotationHandleForX = value;
  226. Redraw();
  227. }
  228. }
  229. [SerializeField]
  230. [Tooltip("Check to show rotation handles for the Y axis")]
  231. private bool showRotationHandleForY = true;
  232. public bool ShowRotationHandleForY
  233. {
  234. get
  235. {
  236. return showRotationHandleForY;
  237. }
  238. set
  239. {
  240. showRotationHandleForY = value;
  241. Redraw();
  242. }
  243. }
  244. [SerializeField]
  245. [Tooltip("Check to show rotation handles for the Z axis")]
  246. private bool showRotationHandleForZ = true;
  247. public bool ShowRotationHandleForZ
  248. {
  249. get
  250. {
  251. return showRotationHandleForZ;
  252. }
  253. set
  254. {
  255. showRotationHandleForZ = value;
  256. Redraw();
  257. }
  258. }
  259. //[SerializeField]
  260. //[Header("AxisScale Handles")]
  261. private GameObject m_facePrefab;
  262. public GameObject facePrefab {
  263. get {
  264. if (m_facePrefab == null) {
  265. if (BoundingBoxAssets) {
  266. m_facePrefab = BoundingBoxAssets.facePrefab;
  267. }
  268. }
  269. return m_facePrefab;
  270. }
  271. }
  272. //[SerializeField]
  273. //[Tooltip("Radius of the handle geometry of rotation handles")]
  274. //private float axisScaleHandleSize = 0.016f; // 1.6cm default handle size
  275. //public float AxisScaleHandleSize
  276. //{
  277. // get
  278. // {
  279. // return axisScaleHandleSize;
  280. // }
  281. // set
  282. // {
  283. // axisScaleHandleSize = value;
  284. // Redraw();
  285. // }
  286. //}
  287. [SerializeField]
  288. private AxisType activeAxis = ~AxisType.None;
  289. public AxisType ActiveAxis
  290. {
  291. get
  292. {
  293. return activeAxis;
  294. }
  295. set
  296. {
  297. activeAxis = value;
  298. Redraw();
  299. }
  300. }
  301. public Transform BoundingBoxContainer
  302. {
  303. get;
  304. set;
  305. }
  306. public BoundingBoxRoot BoundingBoxRoot
  307. {
  308. get;
  309. private set;
  310. }
  311. public CornerBoundingBoxRoot CornerBoundingBoxRoot
  312. {
  313. get;
  314. private set;
  315. }
  316. private SideBoundingBoxRoot SideBoundingBoxRoot
  317. {
  318. get;
  319. set;
  320. }
  321. private FaceBoundingBoxRoot FaceBoundingBoxRoot
  322. {
  323. get;
  324. set;
  325. }
  326. private List<IBoundingBoxRoot> BoundingBoxRootList
  327. {
  328. get;
  329. set;
  330. }
  331. [Header("Audio")]
  332. [SerializeField]
  333. public SCAudiosConfig.AudioType RotateStartAudio = SCAudiosConfig.AudioType.Manipulation_Start;
  334. [SerializeField]
  335. public SCAudiosConfig.AudioType RotateStopAudio = SCAudiosConfig.AudioType.Manipulation_End;
  336. [SerializeField]
  337. public SCAudiosConfig.AudioType ScaleStartAudio = SCAudiosConfig.AudioType.Manipulation_Start;
  338. [SerializeField]
  339. public SCAudiosConfig.AudioType ScaleStopAudio = SCAudiosConfig.AudioType.Manipulation_End;
  340. [Header("Events")]
  341. /// <summary>
  342. /// Event that gets fired when interaction with a rotation handle starts.
  343. /// </summary>
  344. public UnityEvent RotateStarted = new UnityEvent();
  345. /// <summary>
  346. /// Event that gets fired when interaction with a rotation handle stops.
  347. /// </summary>
  348. public UnityEvent RotateStopped = new UnityEvent();
  349. /// <summary>
  350. /// Event that gets fired when interaction with a scale handle starts.
  351. /// </summary>
  352. public UnityEvent ScaleStarted = new UnityEvent();
  353. /// <summary>
  354. /// Event that gets fired when interaction with a scale handle stops.
  355. /// </summary>
  356. public UnityEvent ScaleStopped = new UnityEvent();
  357. #region Class & Enum Define
  358. /// <summary>
  359. /// Enum which describes whether a BoundingBox handle which has been grabbed, is
  360. /// a Rotation Handle (sphere) or a Scale Handle( cube)
  361. /// </summary>
  362. [Flags]
  363. public enum HandleType
  364. {
  365. None = 1 << 0,
  366. Rotation = 1 << 1,
  367. Scale = 1 << 2,
  368. AxisScale = 1 << 3,
  369. }
  370. [Flags]
  371. public enum AxisType
  372. {
  373. None = 1 << 0,
  374. X = 1 << 1,
  375. Y = 1 << 2,
  376. Z = 1 << 3,
  377. NX = 1 << 4,
  378. NY = 1 << 5,
  379. NZ = 1 << 6,
  380. }
  381. /// <summary>
  382. /// Enum which describes how an object's BoundingBox is to be flattened.
  383. /// </summary>
  384. public enum FlattenModeType
  385. {
  386. DoNotFlatten = 0,
  387. /// <summary>
  388. /// Flatten the X axis
  389. /// </summary>
  390. FlattenX,
  391. /// <summary>
  392. /// Flatten the Y axis
  393. /// </summary>
  394. FlattenY,
  395. /// <summary>
  396. /// Flatten the Z axis
  397. /// </summary>
  398. FlattenZ,
  399. /// <summary>
  400. /// Flatten the smallest relative axis if it falls below threshold
  401. /// </summary>
  402. FlattenAuto,
  403. }
  404. /// <summary>
  405. /// This enum defines how the BoundingBox gets activated
  406. /// </summary>
  407. public enum BoundingBoxActivationType
  408. {
  409. ActivateOnStart = 0,
  410. ActivateByPointer,
  411. }
  412. public class Handle
  413. {
  414. /// <summary>
  415. /// Handle Type
  416. /// </summary>
  417. public HandleType type;
  418. /// <summary>
  419. /// Handle Root Gameobject
  420. /// </summary>
  421. public Transform root;
  422. /// <summary>
  423. /// Handle bounds
  424. /// </summary>
  425. public Bounds bounds;
  426. public Vector3 localPosition;
  427. public Transform visualsScale;
  428. public GameObject visual;
  429. public void SetActive(bool active)
  430. {
  431. root.gameObject.SetActive(active);
  432. }
  433. }
  434. #endregion
  435. #region Unity Lifecycle Function
  436. // Start is called before the first frame update
  437. void Start()
  438. {
  439. Init();
  440. }
  441. private void OnValidate()
  442. {
  443. Redraw();
  444. }
  445. #endregion
  446. private void Init()
  447. {
  448. CreatBoundingBoxRoot(flattenAxis);
  449. BoundingBoxRoot = new BoundingBoxRoot(this);
  450. CornerBoundingBoxRoot = new CornerBoundingBoxRoot(this);
  451. SideBoundingBoxRoot = new SideBoundingBoxRoot(this);
  452. FaceBoundingBoxRoot = new FaceBoundingBoxRoot(this);
  453. BoundingBoxRoot.Init();
  454. CornerBoundingBoxRoot.Init();
  455. SideBoundingBoxRoot.Init();
  456. FaceBoundingBoxRoot.Init();
  457. if (BoundingBoxRootList == null)
  458. {
  459. BoundingBoxRootList = new List<IBoundingBoxRoot>();
  460. BoundingBoxRootList.Add(BoundingBoxRoot);
  461. BoundingBoxRootList.Add(CornerBoundingBoxRoot);
  462. BoundingBoxRootList.Add(SideBoundingBoxRoot);
  463. BoundingBoxRootList.Add(FaceBoundingBoxRoot);
  464. }
  465. if (ActivationType == BoundingBoxActivationType.ActivateOnStart)
  466. {
  467. SetVisibility(true);
  468. }
  469. else
  470. {
  471. SetVisibility(false);
  472. }
  473. }
  474. private void CreatBoundingBoxRoot(FlattenModeType flattenMode)
  475. {
  476. RecaculateBounds();
  477. }
  478. private void Redraw()
  479. {
  480. if (BoundingBoxRootList == null)
  481. {
  482. return;
  483. }
  484. RecaculateBounds();
  485. for (int i = 0; i < BoundingBoxRootList.Count; i++)
  486. {
  487. IBoundingBoxRoot boundingBoxRoot = BoundingBoxRootList[i];
  488. boundingBoxRoot.ReDraw();
  489. }
  490. }
  491. private void RecaculateBounds()
  492. {
  493. // Make sure that the bounds of all child objects are up to date before we compute bounds
  494. Physics.SyncTransforms();
  495. BoundBoxCollider = GetComponent<BoxCollider>();
  496. if (BoundBoxCollider == null)
  497. {
  498. Debug.Log("Error! Please Add BoxCollider And Adjust Size For BoundingBoxGameobject");
  499. return;
  500. }
  501. // Store current rotation then zero out the rotation so that the bounds
  502. // are computed when the object is in its 'axis aligned orientation'.
  503. Quaternion currentRotation = transform.rotation;
  504. transform.rotation = Quaternion.identity;
  505. Physics.SyncTransforms(); // Update collider bounds
  506. currentBoundsExtents = BoundBoxCollider.bounds.extents;
  507. boundingBoxInitScale = BoundBoxCollider.transform.lossyScale;
  508. // After bounds are computed, restore rotation...
  509. transform.rotation = currentRotation;
  510. Physics.SyncTransforms();
  511. if (currentBoundsExtents != Vector3.zero)
  512. {
  513. if (FlattenAxis == FlattenModeType.FlattenAuto)
  514. {
  515. float min = Mathf.Min(currentBoundsExtents.x, Mathf.Min(currentBoundsExtents.y, currentBoundsExtents.z));
  516. flattenAxis = (min == currentBoundsExtents.x) ? FlattenModeType.FlattenX :
  517. ((min == currentBoundsExtents.y) ? FlattenModeType.FlattenY : FlattenModeType.FlattenZ);
  518. }
  519. currentBoundsExtents.x = (flattenAxis == FlattenModeType.FlattenX) ? 0.0f : currentBoundsExtents.x;
  520. currentBoundsExtents.y = (flattenAxis == FlattenModeType.FlattenY) ? 0.0f : currentBoundsExtents.y;
  521. currentBoundsExtents.z = (flattenAxis == FlattenModeType.FlattenZ) ? 0.0f : currentBoundsExtents.z;
  522. Transform existContainerTransform = this.transform.Find(GetType().ToString());
  523. if (existContainerTransform != null)
  524. {
  525. #if UNITY_EDITOR
  526. GameObject.Destroy(existContainerTransform.gameObject);
  527. #else
  528. GameObject.DestroyImmediate(existContainerTransform.gameObject);
  529. #endif
  530. }
  531. BoundingBoxContainer = new GameObject(GetType().ToString()).transform;
  532. BoundingBoxContainer.parent = transform;
  533. BoundingBoxContainer.position = BoundBoxCollider.bounds.center;
  534. BoundingBoxContainer.localRotation = Quaternion.identity;
  535. }
  536. }
  537. public void SetVisibility(bool isVisible)
  538. {
  539. for (int i = 0; i < BoundingBoxRootList.Count; i++)
  540. {
  541. IBoundingBoxRoot boundingBoxRoot = BoundingBoxRootList[i];
  542. boundingBoxRoot.SetVisible(isVisible);
  543. }
  544. }
  545. public void SetHighLight(Transform activeHandle, bool hideOtherHandle)
  546. {
  547. for (int i = 0; i < BoundingBoxRootList.Count; i++)
  548. {
  549. IBoundingBoxRoot boundingBoxRoot = BoundingBoxRootList[i];
  550. boundingBoxRoot.SetHighLight(activeHandle, hideOtherHandle);
  551. }
  552. }
  553. #region BoundingBox PointerEvent
  554. public void OnPointerEnter(PointerEventData eventData)
  555. {
  556. SCPointEventData scPointEventData = eventData as SCPointEventData;
  557. if (scPointEventData == null)
  558. {
  559. return;
  560. }
  561. if (scPointEventData.DownPressGameObject == null)
  562. {
  563. SetVisibility(true);
  564. }
  565. }
  566. public void OnPointerExit(PointerEventData eventData)
  567. {
  568. SCPointEventData scPointEventData = eventData as SCPointEventData;
  569. if (scPointEventData == null)
  570. {
  571. return;
  572. }
  573. if (scPointEventData.DownPressGameObject == null)
  574. {
  575. if (activation == BoundingBoxActivationType.ActivateOnStart)
  576. {
  577. SetVisibility(true);
  578. }
  579. else
  580. {
  581. SetVisibility(false);
  582. }
  583. }
  584. }
  585. public void OnPointerDown(PointerEventData eventData)
  586. {
  587. SCPointEventData scPointEventData = eventData as SCPointEventData;
  588. if (scPointEventData == null)
  589. {
  590. return;
  591. }
  592. SetHighLight(eventData.pointerCurrentRaycast.gameObject.transform, true);
  593. }
  594. public void OnPointerUp(PointerEventData eventData)
  595. {
  596. SCPointEventData scPointEventData = eventData as SCPointEventData;
  597. if (scPointEventData == null)
  598. {
  599. return;
  600. }
  601. if (activation == BoundingBoxActivationType.ActivateOnStart)
  602. {
  603. SetVisibility(true);
  604. }
  605. else
  606. {
  607. SetVisibility(true);
  608. }
  609. }
  610. #endregion
  611. }