bvh_abb.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*************************************************************************/
  2. /* bvh_abb.h */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #ifndef BVH_ABB_H
  31. #define BVH_ABB_H
  32. // special optimized version of axis aligned bounding box
  33. struct BVH_ABB {
  34. struct ConvexHull {
  35. // convex hulls (optional)
  36. const Plane *planes;
  37. int num_planes;
  38. const Vector3 *points;
  39. int num_points;
  40. };
  41. struct Segment {
  42. Vector3 from;
  43. Vector3 to;
  44. };
  45. enum IntersectResult {
  46. IR_MISS = 0,
  47. IR_PARTIAL,
  48. IR_FULL,
  49. };
  50. // we store mins with a negative value in order to test them with SIMD
  51. Vector3 min;
  52. Vector3 neg_max;
  53. bool operator==(const BVH_ABB &o) const { return (min == o.min) && (neg_max == o.neg_max); }
  54. bool operator!=(const BVH_ABB &o) const { return (*this == o) == false; }
  55. void set(const Vector3 &_min, const Vector3 &_max) {
  56. min = _min;
  57. neg_max = -_max;
  58. }
  59. // to and from standard AABB
  60. void from(const AABB &p_aabb) {
  61. min = p_aabb.position;
  62. neg_max = -(p_aabb.position + p_aabb.size);
  63. }
  64. void to(AABB &r_aabb) const {
  65. r_aabb.position = min;
  66. r_aabb.size = calculate_size();
  67. }
  68. void merge(const BVH_ABB &p_o) {
  69. neg_max.x = MIN(neg_max.x, p_o.neg_max.x);
  70. neg_max.y = MIN(neg_max.y, p_o.neg_max.y);
  71. neg_max.z = MIN(neg_max.z, p_o.neg_max.z);
  72. min.x = MIN(min.x, p_o.min.x);
  73. min.y = MIN(min.y, p_o.min.y);
  74. min.z = MIN(min.z, p_o.min.z);
  75. }
  76. Vector3 calculate_size() const {
  77. return -neg_max - min;
  78. }
  79. Vector3 calculate_centre() const {
  80. return Vector3((calculate_size() * 0.5) + min);
  81. }
  82. real_t get_proximity_to(const BVH_ABB &p_b) const {
  83. const Vector3 d = (min - neg_max) - (p_b.min - p_b.neg_max);
  84. return (Math::abs(d.x) + Math::abs(d.y) + Math::abs(d.z));
  85. }
  86. int select_by_proximity(const BVH_ABB &p_a, const BVH_ABB &p_b) const {
  87. return (get_proximity_to(p_a) < get_proximity_to(p_b) ? 0 : 1);
  88. }
  89. uint32_t find_cutting_planes(const BVH_ABB::ConvexHull &p_hull, uint32_t *p_plane_ids) const {
  90. uint32_t count = 0;
  91. for (int n = 0; n < p_hull.num_planes; n++) {
  92. const Plane &p = p_hull.planes[n];
  93. if (intersects_plane(p)) {
  94. p_plane_ids[count++] = n;
  95. }
  96. }
  97. return count;
  98. }
  99. bool intersects_plane(const Plane &p_p) const {
  100. Vector3 size = calculate_size();
  101. Vector3 half_extents = size * 0.5;
  102. Vector3 ofs = min + half_extents;
  103. // forward side of plane?
  104. Vector3 point_offset(
  105. (p_p.normal.x < 0) ? -half_extents.x : half_extents.x,
  106. (p_p.normal.y < 0) ? -half_extents.y : half_extents.y,
  107. (p_p.normal.z < 0) ? -half_extents.z : half_extents.z);
  108. Vector3 point = point_offset + ofs;
  109. if (!p_p.is_point_over(point))
  110. return false;
  111. point = -point_offset + ofs;
  112. if (p_p.is_point_over(point))
  113. return false;
  114. return true;
  115. }
  116. bool intersects_convex_optimized(const ConvexHull &p_hull, const uint32_t *p_plane_ids, uint32_t p_num_planes) const {
  117. Vector3 size = calculate_size();
  118. Vector3 half_extents = size * 0.5;
  119. Vector3 ofs = min + half_extents;
  120. for (unsigned int i = 0; i < p_num_planes; i++) {
  121. const Plane &p = p_hull.planes[p_plane_ids[i]];
  122. Vector3 point(
  123. (p.normal.x > 0) ? -half_extents.x : half_extents.x,
  124. (p.normal.y > 0) ? -half_extents.y : half_extents.y,
  125. (p.normal.z > 0) ? -half_extents.z : half_extents.z);
  126. point += ofs;
  127. if (p.is_point_over(point))
  128. return false;
  129. }
  130. return true;
  131. }
  132. bool intersects_convex_partial(const ConvexHull &p_hull) const {
  133. AABB bb;
  134. to(bb);
  135. return bb.intersects_convex_shape(p_hull.planes, p_hull.num_planes, p_hull.points, p_hull.num_points);
  136. }
  137. IntersectResult intersects_convex(const ConvexHull &p_hull) const {
  138. if (intersects_convex_partial(p_hull)) {
  139. // fully within? very important for tree checks
  140. if (is_within_convex(p_hull)) {
  141. return IR_FULL;
  142. }
  143. return IR_PARTIAL;
  144. }
  145. return IR_MISS;
  146. }
  147. bool is_within_convex(const ConvexHull &p_hull) const {
  148. // use half extents routine
  149. AABB bb;
  150. to(bb);
  151. return bb.inside_convex_shape(p_hull.planes, p_hull.num_planes);
  152. }
  153. bool is_point_within_hull(const ConvexHull &p_hull, const Vector3 &p_pt) const {
  154. for (int n = 0; n < p_hull.num_planes; n++) {
  155. if (p_hull.planes[n].distance_to(p_pt) > 0.0f)
  156. return false;
  157. }
  158. return true;
  159. }
  160. bool intersects_segment(const Segment &p_s) const {
  161. AABB bb;
  162. to(bb);
  163. return bb.intersects_segment(p_s.from, p_s.to);
  164. }
  165. bool intersects_point(const Vector3 &p_pt) const {
  166. if (_vector3_any_lessthan(-p_pt, neg_max)) return false;
  167. if (_vector3_any_lessthan(p_pt, min)) return false;
  168. return true;
  169. }
  170. bool intersects(const BVH_ABB &p_o) const {
  171. if (_vector3_any_morethan(p_o.min, -neg_max)) return false;
  172. if (_vector3_any_morethan(min, -p_o.neg_max)) return false;
  173. return true;
  174. }
  175. bool is_other_within(const BVH_ABB &p_o) const {
  176. if (_vector3_any_lessthan(p_o.neg_max, neg_max)) return false;
  177. if (_vector3_any_lessthan(p_o.min, min)) return false;
  178. return true;
  179. }
  180. void grow(const Vector3 &p_change) {
  181. neg_max -= p_change;
  182. min -= p_change;
  183. }
  184. void expand(real_t p_change) {
  185. grow(Vector3(p_change, p_change, p_change));
  186. }
  187. float get_area() const // actually surface area metric
  188. {
  189. Vector3 d = calculate_size();
  190. return 2.0f * (d.x * d.y + d.y * d.z + d.z * d.x);
  191. }
  192. void set_to_max_opposite_extents() {
  193. neg_max = Vector3(FLT_MAX, FLT_MAX, FLT_MAX);
  194. min = neg_max;
  195. }
  196. bool _vector3_any_morethan(const Vector3 &p_a, const Vector3 &p_b) const {
  197. if (p_a.x > p_b.x) return true;
  198. if (p_a.y > p_b.y) return true;
  199. if (p_a.z > p_b.z) return true;
  200. return false;
  201. }
  202. bool _vector3_any_lessthan(const Vector3 &p_a, const Vector3 &p_b) const {
  203. if (p_a.x < p_b.x) return true;
  204. if (p_a.y < p_b.y) return true;
  205. if (p_a.z < p_b.z) return true;
  206. return false;
  207. }
  208. };
  209. #endif // BVH_ABB_H