bvh_collider.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. // Copyright 2009-2021 Intel Corporation
  2. // SPDX-License-Identifier: Apache-2.0
  3. #include "bvh_collider.h"
  4. #include "../geometry/triangle_triangle_intersector.h"
  5. namespace embree
  6. {
  7. namespace isa
  8. {
  9. #define CSTAT(x)
  10. size_t parallel_depth_threshold = 3;
  11. CSTAT(std::atomic<size_t> bvh_collide_traversal_steps(0));
  12. CSTAT(std::atomic<size_t> bvh_collide_leaf_pairs(0));
  13. CSTAT(std::atomic<size_t> bvh_collide_leaf_iterations(0));
  14. CSTAT(std::atomic<size_t> bvh_collide_prim_intersections1(0));
  15. CSTAT(std::atomic<size_t> bvh_collide_prim_intersections2(0));
  16. CSTAT(std::atomic<size_t> bvh_collide_prim_intersections3(0));
  17. CSTAT(std::atomic<size_t> bvh_collide_prim_intersections4(0));
  18. CSTAT(std::atomic<size_t> bvh_collide_prim_intersections5(0));
  19. CSTAT(std::atomic<size_t> bvh_collide_prim_intersections(0));
  20. struct Collision
  21. {
  22. __forceinline Collision() {}
  23. __forceinline Collision (unsigned geomID0, unsigned primID0, unsigned geomID1, unsigned primID1)
  24. : geomID0(geomID0), primID0(primID0), geomID1(geomID1), primID1(primID1) {}
  25. unsigned geomID0;
  26. unsigned primID0;
  27. unsigned geomID1;
  28. unsigned primID1;
  29. };
  30. template<int N>
  31. __forceinline size_t overlap(const BBox3fa& box0, const typename BVHN<N>::AABBNode& node1)
  32. {
  33. const vfloat<N> lower_x = max(vfloat<N>(box0.lower.x),node1.lower_x);
  34. const vfloat<N> lower_y = max(vfloat<N>(box0.lower.y),node1.lower_y);
  35. const vfloat<N> lower_z = max(vfloat<N>(box0.lower.z),node1.lower_z);
  36. const vfloat<N> upper_x = min(vfloat<N>(box0.upper.x),node1.upper_x);
  37. const vfloat<N> upper_y = min(vfloat<N>(box0.upper.y),node1.upper_y);
  38. const vfloat<N> upper_z = min(vfloat<N>(box0.upper.z),node1.upper_z);
  39. return movemask((lower_x <= upper_x) & (lower_y <= upper_y) & (lower_z <= upper_z));
  40. }
  41. template<int N>
  42. __forceinline size_t overlap(const BBox3fa& box0, const BBox<Vec3<vfloat<N>>>& box1)
  43. {
  44. const vfloat<N> lower_x = max(vfloat<N>(box0.lower.x),box1.lower.x);
  45. const vfloat<N> lower_y = max(vfloat<N>(box0.lower.y),box1.lower.y);
  46. const vfloat<N> lower_z = max(vfloat<N>(box0.lower.z),box1.lower.z);
  47. const vfloat<N> upper_x = min(vfloat<N>(box0.upper.x),box1.upper.x);
  48. const vfloat<N> upper_y = min(vfloat<N>(box0.upper.y),box1.upper.y);
  49. const vfloat<N> upper_z = min(vfloat<N>(box0.upper.z),box1.upper.z);
  50. return movemask((lower_x <= upper_x) & (lower_y <= upper_y) & (lower_z <= upper_z));
  51. }
  52. template<int N>
  53. __forceinline size_t overlap(const BBox<Vec3<vfloat<N>>>& box0, size_t i, const BBox<Vec3<vfloat<N>>>& box1)
  54. {
  55. const vfloat<N> lower_x = max(vfloat<N>(box0.lower.x[i]),box1.lower.x);
  56. const vfloat<N> lower_y = max(vfloat<N>(box0.lower.y[i]),box1.lower.y);
  57. const vfloat<N> lower_z = max(vfloat<N>(box0.lower.z[i]),box1.lower.z);
  58. const vfloat<N> upper_x = min(vfloat<N>(box0.upper.x[i]),box1.upper.x);
  59. const vfloat<N> upper_y = min(vfloat<N>(box0.upper.y[i]),box1.upper.y);
  60. const vfloat<N> upper_z = min(vfloat<N>(box0.upper.z[i]),box1.upper.z);
  61. return movemask((lower_x <= upper_x) & (lower_y <= upper_y) & (lower_z <= upper_z));
  62. }
  63. bool intersect_triangle_triangle (Scene* scene0, unsigned geomID0, unsigned primID0, Scene* scene1, unsigned geomID1, unsigned primID1)
  64. {
  65. CSTAT(bvh_collide_prim_intersections1++);
  66. const TriangleMesh* mesh0 = scene0->get<TriangleMesh>(geomID0);
  67. const TriangleMesh* mesh1 = scene1->get<TriangleMesh>(geomID1);
  68. const TriangleMesh::Triangle& tri0 = mesh0->triangle(primID0);
  69. const TriangleMesh::Triangle& tri1 = mesh1->triangle(primID1);
  70. /* special culling for scene intersection with itself */
  71. if (scene0 == scene1 && geomID0 == geomID1)
  72. {
  73. /* ignore self intersections */
  74. if (primID0 == primID1)
  75. return false;
  76. }
  77. CSTAT(bvh_collide_prim_intersections2++);
  78. if (scene0 == scene1 && geomID0 == geomID1)
  79. {
  80. /* ignore intersection with topological neighbors */
  81. const vint4 t0(tri0.v[0],tri0.v[1],tri0.v[2],tri0.v[2]);
  82. if (any(vint4(tri1.v[0]) == t0)) return false;
  83. if (any(vint4(tri1.v[1]) == t0)) return false;
  84. if (any(vint4(tri1.v[2]) == t0)) return false;
  85. }
  86. CSTAT(bvh_collide_prim_intersections3++);
  87. const Vec3fa a0 = mesh0->vertex(tri0.v[0]);
  88. const Vec3fa a1 = mesh0->vertex(tri0.v[1]);
  89. const Vec3fa a2 = mesh0->vertex(tri0.v[2]);
  90. const Vec3fa b0 = mesh1->vertex(tri1.v[0]);
  91. const Vec3fa b1 = mesh1->vertex(tri1.v[1]);
  92. const Vec3fa b2 = mesh1->vertex(tri1.v[2]);
  93. return TriangleTriangleIntersector::intersect_triangle_triangle(a0,a1,a2,b0,b1,b2);
  94. }
  95. template<int N>
  96. __forceinline void BVHNColliderUserGeom<N>::processLeaf(NodeRef node0, NodeRef node1)
  97. {
  98. Collision collisions[16];
  99. size_t num_collisions = 0;
  100. size_t N0; Object* leaf0 = (Object*) node0.leaf(N0);
  101. size_t N1; Object* leaf1 = (Object*) node1.leaf(N1);
  102. for (size_t i=0; i<N0; i++) {
  103. for (size_t j=0; j<N1; j++) {
  104. const unsigned geomID0 = leaf0[i].geomID();
  105. const unsigned primID0 = leaf0[i].primID();
  106. const unsigned geomID1 = leaf1[j].geomID();
  107. const unsigned primID1 = leaf1[j].primID();
  108. if (this->scene0 == this->scene1 && geomID0 == geomID1 && primID0 == primID1) continue;
  109. collisions[num_collisions++] = Collision(geomID0,primID0,geomID1,primID1);
  110. if (num_collisions == 16) {
  111. this->callback(this->userPtr,(RTCCollision*)&collisions,num_collisions);
  112. num_collisions = 0;
  113. }
  114. }
  115. }
  116. if (num_collisions)
  117. this->callback(this->userPtr,(RTCCollision*)&collisions,num_collisions);
  118. }
  119. template<int N>
  120. void BVHNCollider<N>::collide_recurse(NodeRef ref0, const BBox3fa& bounds0, NodeRef ref1, const BBox3fa& bounds1, size_t depth0, size_t depth1)
  121. {
  122. CSTAT(bvh_collide_traversal_steps++);
  123. if (unlikely(ref0.isLeaf())) {
  124. if (unlikely(ref1.isLeaf())) {
  125. CSTAT(bvh_collide_leaf_pairs++);
  126. processLeaf(ref0,ref1);
  127. return;
  128. } else goto recurse_node1;
  129. } else {
  130. if (unlikely(ref1.isLeaf())) {
  131. goto recurse_node0;
  132. } else {
  133. if (area(bounds0) > area(bounds1)) {
  134. goto recurse_node0;
  135. }
  136. else {
  137. goto recurse_node1;
  138. }
  139. }
  140. }
  141. {
  142. recurse_node0:
  143. AABBNode* node0 = ref0.getAABBNode();
  144. size_t mask = overlap<N>(bounds1,*node0);
  145. //for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {
  146. //for (size_t i=0; i<N; i++) {
  147. #if 0
  148. if (depth0 < parallel_depth_threshold)
  149. {
  150. parallel_for(size_t(N), [&] ( size_t i ) {
  151. if (mask & ( 1 << i)) {
  152. BVHN<N>::prefetch(node0->child(i),BVH_FLAG_ALIGNED_NODE);
  153. collide_recurse(node0->child(i),node0->bounds(i),ref1,bounds1,depth0+1,depth1);
  154. }
  155. });
  156. }
  157. else
  158. #endif
  159. {
  160. for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {
  161. BVHN<N>::prefetch(node0->child(i),BVH_FLAG_ALIGNED_NODE);
  162. collide_recurse(node0->child(i),node0->bounds(i),ref1,bounds1,depth0+1,depth1);
  163. }
  164. }
  165. return;
  166. }
  167. {
  168. recurse_node1:
  169. AABBNode* node1 = ref1.getAABBNode();
  170. size_t mask = overlap<N>(bounds0,*node1);
  171. //for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {
  172. //for (size_t i=0; i<N; i++) {
  173. #if 0
  174. if (depth1 < parallel_depth_threshold)
  175. {
  176. parallel_for(size_t(N), [&] ( size_t i ) {
  177. if (mask & ( 1 << i)) {
  178. BVHN<N>::prefetch(node1->child(i),BVH_FLAG_ALIGNED_NODE);
  179. collide_recurse(ref0,bounds0,node1->child(i),node1->bounds(i),depth0,depth1+1);
  180. }
  181. });
  182. }
  183. else
  184. #endif
  185. {
  186. for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {
  187. BVHN<N>::prefetch(node1->child(i),BVH_FLAG_ALIGNED_NODE);
  188. collide_recurse(ref0,bounds0,node1->child(i),node1->bounds(i),depth0,depth1+1);
  189. }
  190. }
  191. return;
  192. }
  193. }
  194. template<int N>
  195. void BVHNCollider<N>::split(const CollideJob& job, jobvector& jobs)
  196. {
  197. if (unlikely(job.ref0.isLeaf())) {
  198. if (unlikely(job.ref1.isLeaf())) {
  199. jobs.push_back(job);
  200. return;
  201. } else goto recurse_node1;
  202. } else {
  203. if (unlikely(job.ref1.isLeaf())) {
  204. goto recurse_node0;
  205. } else {
  206. if (area(job.bounds0) > area(job.bounds1)) {
  207. goto recurse_node0;
  208. }
  209. else {
  210. goto recurse_node1;
  211. }
  212. }
  213. }
  214. {
  215. recurse_node0:
  216. const AABBNode* node0 = job.ref0.getAABBNode();
  217. size_t mask = overlap<N>(job.bounds1,*node0);
  218. for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {
  219. jobs.push_back(CollideJob(node0->child(i),node0->bounds(i),job.depth0+1,job.ref1,job.bounds1,job.depth1));
  220. }
  221. return;
  222. }
  223. {
  224. recurse_node1:
  225. const AABBNode* node1 = job.ref1.getAABBNode();
  226. size_t mask = overlap<N>(job.bounds0,*node1);
  227. for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {
  228. jobs.push_back(CollideJob(job.ref0,job.bounds0,job.depth0,node1->child(i),node1->bounds(i),job.depth1+1));
  229. }
  230. return;
  231. }
  232. }
  233. template<int N>
  234. void BVHNCollider<N>::collide_recurse_entry(NodeRef ref0, const BBox3fa& bounds0, NodeRef ref1, const BBox3fa& bounds1)
  235. {
  236. CSTAT(bvh_collide_traversal_steps = 0);
  237. CSTAT(bvh_collide_leaf_pairs = 0);
  238. CSTAT(bvh_collide_leaf_iterations = 0);
  239. CSTAT(bvh_collide_prim_intersections1 = 0);
  240. CSTAT(bvh_collide_prim_intersections2 = 0);
  241. CSTAT(bvh_collide_prim_intersections3 = 0);
  242. CSTAT(bvh_collide_prim_intersections4 = 0);
  243. CSTAT(bvh_collide_prim_intersections5 = 0);
  244. CSTAT(bvh_collide_prim_intersections = 0);
  245. #if 0
  246. collide_recurse(ref0,bounds0,ref1,bounds1,0,0);
  247. #else
  248. const int M = 2048;
  249. jobvector jobs[2];
  250. jobs[0].reserve(M);
  251. jobs[1].reserve(M);
  252. jobs[0].push_back(CollideJob(ref0,bounds0,0,ref1,bounds1,0));
  253. int source = 0;
  254. int target = 1;
  255. /* try to split job until job list is full */
  256. while (jobs[source].size()+8 <= M)
  257. {
  258. for (size_t i=0; i<jobs[source].size(); i++)
  259. {
  260. const CollideJob& job = jobs[source][i];
  261. size_t remaining = jobs[source].size()-i;
  262. if (jobs[target].size()+remaining+8 > M) {
  263. jobs[target].push_back(job);
  264. } else {
  265. split(job,jobs[target]);
  266. }
  267. }
  268. /* stop splitting jobs if we reached only leaves and cannot make progress anymore */
  269. if (jobs[target].size() == jobs[source].size())
  270. break;
  271. jobs[source].resize(0);
  272. std::swap(source,target);
  273. }
  274. /* parallel processing of all jobs */
  275. parallel_for(size_t(jobs[source].size()), [&] ( size_t i ) {
  276. CollideJob& j = jobs[source][i];
  277. collide_recurse(j.ref0,j.bounds0,j.ref1,j.bounds1,j.depth0,j.depth1);
  278. });
  279. #endif
  280. CSTAT(PRINT(bvh_collide_traversal_steps));
  281. CSTAT(PRINT(bvh_collide_leaf_pairs));
  282. CSTAT(PRINT(bvh_collide_leaf_iterations));
  283. CSTAT(PRINT(bvh_collide_prim_intersections1));
  284. CSTAT(PRINT(bvh_collide_prim_intersections2));
  285. CSTAT(PRINT(bvh_collide_prim_intersections3));
  286. CSTAT(PRINT(bvh_collide_prim_intersections4));
  287. CSTAT(PRINT(bvh_collide_prim_intersections5));
  288. CSTAT(PRINT(bvh_collide_prim_intersections));
  289. }
  290. template<int N>
  291. void BVHNColliderUserGeom<N>::collide(BVH* __restrict__ bvh0, BVH* __restrict__ bvh1, RTCCollideFunc callback, void* userPtr)
  292. {
  293. BVHNColliderUserGeom<N>(bvh0->scene,bvh1->scene,callback,userPtr).
  294. collide_recurse_entry(bvh0->root,bvh0->bounds.bounds(),bvh1->root,bvh1->bounds.bounds());
  295. }
  296. #if defined (EMBREE_LOWEST_ISA)
  297. struct collision_regression_test : public RegressionTest
  298. {
  299. collision_regression_test(const char* name) : RegressionTest(name) {
  300. registerRegressionTest(this);
  301. }
  302. bool run ()
  303. {
  304. bool passed = true;
  305. passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(-0.008815f, 0.041848f, -2.49875e-06f), Vec3fa(-0.008276f, 0.053318f, -2.49875e-06f), Vec3fa(0.003023f, 0.048969f, -2.49875e-06f),
  306. Vec3fa(0.00245f, 0.037612f, -2.49875e-06f), Vec3fa(0.01434f, 0.042634f, -2.49875e-06f), Vec3fa(0.013499f, 0.031309f, -2.49875e-06f)) == false;
  307. passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0)) == true;
  308. passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,1),Vec3fa(1,0,1),Vec3fa(0,1,1)) == false;
  309. passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,1),Vec3fa(1,0,0),Vec3fa(0,1,0)) == true;
  310. passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,0),Vec3fa(1,0,1),Vec3fa(0,1,1)) == true;
  311. passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1f,0.1f,0),Vec3fa(1,0,1),Vec3fa(0,1,1)) == true;
  312. passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1f,0.1f,-0.1f),Vec3fa(1,0,1),Vec3fa(0,1,1)) == true;
  313. passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0)) == true;
  314. passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0,0,0),Vec3fa(0.5f,0,0),Vec3fa(0,0.5f,0)) == true;
  315. passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1f,0.1f,0),Vec3fa(0.5f,0,0),Vec3fa(0,0.5f,0)) == true;
  316. passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1f,0.1f,0),Vec3fa(0.5f,0.1f,0),Vec3fa(0.1f,0.5f,0)) == true;
  317. passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(0.1f,-0.1f,0),Vec3fa(0.5f,0.1f,0),Vec3fa(0.1f,0.5f,0)) == true;
  318. passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0), Vec3fa(-0.1f,0.1f,0),Vec3fa(0.5f,0.1f,0),Vec3fa(0.1f,0.5f,0)) == true;
  319. passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0),
  320. Vec3fa(-1,1,0) + Vec3fa(0,0,0),Vec3fa(-1,1,0) + Vec3fa(0.1f,0,0),Vec3fa(-1,1,0) + Vec3fa(0,0.1f,0)) == false;
  321. passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0),
  322. Vec3fa( 2,0.5f,0) + Vec3fa(0,0,0),Vec3fa( 2,0.5f,0) + Vec3fa(0.1f,0,0),Vec3fa( 2,0.5f,0) + Vec3fa(0,0.1f,0)) == false;
  323. passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0),
  324. Vec3fa(0.5f,-2.0f,0) + Vec3fa(0,0,0),Vec3fa(0.5f,-2.0f,0) + Vec3fa(0.1f,0,0),Vec3fa(0.5f,-2.0f,0) + Vec3fa(0,0.1f,0)) == false;
  325. return passed;
  326. }
  327. };
  328. collision_regression_test collision_regression("collision_regression_test");
  329. #endif
  330. ////////////////////////////////////////////////////////////////////////////////
  331. /// Collider Definitions
  332. ////////////////////////////////////////////////////////////////////////////////
  333. DEFINE_COLLIDER(BVH4ColliderUserGeom,BVHNColliderUserGeom<4>);
  334. #if defined(__AVX__)
  335. DEFINE_COLLIDER(BVH8ColliderUserGeom,BVHNColliderUserGeom<8>);
  336. #endif
  337. }
  338. }