bvh_collider.cpp 16 KB

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