bvh_builder_morton.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. // Copyright 2009-2021 Intel Corporation
  2. // SPDX-License-Identifier: Apache-2.0
  3. #include "bvh.h"
  4. #include "bvh_statistics.h"
  5. #include "bvh_rotate.h"
  6. #include "../common/profile.h"
  7. #include "../../common/algorithms/parallel_prefix_sum.h"
  8. #include "../builders/primrefgen.h"
  9. #include "../builders/bvh_builder_morton.h"
  10. #include "../geometry/triangle.h"
  11. #include "../geometry/trianglev.h"
  12. #include "../geometry/trianglei.h"
  13. #include "../geometry/quadv.h"
  14. #include "../geometry/quadi.h"
  15. #include "../geometry/object.h"
  16. #include "../geometry/instance.h"
  17. #if defined(__64BIT__)
  18. # define ROTATE_TREE 1 // specifies number of tree rotation rounds to perform
  19. #else
  20. # define ROTATE_TREE 0 // do not use tree rotations on 32 bit platforms, barrier bit in NodeRef will cause issues
  21. #endif
  22. namespace embree
  23. {
  24. namespace isa
  25. {
  26. template<int N>
  27. struct SetBVHNBounds
  28. {
  29. typedef BVHN<N> BVH;
  30. typedef typename BVH::NodeRef NodeRef;
  31. typedef typename BVH::NodeRecord NodeRecord;
  32. typedef typename BVH::AABBNode AABBNode;
  33. BVH* bvh;
  34. __forceinline SetBVHNBounds (BVH* bvh) : bvh(bvh) {}
  35. __forceinline NodeRecord operator() (NodeRef ref, const NodeRecord* children, size_t num)
  36. {
  37. AABBNode* node = ref.getAABBNode();
  38. BBox3fa res = empty;
  39. for (size_t i=0; i<num; i++) {
  40. const BBox3fa b = children[i].bounds;
  41. res.extend(b);
  42. node->setRef(i,children[i].ref);
  43. node->setBounds(i,b);
  44. }
  45. BBox3fx result = (BBox3fx&)res;
  46. #if ROTATE_TREE
  47. if (N == 4)
  48. {
  49. size_t n = 0;
  50. for (size_t i=0; i<num; i++)
  51. n += children[i].bounds.lower.a;
  52. if (n >= 4096) {
  53. for (size_t i=0; i<num; i++) {
  54. if (children[i].bounds.lower.a < 4096) {
  55. for (int j=0; j<ROTATE_TREE; j++)
  56. BVHNRotate<N>::rotate(node->child(i));
  57. node->child(i).setBarrier();
  58. }
  59. }
  60. }
  61. result.lower.a = unsigned(n);
  62. }
  63. #endif
  64. return NodeRecord(ref,result);
  65. }
  66. };
  67. template<int N, typename Primitive>
  68. struct CreateMortonLeaf;
  69. template<int N>
  70. struct CreateMortonLeaf<N,Triangle4>
  71. {
  72. typedef BVHN<N> BVH;
  73. typedef typename BVH::NodeRef NodeRef;
  74. typedef typename BVH::NodeRecord NodeRecord;
  75. __forceinline CreateMortonLeaf (TriangleMesh* mesh, unsigned int geomID, BVHBuilderMorton::BuildPrim* morton)
  76. : mesh(mesh), morton(morton), geomID_(geomID) {}
  77. __noinline NodeRecord operator() (const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc)
  78. {
  79. vfloat4 lower(pos_inf);
  80. vfloat4 upper(neg_inf);
  81. size_t items = current.size();
  82. size_t start = current.begin();
  83. assert(items<=4);
  84. /* allocate leaf node */
  85. Triangle4* accel = (Triangle4*) alloc.malloc1(sizeof(Triangle4),BVH::byteAlignment);
  86. NodeRef ref = BVH::encodeLeaf((char*)accel,1);
  87. vuint4 vgeomID = -1, vprimID = -1;
  88. Vec3vf4 v0 = zero, v1 = zero, v2 = zero;
  89. const TriangleMesh* __restrict__ const mesh = this->mesh;
  90. for (size_t i=0; i<items; i++)
  91. {
  92. const unsigned int primID = morton[start+i].index;
  93. const TriangleMesh::Triangle& tri = mesh->triangle(primID);
  94. const Vec3fa& p0 = mesh->vertex(tri.v[0]);
  95. const Vec3fa& p1 = mesh->vertex(tri.v[1]);
  96. const Vec3fa& p2 = mesh->vertex(tri.v[2]);
  97. lower = min(lower,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
  98. upper = max(upper,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
  99. vgeomID [i] = geomID_;
  100. vprimID [i] = primID;
  101. v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
  102. v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
  103. v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
  104. }
  105. Triangle4::store_nt(accel,Triangle4(v0,v1,v2,vgeomID,vprimID));
  106. BBox3fx box_o = BBox3fx((Vec3fx)lower,(Vec3fx)upper);
  107. #if ROTATE_TREE
  108. if (N == 4)
  109. box_o.lower.a = unsigned(current.size());
  110. #endif
  111. return NodeRecord(ref,box_o);
  112. }
  113. private:
  114. TriangleMesh* mesh;
  115. BVHBuilderMorton::BuildPrim* morton;
  116. unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
  117. };
  118. template<int N>
  119. struct CreateMortonLeaf<N,Triangle4v>
  120. {
  121. typedef BVHN<N> BVH;
  122. typedef typename BVH::NodeRef NodeRef;
  123. typedef typename BVH::NodeRecord NodeRecord;
  124. __forceinline CreateMortonLeaf (TriangleMesh* mesh, unsigned int geomID, BVHBuilderMorton::BuildPrim* morton)
  125. : mesh(mesh), morton(morton), geomID_(geomID) {}
  126. __noinline NodeRecord operator() (const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc)
  127. {
  128. vfloat4 lower(pos_inf);
  129. vfloat4 upper(neg_inf);
  130. size_t items = current.size();
  131. size_t start = current.begin();
  132. assert(items<=4);
  133. /* allocate leaf node */
  134. Triangle4v* accel = (Triangle4v*) alloc.malloc1(sizeof(Triangle4v),BVH::byteAlignment);
  135. NodeRef ref = BVH::encodeLeaf((char*)accel,1);
  136. vuint4 vgeomID = -1, vprimID = -1;
  137. Vec3vf4 v0 = zero, v1 = zero, v2 = zero;
  138. const TriangleMesh* __restrict__ mesh = this->mesh;
  139. for (size_t i=0; i<items; i++)
  140. {
  141. const unsigned int primID = morton[start+i].index;
  142. const TriangleMesh::Triangle& tri = mesh->triangle(primID);
  143. const Vec3fa& p0 = mesh->vertex(tri.v[0]);
  144. const Vec3fa& p1 = mesh->vertex(tri.v[1]);
  145. const Vec3fa& p2 = mesh->vertex(tri.v[2]);
  146. lower = min(lower,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
  147. upper = max(upper,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
  148. vgeomID [i] = geomID_;
  149. vprimID [i] = primID;
  150. v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
  151. v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
  152. v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
  153. }
  154. Triangle4v::store_nt(accel,Triangle4v(v0,v1,v2,vgeomID,vprimID));
  155. BBox3fx box_o = BBox3fx((Vec3fx)lower,(Vec3fx)upper);
  156. #if ROTATE_TREE
  157. if (N == 4)
  158. box_o.lower.a = current.size();
  159. #endif
  160. return NodeRecord(ref,box_o);
  161. }
  162. private:
  163. TriangleMesh* mesh;
  164. BVHBuilderMorton::BuildPrim* morton;
  165. unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
  166. };
  167. template<int N>
  168. struct CreateMortonLeaf<N,Triangle4i>
  169. {
  170. typedef BVHN<N> BVH;
  171. typedef typename BVH::NodeRef NodeRef;
  172. typedef typename BVH::NodeRecord NodeRecord;
  173. __forceinline CreateMortonLeaf (TriangleMesh* mesh, unsigned int geomID, BVHBuilderMorton::BuildPrim* morton)
  174. : mesh(mesh), morton(morton), geomID_(geomID) {}
  175. __noinline NodeRecord operator() (const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc)
  176. {
  177. vfloat4 lower(pos_inf);
  178. vfloat4 upper(neg_inf);
  179. size_t items = current.size();
  180. size_t start = current.begin();
  181. assert(items<=4);
  182. /* allocate leaf node */
  183. Triangle4i* accel = (Triangle4i*) alloc.malloc1(sizeof(Triangle4i),BVH::byteAlignment);
  184. NodeRef ref = BVH::encodeLeaf((char*)accel,1);
  185. vuint4 v0 = zero, v1 = zero, v2 = zero;
  186. vuint4 vgeomID = -1, vprimID = -1;
  187. const TriangleMesh* __restrict__ const mesh = this->mesh;
  188. for (size_t i=0; i<items; i++)
  189. {
  190. const unsigned int primID = morton[start+i].index;
  191. const TriangleMesh::Triangle& tri = mesh->triangle(primID);
  192. const Vec3fa& p0 = mesh->vertex(tri.v[0]);
  193. const Vec3fa& p1 = mesh->vertex(tri.v[1]);
  194. const Vec3fa& p2 = mesh->vertex(tri.v[2]);
  195. lower = min(lower,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
  196. upper = max(upper,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2);
  197. vgeomID[i] = geomID_;
  198. vprimID[i] = primID;
  199. unsigned int int_stride = mesh->vertices0.getStride()/4;
  200. v0[i] = tri.v[0] * int_stride;
  201. v1[i] = tri.v[1] * int_stride;
  202. v2[i] = tri.v[2] * int_stride;
  203. }
  204. for (size_t i=items; i<4; i++)
  205. {
  206. vgeomID[i] = vgeomID[0];
  207. vprimID[i] = -1;
  208. v0[i] = 0;
  209. v1[i] = 0;
  210. v2[i] = 0;
  211. }
  212. Triangle4i::store_nt(accel,Triangle4i(v0,v1,v2,vgeomID,vprimID));
  213. BBox3fx box_o = BBox3fx((Vec3fx)lower,(Vec3fx)upper);
  214. #if ROTATE_TREE
  215. if (N == 4)
  216. box_o.lower.a = current.size();
  217. #endif
  218. return NodeRecord(ref,box_o);
  219. }
  220. private:
  221. TriangleMesh* mesh;
  222. BVHBuilderMorton::BuildPrim* morton;
  223. unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
  224. };
  225. template<int N>
  226. struct CreateMortonLeaf<N,Quad4v>
  227. {
  228. typedef BVHN<N> BVH;
  229. typedef typename BVH::NodeRef NodeRef;
  230. typedef typename BVH::NodeRecord NodeRecord;
  231. __forceinline CreateMortonLeaf (QuadMesh* mesh, unsigned int geomID, BVHBuilderMorton::BuildPrim* morton)
  232. : mesh(mesh), morton(morton), geomID_(geomID) {}
  233. __noinline NodeRecord operator() (const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc)
  234. {
  235. vfloat4 lower(pos_inf);
  236. vfloat4 upper(neg_inf);
  237. size_t items = current.size();
  238. size_t start = current.begin();
  239. assert(items<=4);
  240. /* allocate leaf node */
  241. Quad4v* accel = (Quad4v*) alloc.malloc1(sizeof(Quad4v),BVH::byteAlignment);
  242. NodeRef ref = BVH::encodeLeaf((char*)accel,1);
  243. vuint4 vgeomID = -1, vprimID = -1;
  244. Vec3vf4 v0 = zero, v1 = zero, v2 = zero, v3 = zero;
  245. const QuadMesh* __restrict__ mesh = this->mesh;
  246. for (size_t i=0; i<items; i++)
  247. {
  248. const unsigned int primID = morton[start+i].index;
  249. const QuadMesh::Quad& tri = mesh->quad(primID);
  250. const Vec3fa& p0 = mesh->vertex(tri.v[0]);
  251. const Vec3fa& p1 = mesh->vertex(tri.v[1]);
  252. const Vec3fa& p2 = mesh->vertex(tri.v[2]);
  253. const Vec3fa& p3 = mesh->vertex(tri.v[3]);
  254. lower = min(lower,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2,(vfloat4)p3);
  255. upper = max(upper,(vfloat4)p0,(vfloat4)p1,(vfloat4)p2,(vfloat4)p3);
  256. vgeomID [i] = geomID_;
  257. vprimID [i] = primID;
  258. v0.x[i] = p0.x; v0.y[i] = p0.y; v0.z[i] = p0.z;
  259. v1.x[i] = p1.x; v1.y[i] = p1.y; v1.z[i] = p1.z;
  260. v2.x[i] = p2.x; v2.y[i] = p2.y; v2.z[i] = p2.z;
  261. v3.x[i] = p3.x; v3.y[i] = p3.y; v3.z[i] = p3.z;
  262. }
  263. Quad4v::store_nt(accel,Quad4v(v0,v1,v2,v3,vgeomID,vprimID));
  264. BBox3fx box_o = BBox3fx((Vec3fx)lower,(Vec3fx)upper);
  265. #if ROTATE_TREE
  266. if (N == 4)
  267. box_o.lower.a = current.size();
  268. #endif
  269. return NodeRecord(ref,box_o);
  270. }
  271. private:
  272. QuadMesh* mesh;
  273. BVHBuilderMorton::BuildPrim* morton;
  274. unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
  275. };
  276. template<int N>
  277. struct CreateMortonLeaf<N,Object>
  278. {
  279. typedef BVHN<N> BVH;
  280. typedef typename BVH::NodeRef NodeRef;
  281. typedef typename BVH::NodeRecord NodeRecord;
  282. __forceinline CreateMortonLeaf (UserGeometry* mesh, unsigned int geomID, BVHBuilderMorton::BuildPrim* morton)
  283. : mesh(mesh), morton(morton), geomID_(geomID) {}
  284. __noinline NodeRecord operator() (const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc)
  285. {
  286. vfloat4 lower(pos_inf);
  287. vfloat4 upper(neg_inf);
  288. size_t items = current.size();
  289. size_t start = current.begin();
  290. /* allocate leaf node */
  291. Object* accel = (Object*) alloc.malloc1(items*sizeof(Object),BVH::byteAlignment);
  292. NodeRef ref = BVH::encodeLeaf((char*)accel,items);
  293. const UserGeometry* mesh = this->mesh;
  294. BBox3fa bounds = empty;
  295. for (size_t i=0; i<items; i++)
  296. {
  297. const unsigned int index = morton[start+i].index;
  298. const unsigned int primID = index;
  299. bounds.extend(mesh->bounds(primID));
  300. new (&accel[i]) Object(geomID_,primID);
  301. }
  302. BBox3fx box_o = (BBox3fx&)bounds;
  303. #if ROTATE_TREE
  304. if (N == 4)
  305. box_o.lower.a = current.size();
  306. #endif
  307. return NodeRecord(ref,box_o);
  308. }
  309. private:
  310. UserGeometry* mesh;
  311. BVHBuilderMorton::BuildPrim* morton;
  312. unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
  313. };
  314. template<int N>
  315. struct CreateMortonLeaf<N,InstancePrimitive>
  316. {
  317. typedef BVHN<N> BVH;
  318. typedef typename BVH::NodeRef NodeRef;
  319. typedef typename BVH::NodeRecord NodeRecord;
  320. __forceinline CreateMortonLeaf (Instance* mesh, unsigned int geomID, BVHBuilderMorton::BuildPrim* morton)
  321. : mesh(mesh), morton(morton), geomID_(geomID) {}
  322. __noinline NodeRecord operator() (const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc)
  323. {
  324. vfloat4 lower(pos_inf);
  325. vfloat4 upper(neg_inf);
  326. size_t items = current.size();
  327. size_t start = current.begin();
  328. assert(items <= 1);
  329. /* allocate leaf node */
  330. InstancePrimitive* accel = (InstancePrimitive*) alloc.malloc1(items*sizeof(InstancePrimitive),BVH::byteAlignment);
  331. NodeRef ref = BVH::encodeLeaf((char*)accel,items);
  332. const Instance* instance = this->mesh;
  333. BBox3fa bounds = empty;
  334. for (size_t i=0; i<items; i++)
  335. {
  336. const unsigned int primID = morton[start+i].index;
  337. bounds.extend(instance->bounds(primID));
  338. new (&accel[i]) InstancePrimitive(instance, geomID_);
  339. }
  340. BBox3fx box_o = (BBox3fx&)bounds;
  341. #if ROTATE_TREE
  342. if (N == 4)
  343. box_o.lower.a = current.size();
  344. #endif
  345. return NodeRecord(ref,box_o);
  346. }
  347. private:
  348. Instance* mesh;
  349. BVHBuilderMorton::BuildPrim* morton;
  350. unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
  351. };
  352. template<typename Mesh>
  353. struct CalculateMeshBounds
  354. {
  355. __forceinline CalculateMeshBounds (Mesh* mesh)
  356. : mesh(mesh) {}
  357. __forceinline const BBox3fa operator() (const BVHBuilderMorton::BuildPrim& morton) {
  358. return mesh->bounds(morton.index);
  359. }
  360. private:
  361. Mesh* mesh;
  362. };
  363. template<int N, typename Mesh, typename Primitive>
  364. class BVHNMeshBuilderMorton : public Builder
  365. {
  366. typedef BVHN<N> BVH;
  367. typedef typename BVH::AABBNode AABBNode;
  368. typedef typename BVH::NodeRef NodeRef;
  369. typedef typename BVH::NodeRecord NodeRecord;
  370. public:
  371. BVHNMeshBuilderMorton (BVH* bvh, Mesh* mesh, unsigned int geomID, const size_t minLeafSize, const size_t maxLeafSize, const size_t singleThreadThreshold = DEFAULT_SINGLE_THREAD_THRESHOLD)
  372. : bvh(bvh), mesh(mesh), morton(bvh->device,0), settings(N,BVH::maxBuildDepth,minLeafSize,min(maxLeafSize,Primitive::max_size()*BVH::maxLeafBlocks),singleThreadThreshold), geomID_(geomID) {}
  373. /* build function */
  374. void build()
  375. {
  376. /* we reset the allocator when the mesh size changed */
  377. if (mesh->numPrimitives != numPreviousPrimitives) {
  378. bvh->alloc.clear();
  379. morton.clear();
  380. }
  381. size_t numPrimitives = mesh->size();
  382. numPreviousPrimitives = numPrimitives;
  383. /* skip build for empty scene */
  384. if (numPrimitives == 0) {
  385. bvh->set(BVH::emptyNode,empty,0);
  386. return;
  387. }
  388. /* preallocate arrays */
  389. morton.resize(numPrimitives);
  390. size_t bytesEstimated = numPrimitives*sizeof(AABBNode)/(4*N) + size_t(1.2f*Primitive::blocks(numPrimitives)*sizeof(Primitive));
  391. size_t bytesMortonCodes = numPrimitives*sizeof(BVHBuilderMorton::BuildPrim);
  392. bytesEstimated = max(bytesEstimated,bytesMortonCodes); // the first allocation block is reused to sort the morton codes
  393. bvh->alloc.init(bytesMortonCodes,bytesMortonCodes,bytesEstimated);
  394. /* create morton code array */
  395. BVHBuilderMorton::BuildPrim* dest = (BVHBuilderMorton::BuildPrim*) bvh->alloc.specialAlloc(bytesMortonCodes);
  396. size_t numPrimitivesGen = createMortonCodeArray<Mesh>(mesh,morton,bvh->scene->progressInterface);
  397. /* create BVH */
  398. SetBVHNBounds<N> setBounds(bvh);
  399. CreateMortonLeaf<N,Primitive> createLeaf(mesh,geomID_,morton.data());
  400. CalculateMeshBounds<Mesh> calculateBounds(mesh);
  401. auto root = BVHBuilderMorton::build<NodeRecord>(
  402. typename BVH::CreateAlloc(bvh),
  403. typename BVH::AABBNode::Create(),
  404. setBounds,createLeaf,calculateBounds,bvh->scene->progressInterface,
  405. morton.data(),dest,numPrimitivesGen,settings);
  406. bvh->set(root.ref,LBBox3fa(root.bounds),numPrimitives);
  407. #if ROTATE_TREE
  408. if (N == 4)
  409. {
  410. for (int i=0; i<ROTATE_TREE; i++)
  411. BVHNRotate<N>::rotate(bvh->root);
  412. bvh->clearBarrier(bvh->root);
  413. }
  414. #endif
  415. /* clear temporary data for static geometry */
  416. if (bvh->scene->isStaticAccel()) {
  417. morton.clear();
  418. }
  419. bvh->cleanup();
  420. }
  421. void clear() {
  422. morton.clear();
  423. }
  424. private:
  425. BVH* bvh;
  426. Mesh* mesh;
  427. mvector<BVHBuilderMorton::BuildPrim> morton;
  428. BVHBuilderMorton::Settings settings;
  429. unsigned int geomID_ = std::numeric_limits<unsigned int>::max();
  430. unsigned int numPreviousPrimitives = 0;
  431. };
  432. #if defined(EMBREE_GEOMETRY_TRIANGLE)
  433. Builder* BVH4Triangle4MeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,TriangleMesh,Triangle4> ((BVH4*)bvh,mesh,geomID,4,4); }
  434. Builder* BVH4Triangle4vMeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,TriangleMesh,Triangle4v>((BVH4*)bvh,mesh,geomID,4,4); }
  435. Builder* BVH4Triangle4iMeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,TriangleMesh,Triangle4i>((BVH4*)bvh,mesh,geomID,4,4); }
  436. #if defined(__AVX__)
  437. Builder* BVH8Triangle4MeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,TriangleMesh,Triangle4> ((BVH8*)bvh,mesh,geomID,4,4); }
  438. Builder* BVH8Triangle4vMeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,TriangleMesh,Triangle4v>((BVH8*)bvh,mesh,geomID,4,4); }
  439. Builder* BVH8Triangle4iMeshBuilderMortonGeneral (void* bvh, TriangleMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,TriangleMesh,Triangle4i>((BVH8*)bvh,mesh,geomID,4,4); }
  440. #endif
  441. #endif
  442. #if defined(EMBREE_GEOMETRY_QUAD)
  443. Builder* BVH4Quad4vMeshBuilderMortonGeneral (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,QuadMesh,Quad4v>((BVH4*)bvh,mesh,geomID,4,4); }
  444. #if defined(__AVX__)
  445. Builder* BVH8Quad4vMeshBuilderMortonGeneral (void* bvh, QuadMesh* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,QuadMesh,Quad4v>((BVH8*)bvh,mesh,geomID,4,4); }
  446. #endif
  447. #endif
  448. #if defined(EMBREE_GEOMETRY_USER)
  449. Builder* BVH4VirtualMeshBuilderMortonGeneral (void* bvh, UserGeometry* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,UserGeometry,Object>((BVH4*)bvh,mesh,geomID,1,BVH4::maxLeafBlocks); }
  450. #if defined(__AVX__)
  451. Builder* BVH8VirtualMeshBuilderMortonGeneral (void* bvh, UserGeometry* mesh, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,UserGeometry,Object>((BVH8*)bvh,mesh,geomID,1,BVH4::maxLeafBlocks); }
  452. #endif
  453. #endif
  454. #if defined(EMBREE_GEOMETRY_INSTANCE)
  455. Builder* BVH4InstanceMeshBuilderMortonGeneral (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,Instance,InstancePrimitive>((BVH4*)bvh,mesh,gtype,geomID,1,BVH4::maxLeafBlocks); }
  456. #if defined(__AVX__)
  457. Builder* BVH8InstanceMeshBuilderMortonGeneral (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,Instance,InstancePrimitive>((BVH8*)bvh,mesh,gtype,geomID,1,BVH4::maxLeafBlocks); }
  458. #endif
  459. #endif
  460. }
  461. }