frustum.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. * MIT License
  3. *
  4. * Copyright (c) [year] [fullname]
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in all
  14. * copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22. * SOFTWARE.
  23. */
  24. #ifndef GUL_MATH_FRUSTRUM_H
  25. #define GUL_MATH_FRUSTRUM_H
  26. #include "geometry.h"
  27. #include "aabb.h"
  28. namespace gul
  29. {
  30. /**
  31. * @brief The frustum_t struct
  32. *
  33. * A class which represents a frustum in 3d space. It can be used to check clipping
  34. * with bounding boxes
  35. */
  36. template<typename T>
  37. struct frustum_t
  38. {
  39. using value_type = T;
  40. using vec_type = glm::tvec3<value_type, glm::highp>;
  41. using vec4_type = glm::tvec4<value_type, glm::highp>;
  42. using mat_type = glm::tmat4x4<value_type, glm::highp>;
  43. using point_type = point_t<value_type>;
  44. using line_type = line_t<value_type>;
  45. using plane_type = plane_t<value_type>;
  46. using aabb_type = aabb_t<value_type, 3>;
  47. frustum_t()
  48. {
  49. }
  50. /**
  51. * @brief Frustum
  52. * @param proj
  53. *
  54. * Constructs the frustrum from a perspective projection matrix.
  55. * The Frustum will have a default position of (0,0,0) point down the
  56. * negative Z axis
  57. *
  58. */
  59. frustum_t(const mat_type & proj)
  60. {
  61. const auto & m = proj;
  62. left.v.x = -(m[0][3] + m[0][0]);
  63. left.v.y = -(m[1][3] + m[1][0]);
  64. left.v.z = -(m[2][3] + m[2][0]);
  65. left.p = point_type(glm::vec3(0.0f));
  66. left.v = glm::normalize(left.v);
  67. // right
  68. right.v.x = -(m[0][3] - m[0][0]);
  69. right.v.y = -(m[1][3] - m[1][0]);
  70. right.v.z = -(m[2][3] - m[2][0]);
  71. right.p = point_type(glm::vec3(0.0f));
  72. right.v = glm::normalize(right.v);
  73. // bottom
  74. bottom.v.x = -(m[0][3] + m[0][1]);
  75. bottom.v.y = -(m[1][3] + m[1][1]);
  76. bottom.v.z = -(m[2][3] + m[2][1]);
  77. bottom.p = point_type(glm::vec3(0.0f));
  78. bottom.v = glm::normalize(bottom.v);
  79. // top
  80. top.v.x = -(m[0][3] - m[0][1]);
  81. top.v.y = -(m[1][3] - m[1][1]);
  82. top.v.z = -(m[2][3] - m[2][1]);
  83. top.p = point_type(glm::vec3(0.0f));
  84. top.v = glm::normalize(top.v);
  85. // near
  86. near.v.x = m[0][3] + m[0][2];
  87. near.v.y = m[1][3] + m[1][2];
  88. near.v.z = m[2][3] + m[2][2];
  89. near.p = point_type( glm::vec3(0,0, -(m[3][3] + m[3][2])/near.v.z) );
  90. near.v = -glm::normalize(near.v);
  91. // far
  92. far.v.x = m[0][3] - m[0][2];
  93. far.v.y = m[1][3] - m[1][2];
  94. far.v.z = m[2][3] - m[2][2];
  95. far.p = point_type( glm::vec3(0,0, -(m[3][3] - m[3][2]) / far.v.z) );
  96. far.v = -glm::normalize(far.v);
  97. }
  98. // Transform the fustrum using a matrix
  99. // The matrix M needs to be unitary
  100. void transform(const mat_type & ViewMatrix)
  101. {
  102. line_type * L = &top;
  103. for(int i=0;i<6;i++)
  104. {
  105. auto p4 = ViewMatrix * vec4_type( L[i].p.x, L[i].p.y, L[i].p.z, 1.0f);
  106. auto v4 = ViewMatrix * vec4_type( L[i].v.x, L[i].v.y, L[i].v.z, 0.0f);
  107. L[i] = line_type( point_type(p4.x,p4.y,p4.z), vec_type(v4.x,v4.y,v4.z));
  108. }
  109. auto p4 = ViewMatrix * vec4_type( p.x, p.y, p.z, 1.0f);
  110. p = point_type(vec_type(p4.x,p4.y,p4.z));
  111. }
  112. /**
  113. * @brief Intersects
  114. * @param B
  115. * @return
  116. *
  117. * Determines if a bounding box intersects the fustrum
  118. */
  119. bool intersects(aabb_type const & B) const
  120. {
  121. // for each plane, check if the corners of the bounding box are on the same side of the plane
  122. line_type const * L = &top;
  123. const vec_type P[] =
  124. {
  125. vec_type( B.lowerBound.x, B.lowerBound.y, B.lowerBound.z),
  126. vec_type( B.lowerBound.x, B.lowerBound.y, B.upperBound.z),
  127. vec_type( B.lowerBound.x, B.upperBound.y, B.lowerBound.z),
  128. vec_type( B.lowerBound.x, B.upperBound.y, B.upperBound.z),
  129. vec_type( B.upperBound.x, B.lowerBound.y, B.lowerBound.z),
  130. vec_type( B.upperBound.x, B.lowerBound.y, B.upperBound.z),
  131. vec_type( B.upperBound.x, B.upperBound.y, B.lowerBound.z),
  132. vec_type( B.upperBound.x, B.upperBound.y, B.upperBound.z)
  133. };
  134. // for each plane
  135. for(int i=0 ; i<6 ; i++)
  136. {
  137. int c = 0;
  138. auto oneOverL = 1.0f / glm::length(L[i].v);
  139. auto Lip = L[i].p.asVec();
  140. c += (glm::dot( P[0]-Lip, L[i].v) * oneOverL ) > 0;
  141. c += (glm::dot( P[1]-Lip, L[i].v) * oneOverL ) > 0;
  142. c += (glm::dot( P[2]-Lip, L[i].v) * oneOverL ) > 0;
  143. c += (glm::dot( P[3]-Lip, L[i].v) * oneOverL ) > 0;
  144. c += (glm::dot( P[4]-Lip, L[i].v) * oneOverL ) > 0;
  145. c += (glm::dot( P[5]-Lip, L[i].v) * oneOverL ) > 0;
  146. c += (glm::dot( P[6]-Lip, L[i].v) * oneOverL ) > 0;
  147. c += (glm::dot( P[7]-Lip, L[i].v) * oneOverL ) > 0;
  148. if(c==8) return false;
  149. }
  150. return true;
  151. }
  152. /**
  153. * @brief Intersects
  154. * @param point
  155. * @return true if the point is within the furstrum
  156. */
  157. bool intersects(const glm::vec3 & P ) const
  158. {
  159. line_type const * L = &top;
  160. for(int i=0;i<6;i++)
  161. {
  162. const float d = glm::dot( P-L[i].p, L[i].v) / glm::length(L[i].v);
  163. if( d > 0) return false;
  164. }
  165. return true;
  166. }
  167. const glm::vec3 & get_position() const
  168. {
  169. return p;
  170. }
  171. plane_type getNear() const
  172. {
  173. return plane_type( near.p, near.v);
  174. }
  175. plane_type getFar() const
  176. {
  177. return plane_type( point_type(2.0f*p.asVec() - far.p.asVec()), far.v);
  178. }
  179. plane_type getTop() const
  180. {
  181. return plane_type( point_type(p), top.v);
  182. }
  183. plane_type getRight() const
  184. {
  185. return plane_type( point_type(p), right.v);
  186. }
  187. plane_type getBottom() const
  188. {
  189. return plane_type( point_type(p), bottom.v);
  190. }
  191. plane_type getLeft() const
  192. {
  193. return plane_type( point_type(p), left.v);
  194. }
  195. public:
  196. point_type p; // position of the camera in 3d space. The position of the point of the pyrimad
  197. // the 6 planes that define the fustrum
  198. // these planes are in real coordinate space. not normalized.
  199. line_type top; // this plane passes through the point, p,
  200. line_type right; // this plane passes through the point, p,
  201. line_type bottom; // this plane passes through the point, p,
  202. line_type left; // this plane passes through the point, p,
  203. line_type near;
  204. line_type far;
  205. };
  206. using frustum = frustum_t<float>;
  207. template<typename T>
  208. bool intersects(frustum_t<T> const & F, typename frustum_t<T>::aabb_type const & bb)
  209. {
  210. return F.intersects(bb);
  211. }
  212. template<typename T>
  213. bool intersects(typename frustum_t<T>::aabb_type const & bb, frustum_t<T> const & F)
  214. {
  215. return F.intersects(bb);
  216. }
  217. }
  218. #endif