bvh_abb.h 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /**************************************************************************/
  2. /* bvh_abb.h */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  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. template <class BOUNDS = AABB, class POINT = Vector3>
  34. struct BVH_ABB {
  35. struct ConvexHull {
  36. // convex hulls (optional)
  37. const Plane *planes;
  38. int num_planes;
  39. const Vector3 *points;
  40. int num_points;
  41. };
  42. struct Segment {
  43. POINT from;
  44. POINT to;
  45. };
  46. enum IntersectResult {
  47. IR_MISS = 0,
  48. IR_PARTIAL,
  49. IR_FULL,
  50. };
  51. // we store mins with a negative value in order to test them with SIMD
  52. POINT min;
  53. POINT neg_max;
  54. bool operator==(const BVH_ABB &o) const { return (min == o.min) && (neg_max == o.neg_max); }
  55. bool operator!=(const BVH_ABB &o) const { return (*this == o) == false; }
  56. void set(const POINT &_min, const POINT &_max) {
  57. min = _min;
  58. neg_max = -_max;
  59. }
  60. // to and from standard AABB
  61. void from(const BOUNDS &p_aabb) {
  62. min = p_aabb.position;
  63. neg_max = -(p_aabb.position + p_aabb.size);
  64. }
  65. void to(BOUNDS &r_aabb) const {
  66. r_aabb.position = min;
  67. r_aabb.size = calculate_size();
  68. }
  69. void merge(const BVH_ABB &p_o) {
  70. for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
  71. neg_max[axis] = MIN(neg_max[axis], p_o.neg_max[axis]);
  72. min[axis] = MIN(min[axis], p_o.min[axis]);
  73. }
  74. }
  75. POINT calculate_size() const {
  76. return -neg_max - min;
  77. }
  78. POINT calculate_centre() const {
  79. return POINT((calculate_size() * 0.5f) + min);
  80. }
  81. real_t get_proximity_to(const BVH_ABB &p_b) const {
  82. const POINT d = (min - neg_max) - (p_b.min - p_b.neg_max);
  83. real_t proximity = 0;
  84. for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
  85. proximity += Math::abs(d[axis]);
  86. }
  87. return proximity;
  88. }
  89. int select_by_proximity(const BVH_ABB &p_a, const BVH_ABB &p_b) const {
  90. return (get_proximity_to(p_a) < get_proximity_to(p_b) ? 0 : 1);
  91. }
  92. uint32_t find_cutting_planes(const typename BVH_ABB::ConvexHull &p_hull, uint32_t *p_plane_ids) const {
  93. uint32_t count = 0;
  94. for (int n = 0; n < p_hull.num_planes; n++) {
  95. const Plane &p = p_hull.planes[n];
  96. if (intersects_plane(p)) {
  97. p_plane_ids[count++] = n;
  98. }
  99. }
  100. return count;
  101. }
  102. bool intersects_plane(const Plane &p_p) const {
  103. Vector3 size = calculate_size();
  104. Vector3 half_extents = size * 0.5f;
  105. Vector3 ofs = min + half_extents;
  106. // forward side of plane?
  107. Vector3 point_offset(
  108. (p_p.normal.x < 0) ? -half_extents.x : half_extents.x,
  109. (p_p.normal.y < 0) ? -half_extents.y : half_extents.y,
  110. (p_p.normal.z < 0) ? -half_extents.z : half_extents.z);
  111. Vector3 point = point_offset + ofs;
  112. if (!p_p.is_point_over(point)) {
  113. return false;
  114. }
  115. point = -point_offset + ofs;
  116. if (p_p.is_point_over(point)) {
  117. return false;
  118. }
  119. return true;
  120. }
  121. bool intersects_convex_optimized(const ConvexHull &p_hull, const uint32_t *p_plane_ids, uint32_t p_num_planes) const {
  122. Vector3 size = calculate_size();
  123. Vector3 half_extents = size * 0.5f;
  124. Vector3 ofs = min + half_extents;
  125. for (unsigned int i = 0; i < p_num_planes; i++) {
  126. const Plane &p = p_hull.planes[p_plane_ids[i]];
  127. Vector3 point(
  128. (p.normal.x > 0) ? -half_extents.x : half_extents.x,
  129. (p.normal.y > 0) ? -half_extents.y : half_extents.y,
  130. (p.normal.z > 0) ? -half_extents.z : half_extents.z);
  131. point += ofs;
  132. if (p.is_point_over(point)) {
  133. return false;
  134. }
  135. }
  136. return true;
  137. }
  138. bool intersects_convex_partial(const ConvexHull &p_hull) const {
  139. BOUNDS bb;
  140. to(bb);
  141. return bb.intersects_convex_shape(p_hull.planes, p_hull.num_planes, p_hull.points, p_hull.num_points);
  142. }
  143. IntersectResult intersects_convex(const ConvexHull &p_hull) const {
  144. if (intersects_convex_partial(p_hull)) {
  145. // fully within? very important for tree checks
  146. if (is_within_convex(p_hull)) {
  147. return IR_FULL;
  148. }
  149. return IR_PARTIAL;
  150. }
  151. return IR_MISS;
  152. }
  153. bool is_within_convex(const ConvexHull &p_hull) const {
  154. // use half extents routine
  155. BOUNDS bb;
  156. to(bb);
  157. return bb.inside_convex_shape(p_hull.planes, p_hull.num_planes);
  158. }
  159. bool is_point_within_hull(const ConvexHull &p_hull, const Vector3 &p_pt) const {
  160. for (int n = 0; n < p_hull.num_planes; n++) {
  161. if (p_hull.planes[n].distance_to(p_pt) > 0) {
  162. return false;
  163. }
  164. }
  165. return true;
  166. }
  167. bool intersects_segment(const Segment &p_s) const {
  168. BOUNDS bb;
  169. to(bb);
  170. return bb.intersects_segment(p_s.from, p_s.to);
  171. }
  172. bool intersects_point(const POINT &p_pt) const {
  173. if (_any_lessthan(-p_pt, neg_max)) {
  174. return false;
  175. }
  176. if (_any_lessthan(p_pt, min)) {
  177. return false;
  178. }
  179. return true;
  180. }
  181. // Very hot in profiling, make sure optimized
  182. bool intersects(const BVH_ABB &p_o) const {
  183. if (_any_morethan(p_o.min, -neg_max)) {
  184. return false;
  185. }
  186. if (_any_morethan(min, -p_o.neg_max)) {
  187. return false;
  188. }
  189. return true;
  190. }
  191. // for pre-swizzled tester (this object)
  192. bool intersects_swizzled(const BVH_ABB &p_o) const {
  193. if (_any_lessthan(min, p_o.min)) {
  194. return false;
  195. }
  196. if (_any_lessthan(neg_max, p_o.neg_max)) {
  197. return false;
  198. }
  199. return true;
  200. }
  201. bool is_other_within(const BVH_ABB &p_o) const {
  202. if (_any_lessthan(p_o.neg_max, neg_max)) {
  203. return false;
  204. }
  205. if (_any_lessthan(p_o.min, min)) {
  206. return false;
  207. }
  208. return true;
  209. }
  210. void grow(const POINT &p_change) {
  211. neg_max -= p_change;
  212. min -= p_change;
  213. }
  214. void expand(real_t p_change) {
  215. POINT change;
  216. change.set_all(p_change);
  217. grow(change);
  218. }
  219. // Actually surface area metric.
  220. float get_area() const {
  221. POINT d = calculate_size();
  222. return 2 * (d.x * d.y + d.y * d.z + d.z * d.x);
  223. }
  224. void set_to_max_opposite_extents() {
  225. neg_max.set_all(FLT_MAX);
  226. min = neg_max;
  227. }
  228. bool _any_morethan(const POINT &p_a, const POINT &p_b) const {
  229. for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
  230. if (p_a[axis] > p_b[axis]) {
  231. return true;
  232. }
  233. }
  234. return false;
  235. }
  236. bool _any_lessthan(const POINT &p_a, const POINT &p_b) const {
  237. for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
  238. if (p_a[axis] < p_b[axis]) {
  239. return true;
  240. }
  241. }
  242. return false;
  243. }
  244. };
  245. #endif // BVH_ABB_H