Frustum.h 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // Copyright (c) 2008-2023 the Urho3D project
  2. // License: MIT
  3. /// \file
  4. #pragma once
  5. #include "../Math/BoundingBox.h"
  6. #include "../Math/Matrix3x4.h"
  7. #include "../Math/Plane.h"
  8. #include "../Math/Rect.h"
  9. #include "../Math/Sphere.h"
  10. namespace Urho3D
  11. {
  12. /// Frustum planes.
  13. enum FrustumPlane
  14. {
  15. PLANE_NEAR = 0,
  16. PLANE_LEFT,
  17. PLANE_RIGHT,
  18. PLANE_UP,
  19. PLANE_DOWN,
  20. PLANE_FAR,
  21. };
  22. inline constexpr i32 NUM_FRUSTUM_PLANES = 6;
  23. inline constexpr i32 NUM_FRUSTUM_VERTICES = 8;
  24. /// Convex constructed of 6 planes.
  25. class URHO3D_API Frustum
  26. {
  27. public:
  28. /// Construct a degenerate frustum with all points at origin.
  29. Frustum() noexcept = default;
  30. /// Copy-construct from another frustum.
  31. Frustum(const Frustum& frustum) noexcept;
  32. /// Assign from another frustum.
  33. Frustum& operator =(const Frustum& rhs) noexcept;
  34. /// Define with projection parameters and a transform matrix.
  35. void
  36. Define(float fov, float aspectRatio, float zoom, float nearZ, float farZ, const Matrix3x4& transform = Matrix3x4::IDENTITY);
  37. /// Define with near and far dimension vectors and a transform matrix.
  38. void Define(const Vector3& near, const Vector3& far, const Matrix3x4& transform = Matrix3x4::IDENTITY);
  39. /// Define with a bounding box and a transform matrix.
  40. void Define(const BoundingBox& box, const Matrix3x4& transform = Matrix3x4::IDENTITY);
  41. /// Define from a projection or view-projection matrix.
  42. void Define(const Matrix4& projection);
  43. /// Define with orthographic projection parameters and a transform matrix.
  44. void DefineOrtho
  45. (float orthoSize, float aspectRatio, float zoom, float nearZ, float farZ, const Matrix3x4& transform = Matrix3x4::IDENTITY);
  46. /// Define a split (limited) frustum from a projection matrix, with near & far distances specified.
  47. void DefineSplit(const Matrix4& projection, float near, float far);
  48. /// Transform by a 3x3 matrix.
  49. void Transform(const Matrix3& transform);
  50. /// Transform by a 3x4 matrix.
  51. void Transform(const Matrix3x4& transform);
  52. /// Test if a point is inside or outside.
  53. Intersection IsInside(const Vector3& point) const
  54. {
  55. for (const Plane& plane : planes_)
  56. {
  57. if (plane.Distance(point) < 0.0f)
  58. return OUTSIDE;
  59. }
  60. return INSIDE;
  61. }
  62. /// Test if a sphere is inside, outside or intersects.
  63. Intersection IsInside(const Sphere& sphere) const
  64. {
  65. bool allInside = true;
  66. for (const Plane& plane : planes_)
  67. {
  68. float dist = plane.Distance(sphere.center_);
  69. if (dist < -sphere.radius_)
  70. return OUTSIDE;
  71. else if (dist < sphere.radius_)
  72. allInside = false;
  73. }
  74. return allInside ? INSIDE : INTERSECTS;
  75. }
  76. /// Test if a sphere if (partially) inside or outside.
  77. Intersection IsInsideFast(const Sphere& sphere) const
  78. {
  79. for (const Plane& plane : planes_)
  80. {
  81. if (plane.Distance(sphere.center_) < -sphere.radius_)
  82. return OUTSIDE;
  83. }
  84. return INSIDE;
  85. }
  86. /// Test if a bounding box is inside, outside or intersects.
  87. Intersection IsInside(const BoundingBox& box) const
  88. {
  89. Vector3 center = box.Center();
  90. Vector3 edge = center - box.min_;
  91. bool allInside = true;
  92. for (const Plane& plane : planes_)
  93. {
  94. float dist = plane.normal_.DotProduct(center) + plane.d_;
  95. float absDist = plane.absNormal_.DotProduct(edge);
  96. if (dist < -absDist)
  97. return OUTSIDE;
  98. else if (dist < absDist)
  99. allInside = false;
  100. }
  101. return allInside ? INSIDE : INTERSECTS;
  102. }
  103. /// Test if a bounding box is (partially) inside or outside.
  104. Intersection IsInsideFast(const BoundingBox& box) const
  105. {
  106. Vector3 center = box.Center();
  107. Vector3 edge = center - box.min_;
  108. for (const Plane& plane : planes_)
  109. {
  110. float dist = plane.normal_.DotProduct(center) + plane.d_;
  111. float absDist = plane.absNormal_.DotProduct(edge);
  112. if (dist < -absDist)
  113. return OUTSIDE;
  114. }
  115. return INSIDE;
  116. }
  117. /// Return distance of a point to the frustum, or 0 if inside.
  118. float Distance(const Vector3& point) const
  119. {
  120. float distance = 0.0f;
  121. for (const Plane& plane : planes_)
  122. distance = Max(-plane.Distance(point), distance);
  123. return distance;
  124. }
  125. /// Return transformed by a 3x3 matrix.
  126. Frustum Transformed(const Matrix3& transform) const;
  127. /// Return transformed by a 3x4 matrix.
  128. Frustum Transformed(const Matrix3x4& transform) const;
  129. /// Return projected by a 4x4 projection matrix.
  130. Rect Projected(const Matrix4& projection) const;
  131. /// Update the planes. Called internally.
  132. void UpdatePlanes();
  133. /// Frustum planes.
  134. Plane planes_[NUM_FRUSTUM_PLANES];
  135. /// Frustum vertices.
  136. Vector3 vertices_[NUM_FRUSTUM_VERTICES];
  137. };
  138. }