PlaneSurface.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. using UnityEngine;
  2. namespace Rokid.UXR.Interaction
  3. {
  4. public class PlaneSurface : MonoBehaviour, ISurface, IBounds
  5. {
  6. public enum NormalFacing
  7. {
  8. /// <summary>
  9. /// Normal faces along the transform's negative Z axis
  10. /// </summary>
  11. Backward,
  12. /// <summary>
  13. /// Normal faces along the transform's positive Z axis
  14. /// </summary>
  15. Forward,
  16. }
  17. [SerializeField]
  18. private NormalFacing _facing = NormalFacing.Backward;
  19. [SerializeField, Tooltip("Raycasts hit either side of plane, but hit normal " +
  20. "will still respect plane facing.")]
  21. private bool _doubleSided = false;
  22. public NormalFacing Facing
  23. {
  24. get => _facing;
  25. set => _facing = value;
  26. }
  27. public bool DoubleSided
  28. {
  29. get => _doubleSided;
  30. set => _doubleSided = value;
  31. }
  32. public Vector3 Normal
  33. {
  34. get
  35. {
  36. return _facing == NormalFacing.Forward ?
  37. transform.forward :
  38. -transform.forward;
  39. }
  40. }
  41. private bool IsPointAboveSurface(Vector3 point)
  42. {
  43. Plane plane = GetPlane();
  44. return plane.GetSide(point);
  45. }
  46. public bool ClosestSurfacePoint(in Vector3 point, out SurfaceHit hit, float maxDistance)
  47. {
  48. hit = new SurfaceHit();
  49. Plane plane = GetPlane();
  50. float hitDistance = plane.GetDistanceToPoint(point);
  51. if (maxDistance > 0 && Mathf.Abs(hitDistance) > maxDistance)
  52. {
  53. return false;
  54. }
  55. hit.Point = plane.ClosestPointOnPlane(point);
  56. hit.Distance = IsPointAboveSurface(point) ? hitDistance : -hitDistance;
  57. hit.Normal = plane.normal;
  58. return true;
  59. }
  60. public Transform Transform => transform;
  61. public Bounds Bounds
  62. {
  63. get
  64. {
  65. Vector3 size = new Vector3(
  66. Mathf.Abs(Normal.x) == 1f ? float.Epsilon : float.PositiveInfinity,
  67. Mathf.Abs(Normal.y) == 1f ? float.Epsilon : float.PositiveInfinity,
  68. Mathf.Abs(Normal.z) == 1f ? float.Epsilon : float.PositiveInfinity);
  69. return new Bounds(transform.position, size);
  70. }
  71. }
  72. public bool Raycast(in Ray ray, out SurfaceHit hit, float maxDistance)
  73. {
  74. hit = new SurfaceHit();
  75. Plane plane = GetPlane();
  76. if (!_doubleSided && !IsPointAboveSurface(ray.origin))
  77. {
  78. return false;
  79. }
  80. if (plane.Raycast(ray, out float hitDistance))
  81. {
  82. if (maxDistance > 0 && hitDistance > maxDistance)
  83. {
  84. return false;
  85. }
  86. hit.Point = ray.GetPoint(hitDistance);
  87. hit.Normal = plane.normal;
  88. hit.Distance = hitDistance;
  89. return true;
  90. }
  91. return false;
  92. }
  93. public Plane GetPlane()
  94. {
  95. return new Plane(Normal, transform.position);
  96. }
  97. }
  98. }