BoundingBox.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  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. AxisMove = 1 << 4
  370. }
  371. [Flags]
  372. public enum AxisType
  373. {
  374. None = 1 << 0,
  375. X = 1 << 1,
  376. Y = 1 << 2,
  377. Z = 1 << 3,
  378. NX = 1 << 4,
  379. NY = 1 << 5,
  380. NZ = 1 << 6,
  381. }
  382. /// <summary>
  383. /// Enum which describes how an object's BoundingBox is to be flattened.
  384. /// </summary>
  385. public enum FlattenModeType
  386. {
  387. DoNotFlatten = 0,
  388. /// <summary>
  389. /// Flatten the X axis
  390. /// </summary>
  391. FlattenX,
  392. /// <summary>
  393. /// Flatten the Y axis
  394. /// </summary>
  395. FlattenY,
  396. /// <summary>
  397. /// Flatten the Z axis
  398. /// </summary>
  399. FlattenZ,
  400. /// <summary>
  401. /// Flatten the smallest relative axis if it falls below threshold
  402. /// </summary>
  403. FlattenAuto,
  404. }
  405. /// <summary>
  406. /// This enum defines how the BoundingBox gets activated
  407. /// </summary>
  408. public enum BoundingBoxActivationType
  409. {
  410. ActivateOnStart = 0,
  411. ActivateByPointer,
  412. }
  413. public class Handle
  414. {
  415. /// <summary>
  416. /// Handle Type
  417. /// </summary>
  418. public HandleType type;
  419. /// <summary>
  420. /// Handle Root Gameobject
  421. /// </summary>
  422. public Transform root;
  423. /// <summary>
  424. /// Handle bounds
  425. /// </summary>
  426. public Bounds bounds;
  427. public Vector3 localPosition;
  428. public Transform visualsScale;
  429. public GameObject visual;
  430. public void SetActive(bool active)
  431. {
  432. root.gameObject.SetActive(active);
  433. }
  434. }
  435. #endregion
  436. #region Unity Lifecycle Function
  437. // Start is called before the first frame update
  438. void Start()
  439. {
  440. Init();
  441. }
  442. private void OnValidate()
  443. {
  444. Redraw();
  445. }
  446. #endregion
  447. private void Init()
  448. {
  449. CreatBoundingBoxRoot(flattenAxis);
  450. BoundingBoxRoot = new BoundingBoxRoot(this);
  451. CornerBoundingBoxRoot = new CornerBoundingBoxRoot(this);
  452. SideBoundingBoxRoot = new SideBoundingBoxRoot(this);
  453. FaceBoundingBoxRoot = new FaceBoundingBoxRoot(this);
  454. BoundingBoxRoot.Init();
  455. CornerBoundingBoxRoot.Init();
  456. SideBoundingBoxRoot.Init();
  457. FaceBoundingBoxRoot.Init();
  458. if (BoundingBoxRootList == null)
  459. {
  460. BoundingBoxRootList = new List<IBoundingBoxRoot>();
  461. BoundingBoxRootList.Add(BoundingBoxRoot);
  462. BoundingBoxRootList.Add(CornerBoundingBoxRoot);
  463. BoundingBoxRootList.Add(SideBoundingBoxRoot);
  464. BoundingBoxRootList.Add(FaceBoundingBoxRoot);
  465. }
  466. if (ActivationType == BoundingBoxActivationType.ActivateOnStart)
  467. {
  468. SetVisibility(true);
  469. }
  470. else
  471. {
  472. SetVisibility(false);
  473. }
  474. }
  475. private void CreatBoundingBoxRoot(FlattenModeType flattenMode)
  476. {
  477. RecaculateBounds();
  478. }
  479. private void Redraw()
  480. {
  481. if (BoundingBoxRootList == null)
  482. {
  483. return;
  484. }
  485. RecaculateBounds();
  486. for (int i = 0; i < BoundingBoxRootList.Count; i++)
  487. {
  488. IBoundingBoxRoot boundingBoxRoot = BoundingBoxRootList[i];
  489. boundingBoxRoot.ReDraw();
  490. }
  491. }
  492. private void RecaculateBounds()
  493. {
  494. // Make sure that the bounds of all child objects are up to date before we compute bounds
  495. Physics.SyncTransforms();
  496. BoundBoxCollider = GetComponent<BoxCollider>();
  497. if (BoundBoxCollider == null)
  498. {
  499. Debug.Log("Error! Please Add BoxCollider And Adjust Size For BoundingBoxGameobject");
  500. return;
  501. }
  502. // Store current rotation then zero out the rotation so that the bounds
  503. // are computed when the object is in its 'axis aligned orientation'.
  504. Quaternion currentRotation = transform.rotation;
  505. transform.rotation = Quaternion.identity;
  506. Physics.SyncTransforms(); // Update collider bounds
  507. currentBoundsExtents = BoundBoxCollider.bounds.extents;
  508. boundingBoxInitScale = BoundBoxCollider.transform.lossyScale;
  509. // After bounds are computed, restore rotation...
  510. transform.rotation = currentRotation;
  511. Physics.SyncTransforms();
  512. if (currentBoundsExtents != Vector3.zero)
  513. {
  514. if (FlattenAxis == FlattenModeType.FlattenAuto)
  515. {
  516. float min = Mathf.Min(currentBoundsExtents.x, Mathf.Min(currentBoundsExtents.y, currentBoundsExtents.z));
  517. flattenAxis = (min == currentBoundsExtents.x) ? FlattenModeType.FlattenX :
  518. ((min == currentBoundsExtents.y) ? FlattenModeType.FlattenY : FlattenModeType.FlattenZ);
  519. }
  520. currentBoundsExtents.x = (flattenAxis == FlattenModeType.FlattenX) ? 0.0f : currentBoundsExtents.x;
  521. currentBoundsExtents.y = (flattenAxis == FlattenModeType.FlattenY) ? 0.0f : currentBoundsExtents.y;
  522. currentBoundsExtents.z = (flattenAxis == FlattenModeType.FlattenZ) ? 0.0f : currentBoundsExtents.z;
  523. Transform existContainerTransform = this.transform.Find(GetType().ToString());
  524. if (existContainerTransform != null)
  525. {
  526. #if UNITY_EDITOR
  527. GameObject.Destroy(existContainerTransform.gameObject);
  528. #else
  529. GameObject.DestroyImmediate(existContainerTransform.gameObject);
  530. #endif
  531. }
  532. BoundingBoxContainer = new GameObject(GetType().ToString()).transform;
  533. BoundingBoxContainer.parent = transform;
  534. BoundingBoxContainer.position = BoundBoxCollider.bounds.center;
  535. BoundingBoxContainer.localRotation = Quaternion.identity;
  536. }
  537. }
  538. public void SetVisibility(bool isVisible)
  539. {
  540. for (int i = 0; i < BoundingBoxRootList.Count; i++)
  541. {
  542. IBoundingBoxRoot boundingBoxRoot = BoundingBoxRootList[i];
  543. boundingBoxRoot.SetVisible(isVisible);
  544. }
  545. }
  546. public void SetHighLight(Transform activeHandle, bool hideOtherHandle)
  547. {
  548. for (int i = 0; i < BoundingBoxRootList.Count; i++)
  549. {
  550. IBoundingBoxRoot boundingBoxRoot = BoundingBoxRootList[i];
  551. boundingBoxRoot.SetHighLight(activeHandle, hideOtherHandle);
  552. }
  553. }
  554. #region BoundingBox PointerEvent
  555. public void OnPointerEnter(PointerEventData eventData)
  556. {
  557. SCPointEventData scPointEventData = eventData as SCPointEventData;
  558. if (scPointEventData == null)
  559. {
  560. return;
  561. }
  562. if (scPointEventData.DownPressGameObject == null)
  563. {
  564. SetVisibility(true);
  565. }
  566. }
  567. public void OnPointerExit(PointerEventData eventData)
  568. {
  569. SCPointEventData scPointEventData = eventData as SCPointEventData;
  570. if (scPointEventData == null)
  571. {
  572. return;
  573. }
  574. if (scPointEventData.DownPressGameObject == null)
  575. {
  576. if (activation == BoundingBoxActivationType.ActivateOnStart)
  577. {
  578. SetVisibility(true);
  579. }
  580. else
  581. {
  582. SetVisibility(false);
  583. }
  584. }
  585. }
  586. public void OnPointerDown(PointerEventData eventData)
  587. {
  588. SCPointEventData scPointEventData = eventData as SCPointEventData;
  589. if (scPointEventData == null)
  590. {
  591. return;
  592. }
  593. SetHighLight(eventData.pointerCurrentRaycast.gameObject.transform, true);
  594. }
  595. public void OnPointerUp(PointerEventData eventData)
  596. {
  597. SCPointEventData scPointEventData = eventData as SCPointEventData;
  598. if (scPointEventData == null)
  599. {
  600. return;
  601. }
  602. if (activation == BoundingBoxActivationType.ActivateOnStart)
  603. {
  604. SetVisibility(true);
  605. }
  606. else
  607. {
  608. SetVisibility(true);
  609. }
  610. }
  611. #endregion
  612. }