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