Path: blob/master/thirdparty/embree/kernels/bvh/bvh_collider.cpp
9906 views
// Copyright 2009-2021 Intel Corporation1// SPDX-License-Identifier: Apache-2.023#include "bvh_collider.h"45#include "../geometry/triangle_triangle_intersector.h"6#include "../../common/algorithms/parallel_for.h"78namespace embree9{10namespace isa11{12#define CSTAT(x)1314size_t parallel_depth_threshold = 3;15CSTAT(std::atomic<size_t> bvh_collide_traversal_steps(0));16CSTAT(std::atomic<size_t> bvh_collide_leaf_pairs(0));17CSTAT(std::atomic<size_t> bvh_collide_leaf_iterations(0));18CSTAT(std::atomic<size_t> bvh_collide_prim_intersections1(0));19CSTAT(std::atomic<size_t> bvh_collide_prim_intersections2(0));20CSTAT(std::atomic<size_t> bvh_collide_prim_intersections3(0));21CSTAT(std::atomic<size_t> bvh_collide_prim_intersections4(0));22CSTAT(std::atomic<size_t> bvh_collide_prim_intersections5(0));23CSTAT(std::atomic<size_t> bvh_collide_prim_intersections(0));2425struct Collision26{27__forceinline Collision() {}2829__forceinline Collision (unsigned geomID0, unsigned primID0, unsigned geomID1, unsigned primID1)30: geomID0(geomID0), primID0(primID0), geomID1(geomID1), primID1(primID1) {}3132unsigned geomID0;33unsigned primID0;34unsigned geomID1;35unsigned primID1;36};3738template<int N>39__forceinline size_t overlap(const BBox3fa& box0, const typename BVHN<N>::AABBNode& node1)40{41const vfloat<N> lower_x = max(vfloat<N>(box0.lower.x),node1.lower_x);42const vfloat<N> lower_y = max(vfloat<N>(box0.lower.y),node1.lower_y);43const vfloat<N> lower_z = max(vfloat<N>(box0.lower.z),node1.lower_z);44const vfloat<N> upper_x = min(vfloat<N>(box0.upper.x),node1.upper_x);45const vfloat<N> upper_y = min(vfloat<N>(box0.upper.y),node1.upper_y);46const vfloat<N> upper_z = min(vfloat<N>(box0.upper.z),node1.upper_z);47return movemask((lower_x <= upper_x) & (lower_y <= upper_y) & (lower_z <= upper_z));48}4950template<int N>51__forceinline size_t overlap(const BBox3fa& box0, const BBox<Vec3<vfloat<N>>>& box1)52{53const vfloat<N> lower_x = max(vfloat<N>(box0.lower.x),box1.lower.x);54const vfloat<N> lower_y = max(vfloat<N>(box0.lower.y),box1.lower.y);55const vfloat<N> lower_z = max(vfloat<N>(box0.lower.z),box1.lower.z);56const vfloat<N> upper_x = min(vfloat<N>(box0.upper.x),box1.upper.x);57const vfloat<N> upper_y = min(vfloat<N>(box0.upper.y),box1.upper.y);58const vfloat<N> upper_z = min(vfloat<N>(box0.upper.z),box1.upper.z);59return movemask((lower_x <= upper_x) & (lower_y <= upper_y) & (lower_z <= upper_z));60}6162template<int N>63__forceinline size_t overlap(const BBox<Vec3<vfloat<N>>>& box0, size_t i, const BBox<Vec3<vfloat<N>>>& box1)64{65const vfloat<N> lower_x = max(vfloat<N>(box0.lower.x[i]),box1.lower.x);66const vfloat<N> lower_y = max(vfloat<N>(box0.lower.y[i]),box1.lower.y);67const vfloat<N> lower_z = max(vfloat<N>(box0.lower.z[i]),box1.lower.z);68const vfloat<N> upper_x = min(vfloat<N>(box0.upper.x[i]),box1.upper.x);69const vfloat<N> upper_y = min(vfloat<N>(box0.upper.y[i]),box1.upper.y);70const vfloat<N> upper_z = min(vfloat<N>(box0.upper.z[i]),box1.upper.z);71return movemask((lower_x <= upper_x) & (lower_y <= upper_y) & (lower_z <= upper_z));72}7374bool intersect_triangle_triangle (Scene* scene0, unsigned geomID0, unsigned primID0, Scene* scene1, unsigned geomID1, unsigned primID1)75{76CSTAT(bvh_collide_prim_intersections1++);77const TriangleMesh* mesh0 = scene0->get<TriangleMesh>(geomID0);78const TriangleMesh* mesh1 = scene1->get<TriangleMesh>(geomID1);79const TriangleMesh::Triangle& tri0 = mesh0->triangle(primID0);80const TriangleMesh::Triangle& tri1 = mesh1->triangle(primID1);8182/* special culling for scene intersection with itself */83if (scene0 == scene1 && geomID0 == geomID1)84{85/* ignore self intersections */86if (primID0 == primID1)87return false;88}89CSTAT(bvh_collide_prim_intersections2++);9091if (scene0 == scene1 && geomID0 == geomID1)92{93/* ignore intersection with topological neighbors */94const vint4 t0(tri0.v[0],tri0.v[1],tri0.v[2],tri0.v[2]);95if (any(vint4(tri1.v[0]) == t0)) return false;96if (any(vint4(tri1.v[1]) == t0)) return false;97if (any(vint4(tri1.v[2]) == t0)) return false;98}99CSTAT(bvh_collide_prim_intersections3++);100101const Vec3fa a0 = mesh0->vertex(tri0.v[0]);102const Vec3fa a1 = mesh0->vertex(tri0.v[1]);103const Vec3fa a2 = mesh0->vertex(tri0.v[2]);104const Vec3fa b0 = mesh1->vertex(tri1.v[0]);105const Vec3fa b1 = mesh1->vertex(tri1.v[1]);106const Vec3fa b2 = mesh1->vertex(tri1.v[2]);107108return TriangleTriangleIntersector::intersect_triangle_triangle(a0,a1,a2,b0,b1,b2);109}110111template<int N>112__forceinline void BVHNColliderUserGeom<N>::processLeaf(NodeRef node0, NodeRef node1)113{114Collision collisions[16];115size_t num_collisions = 0;116117size_t N0; Object* leaf0 = (Object*) node0.leaf(N0);118size_t N1; Object* leaf1 = (Object*) node1.leaf(N1);119for (size_t i=0; i<N0; i++) {120for (size_t j=0; j<N1; j++) {121const unsigned geomID0 = leaf0[i].geomID();122const unsigned primID0 = leaf0[i].primID();123const unsigned geomID1 = leaf1[j].geomID();124const unsigned primID1 = leaf1[j].primID();125if (this->scene0 == this->scene1 && geomID0 == geomID1 && primID0 == primID1) continue;126collisions[num_collisions++] = Collision(geomID0,primID0,geomID1,primID1);127if (num_collisions == 16) {128this->callback(this->userPtr,(RTCCollision*)&collisions,num_collisions);129num_collisions = 0;130}131}132}133if (num_collisions)134this->callback(this->userPtr,(RTCCollision*)&collisions,num_collisions);135}136137template<int N>138void BVHNCollider<N>::collide_recurse(NodeRef ref0, const BBox3fa& bounds0, NodeRef ref1, const BBox3fa& bounds1, size_t depth0, size_t depth1)139{140CSTAT(bvh_collide_traversal_steps++);141if (unlikely(ref0.isLeaf())) {142if (unlikely(ref1.isLeaf())) {143CSTAT(bvh_collide_leaf_pairs++);144processLeaf(ref0,ref1);145return;146} else goto recurse_node1;147148} else {149if (unlikely(ref1.isLeaf())) {150goto recurse_node0;151} else {152if (area(bounds0) > area(bounds1)) {153goto recurse_node0;154}155else {156goto recurse_node1;157}158}159}160161{162recurse_node0:163AABBNode* node0 = ref0.getAABBNode();164size_t mask = overlap<N>(bounds1,*node0);165//for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {166//for (size_t i=0; i<N; i++) {167#if 0168if (depth0 < parallel_depth_threshold)169{170parallel_for(size_t(N), [&] ( size_t i ) {171if (mask & ( 1 << i)) {172BVHN<N>::prefetch(node0->child(i),BVH_FLAG_ALIGNED_NODE);173collide_recurse(node0->child(i),node0->bounds(i),ref1,bounds1,depth0+1,depth1);174}175});176}177else178#endif179{180for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {181BVHN<N>::prefetch(node0->child(i),BVH_FLAG_ALIGNED_NODE);182collide_recurse(node0->child(i),node0->bounds(i),ref1,bounds1,depth0+1,depth1);183}184}185return;186}187188{189recurse_node1:190AABBNode* node1 = ref1.getAABBNode();191size_t mask = overlap<N>(bounds0,*node1);192//for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {193//for (size_t i=0; i<N; i++) {194#if 0195if (depth1 < parallel_depth_threshold)196{197parallel_for(size_t(N), [&] ( size_t i ) {198if (mask & ( 1 << i)) {199BVHN<N>::prefetch(node1->child(i),BVH_FLAG_ALIGNED_NODE);200collide_recurse(ref0,bounds0,node1->child(i),node1->bounds(i),depth0,depth1+1);201}202});203}204else205#endif206{207for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {208BVHN<N>::prefetch(node1->child(i),BVH_FLAG_ALIGNED_NODE);209collide_recurse(ref0,bounds0,node1->child(i),node1->bounds(i),depth0,depth1+1);210}211}212return;213}214}215216template<int N>217void BVHNCollider<N>::split(const CollideJob& job, jobvector& jobs)218{219if (unlikely(job.ref0.isLeaf())) {220if (unlikely(job.ref1.isLeaf())) {221jobs.push_back(job);222return;223} else goto recurse_node1;224} else {225if (unlikely(job.ref1.isLeaf())) {226goto recurse_node0;227} else {228if (area(job.bounds0) > area(job.bounds1)) {229goto recurse_node0;230}231else {232goto recurse_node1;233}234}235}236237{238recurse_node0:239const AABBNode* node0 = job.ref0.getAABBNode();240size_t mask = overlap<N>(job.bounds1,*node0);241for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {242jobs.push_back(CollideJob(node0->child(i),node0->bounds(i),job.depth0+1,job.ref1,job.bounds1,job.depth1));243}244return;245}246247{248recurse_node1:249const AABBNode* node1 = job.ref1.getAABBNode();250size_t mask = overlap<N>(job.bounds0,*node1);251for (size_t m=mask, i=bsf(m); m!=0; m=btc(m,i), i=bsf(m)) {252jobs.push_back(CollideJob(job.ref0,job.bounds0,job.depth0,node1->child(i),node1->bounds(i),job.depth1+1));253}254return;255}256}257258template<int N>259void BVHNCollider<N>::collide_recurse_entry(NodeRef ref0, const BBox3fa& bounds0, NodeRef ref1, const BBox3fa& bounds1)260{261CSTAT(bvh_collide_traversal_steps = 0);262CSTAT(bvh_collide_leaf_pairs = 0);263CSTAT(bvh_collide_leaf_iterations = 0);264CSTAT(bvh_collide_prim_intersections1 = 0);265CSTAT(bvh_collide_prim_intersections2 = 0);266CSTAT(bvh_collide_prim_intersections3 = 0);267CSTAT(bvh_collide_prim_intersections4 = 0);268CSTAT(bvh_collide_prim_intersections5 = 0);269CSTAT(bvh_collide_prim_intersections = 0);270#if 0271collide_recurse(ref0,bounds0,ref1,bounds1,0,0);272#else273const int M = 2048;274jobvector jobs[2];275jobs[0].reserve(M);276jobs[1].reserve(M);277jobs[0].push_back(CollideJob(ref0,bounds0,0,ref1,bounds1,0));278int source = 0;279int target = 1;280281/* try to split job until job list is full */282while (jobs[source].size()+8 <= M)283{284for (size_t i=0; i<jobs[source].size(); i++)285{286const CollideJob& job = jobs[source][i];287size_t remaining = jobs[source].size()-i;288if (jobs[target].size()+remaining+8 > M) {289jobs[target].push_back(job);290} else {291split(job,jobs[target]);292}293}294295/* stop splitting jobs if we reached only leaves and cannot make progress anymore */296if (jobs[target].size() == jobs[source].size())297break;298299jobs[source].resize(0);300std::swap(source,target);301}302303/* parallel processing of all jobs */304parallel_for(size_t(jobs[source].size()), [&] ( size_t i ) {305CollideJob& j = jobs[source][i];306collide_recurse(j.ref0,j.bounds0,j.ref1,j.bounds1,j.depth0,j.depth1);307});308309310#endif311CSTAT(PRINT(bvh_collide_traversal_steps));312CSTAT(PRINT(bvh_collide_leaf_pairs));313CSTAT(PRINT(bvh_collide_leaf_iterations));314CSTAT(PRINT(bvh_collide_prim_intersections1));315CSTAT(PRINT(bvh_collide_prim_intersections2));316CSTAT(PRINT(bvh_collide_prim_intersections3));317CSTAT(PRINT(bvh_collide_prim_intersections4));318CSTAT(PRINT(bvh_collide_prim_intersections5));319CSTAT(PRINT(bvh_collide_prim_intersections));320}321322template<int N>323void BVHNColliderUserGeom<N>::collide(BVH* __restrict__ bvh0, BVH* __restrict__ bvh1, RTCCollideFunc callback, void* userPtr)324{325BVHNColliderUserGeom<N>(bvh0->scene,bvh1->scene,callback,userPtr).326collide_recurse_entry(bvh0->root,bvh0->bounds.bounds(),bvh1->root,bvh1->bounds.bounds());327}328329#if defined (EMBREE_LOWEST_ISA)330struct collision_regression_test : public RegressionTest331{332collision_regression_test(const char* name) : RegressionTest(name) {333registerRegressionTest(this);334}335336bool run ()337{338bool passed = true;339passed &= 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),340Vec3fa(0.00245f, 0.037612f, -2.49875e-06f), Vec3fa(0.01434f, 0.042634f, -2.49875e-06f), Vec3fa(0.013499f, 0.031309f, -2.49875e-06f)) == false;341passed &= 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;342passed &= 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;343passed &= 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;344passed &= 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;345passed &= 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;346passed &= 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;347passed &= 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;348passed &= 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;349passed &= 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;350passed &= 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;351passed &= 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;352passed &= 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;353passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0),354Vec3fa(-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;355passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0),356Vec3fa( 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;357passed &= TriangleTriangleIntersector::intersect_triangle_triangle (Vec3fa(0,0,0),Vec3fa(1,0,0),Vec3fa(0,1,0),358Vec3fa(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;359return passed;360}361};362363collision_regression_test collision_regression("collision_regression_test");364#endif365366////////////////////////////////////////////////////////////////////////////////367/// Collider Definitions368////////////////////////////////////////////////////////////////////////////////369370DEFINE_COLLIDER(BVH4ColliderUserGeom,BVHNColliderUserGeom<4>);371372#if defined(__AVX__)373DEFINE_COLLIDER(BVH8ColliderUserGeom,BVHNColliderUserGeom<8>);374#endif375}376}377378379