70#define kNANORT_MAX_STACK_DEPTH (512)
71#define kNANORT_MIN_PRIMITIVES_FOR_PARALLEL_BUILD (1024 * 8)
72#define kNANORT_SHALLOW_DEPTH (4)
74#ifdef NANORT_USE_CPP11_FEATURE
82#define kNANORT_MAX_THREADS (256)
85#ifndef NANORT_ENABLE_PARALLEL_BUILD
86#define NANORT_ENABLE_PARALLEL_BUILD
104#pragma clang diagnostic push
105#if __has_warning("-Wzero-as-null-pointer-constant")
106#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
137 template <
typename T,
size_t stack_capacity>
140 typedef typename std::allocator<T>::pointer
pointer;
141 typedef typename std::allocator<T>::size_type
size_type;
173 template <
typename U>
191 template <
typename U,
size_t other_capacity>
204 n <= stack_capacity) {
209 return std::allocator<T>::allocate(n, hint);
219 std::allocator<T>::deallocate(p, n);
234 template <
typename TContainerType,
int stack_capacity>
266 const typename Allocator::Source& stack_data()
const {
return stack_data_; }
286 template <
typename T,
size_t stack_capacity>
288 :
public StackContainer<std::vector<T, StackAllocator<T, stack_capacity> >,
302 this->
container().assign(other->begin(), other->end());
307 this->
container().assign(other->begin(), other->end());
321 template <
typename T =
float>
341 inline T
x()
const {
return v[0]; }
342 inline T
y()
const {
return v[1]; }
343 inline T
z()
const {
return v[2]; }
347 return real3(
x() - f2.
x(),
y() - f2.
y(),
z() - f2.
z());
350 return real3(
x() * f2.
x(),
y() * f2.
y(),
z() * f2.
z());
353 return real3(
x() + f2.
x(),
y() + f2.
y(),
z() + f2.
z());
362 return real3(
x() / f2.
x(),
y() / f2.
y(),
z() / f2.
z());
372 template <
typename T>
377 template <
typename T>
382 template <
typename T>
384 return std::sqrt(rhs.
x() * rhs.
x() + rhs.
y() * rhs.
y() + rhs.
z() * rhs.
z());
387 template <
typename T>
391 if (std::fabs(len) > std::numeric_limits<T>::epsilon()) {
392 T inv_len =
static_cast<T
>(1.0) / len;
400 template <
typename T>
403 c[0] = a[1] * b[2] - a[2] * b[1];
404 c[1] = a[2] * b[0] - a[0] * b[2];
405 c[2] = a[0] * b[1] - a[1] * b[0];
409 template <
typename T>
411 return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
414 template <
typename T>
418#ifdef NANORT_USE_CPP11_FEATURE
420 if (std::fabs(v[0]) < std::numeric_limits<T>::epsilon()) {
421 r[0] = std::numeric_limits<T>::infinity() *
422 std::copysign(
static_cast<T
>(1), v[0]);
425 r[0] =
static_cast<T
>(1.0) / v[0];
428 if (std::fabs(v[1]) < std::numeric_limits<T>::epsilon()) {
429 r[1] = std::numeric_limits<T>::infinity() *
430 std::copysign(
static_cast<T
>(1), v[1]);
433 r[1] =
static_cast<T
>(1.0) / v[1];
436 if (std::fabs(v[2]) < std::numeric_limits<T>::epsilon()) {
437 r[2] = std::numeric_limits<T>::infinity() *
438 std::copysign(
static_cast<T
>(1), v[2]);
441 r[2] =
static_cast<T
>(1.0) / v[2];
445 if (std::fabs(v[0]) < std::numeric_limits<T>::epsilon()) {
446 T sgn = (v[0] <
static_cast<T
>(0)) ?
static_cast<T
>(-1) :
static_cast<T
>(1);
447 r[0] = std::numeric_limits<T>::infinity() * sgn;
450 r[0] =
static_cast<T
>(1.0) / v[0];
453 if (std::fabs(v[1]) < std::numeric_limits<T>::epsilon()) {
454 T sgn = (v[1] <
static_cast<T
>(0)) ?
static_cast<T
>(-1) :
static_cast<T
>(1);
455 r[1] = std::numeric_limits<T>::infinity() * sgn;
458 r[1] =
static_cast<T
>(1.0) / v[1];
461 if (std::fabs(v[2]) < std::numeric_limits<T>::epsilon()) {
462 T sgn = (v[2] <
static_cast<T
>(0)) ?
static_cast<T
>(-1) :
static_cast<T
>(1);
463 r[2] = std::numeric_limits<T>::infinity() * sgn;
466 r[2] =
static_cast<T
>(1.0) / v[2];
473 template <
typename real>
475 const size_t stride_bytes) {
476 return reinterpret_cast<const real*
>(
477 reinterpret_cast<const unsigned char*
>(p) + idx * stride_bytes);
480 template <
typename T =
float>
484 :
min_t(static_cast<T>(0.0)),
485 max_t(
std::numeric_limits<T>::max()),
487 org[0] =
static_cast<T
>(0.0);
488 org[1] =
static_cast<T
>(0.0);
489 org[2] =
static_cast<T
>(0.0);
490 dir[0] =
static_cast<T
>(0.0);
491 dir[1] =
static_cast<T
>(0.0);
492 dir[2] =
static_cast<T
>(-1.0);
504 template <
typename T =
float>
561 bool operator()(
const H& a,
const H& b)
const {
return a.t < b.t; }
565 template <
typename T =
float>
635 template <
typename T>
642 bmin[0] =
bmin[1] =
bmin[2] = std::numeric_limits<T>::max();
643 bmax[0] =
bmax[1] =
bmax[2] = -std::numeric_limits<T>::max();
653 template <
typename T>
657 :
t_min(
std::numeric_limits<T>::max()),
658 t_max(-
std::numeric_limits<T>::max()),
659 node_id(static_cast<unsigned int>(-1)) {}
687 template <
typename T>
704 template <
typename T>
722 template <
class Prim,
class Pred>
723 bool Build(
const unsigned int num_primitives,
const Prim& p,
const Pred& pred,
733#if defined(NANORT_ENABLE_SERIALIZATION)
737 bool Dump(
const char* filename)
const;
738 bool Dump(FILE* fp)
const;
743 bool Load(
const char* filename);
763 template <
class I,
class H>
770 template<
class I,
class H,
class Comp>
771 bool MultiHitTraverse(
const Ray<T>& ray,
772 int max_intersections,
773 const I& intersector,
789 const I& intersector,
800 bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<T>::max();
801 bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<T>::max();
804 bmin[0] =
nodes_[0].bmin[0];
805 bmin[1] =
nodes_[0].bmin[1];
806 bmin[2] =
nodes_[0].bmin[2];
807 bmax[0] =
nodes_[0].bmax[0];
808 bmax[1] =
nodes_[0].bmax[1];
809 bmax[2] =
nodes_[0].bmax[2];
816#if defined(NANORT_ENABLE_PARALLEL_BUILD)
818 unsigned int left_idx;
819 unsigned int right_idx;
824 std::vector<ShallowNodeInfo> shallow_node_infos_;
827 template <
class P,
class Pred>
828 unsigned int BuildShallowTree(std::vector<BVHNode<T> >* out_nodes,
829 unsigned int left_idx,
unsigned int right_idx,
831 unsigned int max_shallow_depth,
const P& p,
836 template <
class P,
class Pred>
839 unsigned int left_idx,
unsigned int right_idx,
840 unsigned int depth,
const P& p,
const Pred& pred);
844 const I& intersector)
const;
849 const I& intersector,
854 template<
class I,
class H,
class Comp>
855 bool MultiHitTestLeafNode(std::priority_queue<H, std::vector<H>, Comp>* isect_pq,
856 int max_intersections,
858 const I& intersector)
const;
870 template <
typename T =
float>
874 const T* vertices,
const unsigned int* faces,
875 size_t vertex_stride_bytes)
877 pos_(static_cast<T>(0.0)),
899 void Set(
int axis, T pos)
const {
908 unsigned int i0 =
faces_[3 * i + 0];
909 unsigned int i1 =
faces_[3 * i + 1];
910 unsigned int i2 =
faces_[3 * i + 2];
916 T center = p0[axis] + p1[axis] + p2[axis];
918 return (center < pos*
static_cast<T
>(3.0));
930 template <
typename T =
float>
934 const T* vertices,
const unsigned int* faces,
935 const size_t vertex_stride_bytes)
943 unsigned int prim_index)
const {
944 unsigned vertex =
faces_[3 * prim_index + 0];
954 for (
unsigned int i = 1; i < 3; i++) {
956 for (
int k = 0; k < 3; k++) {
960 (*bmin)[k] = std::min((*bmin)[k], coord);
961 (*bmax)[k] = std::max((*bmax)[k], coord);
971 template <
typename T =
float>
982 template <
typename T =
float,
class H = TriangleIntersection<T> >
986 const size_t vertex_stride_bytes)
1007 bool Intersect(T* t_inout,
const unsigned int prim_index)
const {
1018 const unsigned int f0 =
faces_[3 * prim_index + 0];
1019 const unsigned int f1 =
faces_[3 * prim_index + 1];
1020 const unsigned int f2 =
faces_[3 * prim_index + 2];
1037 T U = Cx * By - Cy * Bx;
1038 T V = Ax * Cy - Ay * Cx;
1039 T W = Bx * Ay - By * Ax;
1042#pragma clang diagnostic push
1043#pragma clang diagnostic ignored "-Wfloat-equal"
1047 if (U ==
static_cast<T
>(0.0) || V ==
static_cast<T
>(0.0) ||
1048 W ==
static_cast<T
>(0.0)) {
1049 double CxBy =
static_cast<double>(Cx) *
static_cast<double>(By);
1050 double CyBx =
static_cast<double>(Cy) *
static_cast<double>(Bx);
1051 U =
static_cast<T
>(CxBy - CyBx);
1053 double AxCy =
static_cast<double>(Ax) *
static_cast<double>(Cy);
1054 double AyCx =
static_cast<double>(Ay) *
static_cast<double>(Cx);
1055 V =
static_cast<T
>(AxCy - AyCx);
1057 double BxAy =
static_cast<double>(Bx) *
static_cast<double>(Ay);
1058 double ByAx =
static_cast<double>(By) *
static_cast<double>(Ax);
1059 W =
static_cast<T
>(BxAy - ByAx);
1062 if (U <
static_cast<T
>(0.0) || V < static_cast<T>(0.0) ||
1063 W < static_cast<T>(0.0)) {
1065 (U >
static_cast<T
>(0.0) || V >
static_cast<T
>(0.0) ||
1066 W >
static_cast<T
>(0.0))) {
1072 if (det ==
static_cast<T
>(0.0))
return false;
1075#pragma clang diagnostic pop
1081 const T D = U * Az + V * Bz + W * Cz;
1083 const T rcpDet =
static_cast<T
>(1.0) / det;
1086 if (tt > (*t_inout)) {
1109 void Update(T t,
unsigned int prim_idx)
const {
1124 T absDir = std::fabs(ray.
dir[0]);
1125 if (absDir < std::fabs(ray.
dir[1])) {
1127 absDir = std::fabs(ray.
dir[1]);
1129 if (absDir < std::fabs(ray.
dir[2])) {
1131 absDir = std::fabs(ray.
dir[2]);
1152 u_ =
static_cast<T
>(0.0);
1153 v_ =
static_cast<T
>(0.0);
1191 return (a < b) ? a : b;
1195 return (a > b) ? a : b;
1204 bin.resize(2 * 3 * size);
1215 template <
typename T>
1218 return static_cast<T
>(2.0) *
1219 (box[0] * box[1] + box[1] * box[2] + box[2] * box[0]);
1222 template <
typename T>
1225 const unsigned int* faces,
1226 unsigned int index) {
1227 unsigned int f0 = faces[3 * index + 0];
1228 unsigned int f1 = faces[3 * index + 1];
1229 unsigned int f2 = faces[3 * index + 2];
1233 p[0] =
real3<T>(&vertices[3 * f0]);
1234 p[1] =
real3<T>(&vertices[3 * f1]);
1235 p[2] =
real3<T>(&vertices[3 * f2]);
1240 for (
int i = 1; i < 3; i++) {
1241 (*bmin)[0] = std::min((*bmin)[0], p[i][0]);
1242 (*bmin)[1] = std::min((*bmin)[1], p[i][1]);
1243 (*bmin)[2] = std::min((*bmin)[2], p[i][2]);
1245 (*bmax)[0] = std::max((*bmax)[0], p[i][0]);
1246 (*bmax)[1] = std::max((*bmax)[1], p[i][1]);
1247 (*bmax)[2] = std::max((*bmax)[2], p[i][2]);
1251 template <
typename T,
class P>
1255 unsigned int* indices,
unsigned int left_idx,
1256 unsigned int right_idx,
const P& p) {
1257 T bin_size =
static_cast<T
>(bins->
bin_size);
1260 real3<T> scene_size, scene_inv_size;
1261 scene_size = scene_max - scene_min;
1263 for (
int i = 0; i < 3; ++i) {
1264 assert(scene_size[i] >=
static_cast<T
>(0.0));
1266 if (scene_size[i] >
static_cast<T
>(0.0)) {
1267 scene_inv_size[i] = bin_size / scene_size[i];
1270 scene_inv_size[i] =
static_cast<T
>(0.0);
1275 std::fill(bins->
bin.begin(), bins->
bin.end(), 0);
1281 for (
size_t i = left_idx; i < right_idx; i++) {
1290 p.BoundingBox(&bmin, &bmax, indices[i]);
1293 real3<T> quantized_bmin = (bmin - scene_min) * scene_inv_size;
1294 real3<T> quantized_bmax = (bmax - scene_min) * scene_inv_size;
1297 for (
int j = 0; j < 3; ++j) {
1298 int q0 =
static_cast<int>(quantized_bmin[j]);
1300 int q1 =
static_cast<int>(quantized_bmax[j]);
1303 idx_bmin[j] =
static_cast<unsigned int>(q0);
1304 idx_bmax[j] =
static_cast<unsigned int>(q1);
1306 if (idx_bmin[j] >= bin_size)
1307 idx_bmin[j] =
static_cast<unsigned int>(bin_size) - 1;
1309 if (idx_bmax[j] >= bin_size)
1310 idx_bmax[j] =
static_cast<unsigned int>(bin_size) - 1;
1314 static_cast<size_t>(j) * bins->
bin_size + idx_bmin[j]] += 1;
1316 static_cast<size_t>(j) * bins->
bin_size + idx_bmax[j]] += 1;
1321 template <
typename T>
1322 inline T
SAH(
size_t ns1, T leftArea,
size_t ns2, T rightArea, T invS, T Taabb,
1326 sah =
static_cast<T
>(2.0) * Taabb +
1327 (leftArea * invS) *
static_cast<T
>(ns1) * Ttri +
1328 (rightArea * invS) *
static_cast<T
>(ns2) * Ttri;
1333 template <
typename T>
1337 const real3<T>& bmax,
size_t num_primitives,
1339 const T kEPS = std::numeric_limits<T>::epsilon();
1345 T saLeft, saRight, saTotal;
1349 T costTtri =
static_cast<T
>(1.0) - costTaabb;
1353 bsize = bmax - bmin;
1354 bstep = bsize * (
static_cast<T
>(1.0) / bins->
bin_size);
1357 T invSaTotal =
static_cast<T
>(0.0);
1358 if (saTotal > kEPS) {
1359 invSaTotal =
static_cast<T
>(1.0) / saTotal;
1362 for (
int j = 0; j < 3; ++j) {
1373 T minCostPos = bmin[j] +
static_cast<T
>(1.0) * bstep[j];
1374 minCost[j] = std::numeric_limits<T>::max();
1377 right = num_primitives;
1378 bminLeft = bminRight = bmin;
1379 bmaxLeft = bmaxRight = bmax;
1381 for (
int i = 0; i < static_cast<int>(bins->
bin_size) - 1; ++i) {
1383 static_cast<size_t>(j) * bins->
bin_size +
1384 static_cast<size_t>(i)];
1386 static_cast<size_t>(j) * bins->
bin_size +
1387 static_cast<size_t>(i)];
1389 assert(left <= num_primitives);
1390 assert(right <= num_primitives);
1397 pos = bmin[j] + (i +
static_cast<T
>(1.0)) * bstep[j];
1405 SAH(left, saLeft, right, saRight, invSaTotal, costTaabb, costTtri);
1407 if (cost < minCost[j]) {
1417 cut_pos[j] = minCostPos;
1424 T cost = minCost[0];
1427 if (cost > minCost[1]) {
1431 if (cost > minCost[2]) {
1440 template <
typename T,
class P>
1441 void ComputeBoundingBoxOMP(real3<T>* bmin, real3<T>* bmax,
1442 const unsigned int* indices,
unsigned int left_index,
1443 unsigned int right_index,
const P& p) {
1444 { p.BoundingBox(bmin, bmax, indices[left_index]); }
1446 T local_bmin[3] = { (*bmin)[0], (*bmin)[1], (*bmin)[2] };
1447 T local_bmax[3] = { (*bmax)[0], (*bmax)[1], (*bmax)[2] };
1449 unsigned int n = right_index - left_index;
1451#pragma omp parallel firstprivate(local_bmin, local_bmax) if (n > (1024 * 128))
1453#pragma omp parallel for
1455 for (
int i =
int(left_index); i < int(right_index); i++) {
1456 unsigned int idx = indices[i];
1458 real3<T> bbox_min, bbox_max;
1460 p.BoundingBox(&bbox_min, &bbox_max, idx);
1463 for (
int k = 0; k < 3; k++) {
1464 (*bmin)[k] = std::min((*bmin)[k], bbox_min[k]);
1465 (*bmax)[k] = std::max((*bmax)[k], bbox_max[k]);
1471 for (
int k = 0; k < 3; k++) {
1472 (*bmin)[k] = std::min((*bmin)[k], local_bmin[k]);
1473 (*bmax)[k] = std::max((*bmax)[k], local_bmax[k]);
1480#ifdef NANORT_USE_CPP11_FEATURE
1481 template <
typename T,
class P>
1482 inline void ComputeBoundingBoxThreaded(real3<T>* bmin, real3<T>* bmax,
1483 const unsigned int* indices,
1484 unsigned int left_index,
1485 unsigned int right_index,
const P& p) {
1486 unsigned int n = right_index - left_index;
1488 size_t num_threads = std::min(
1489 size_t(kNANORT_MAX_THREADS),
1490 std::max(
size_t(1),
size_t(std::thread::hardware_concurrency())));
1492 if (n < num_threads) {
1496 std::vector<std::thread> workers;
1498 size_t ndiv = n / num_threads;
1500 std::vector<T> local_bmins(3 * num_threads);
1501 std::vector<T> local_bmaxs(3 * num_threads);
1503 for (
size_t t = 0; t < num_threads; t++) {
1504 workers.emplace_back(std::thread([&, t]() {
1505 size_t si = left_index + t * ndiv;
1506 size_t ei = (t == (num_threads - 1)) ? size_t(right_index) :
std::min(left_index + (t + 1) * ndiv, size_t(right_index));
1508 local_bmins[3 * t + 0] = std::numeric_limits<T>::infinity();
1509 local_bmins[3 * t + 1] = std::numeric_limits<T>::infinity();
1510 local_bmins[3 * t + 2] = std::numeric_limits<T>::infinity();
1511 local_bmaxs[3 * t + 0] = -std::numeric_limits<T>::infinity();
1512 local_bmaxs[3 * t + 1] = -std::numeric_limits<T>::infinity();
1513 local_bmaxs[3 * t + 2] = -std::numeric_limits<T>::infinity();
1516 for (
size_t i = si; i < ei; i++) {
1517 unsigned int idx = indices[i];
1519 real3<T> bbox_min, bbox_max;
1520 p.BoundingBox(&bbox_min, &bbox_max, idx);
1523 for (
size_t k = 0; k < 3; k++) {
1524 local_bmins[3 * t + k] =
1525 std::min(local_bmins[3 * t + k], bbox_min[
int(k)]);
1526 local_bmaxs[3 * t + k] =
1527 std::max(local_bmaxs[3 * t + k], bbox_max[
int(k)]);
1533 for (
auto& t : workers) {
1538 for (
size_t k = 0; k < 3; k++) {
1539 (*bmin)[int(k)] = local_bmins[k];
1540 (*bmax)[int(k)] = local_bmaxs[k];
1543 for (
size_t t = 1; t < num_threads; t++) {
1544 for (
size_t k = 0; k < 3; k++) {
1545 (*bmin)[int(k)] = std::min((*bmin)[
int(k)], local_bmins[3 * t + k]);
1546 (*bmax)[int(k)] = std::max((*bmax)[
int(k)], local_bmaxs[3 * t + k]);
1552 template <
typename T,
class P>
1554 const unsigned int* indices,
1555 unsigned int left_index,
1556 unsigned int right_index,
const P& p) {
1557 unsigned int idx = indices[left_index];
1558 p.BoundingBox(bmin, bmax, idx);
1562 for (
unsigned int i = left_index + 1; i < right_index; i++) {
1565 p.BoundingBox(&bbox_min, &bbox_max, idx);
1568 for (
int k = 0; k < 3; k++) {
1569 (*bmin)[k] = std::min((*bmin)[k], bbox_min[k]);
1570 (*bmax)[k] = std::max((*bmax)[k], bbox_max[k]);
1576 template <
typename T>
1578 const std::vector<
BBox<T> >& bboxes,
1579 unsigned int* indices,
unsigned int left_index,
1580 unsigned int right_index) {
1581 unsigned int i = left_index;
1582 unsigned int idx = indices[i];
1584 (*bmin)[0] = bboxes[idx].bmin[0];
1585 (*bmin)[1] = bboxes[idx].bmin[1];
1586 (*bmin)[2] = bboxes[idx].bmin[2];
1587 (*bmax)[0] = bboxes[idx].bmax[0];
1588 (*bmax)[1] = bboxes[idx].bmax[1];
1589 (*bmax)[2] = bboxes[idx].bmax[2];
1592 for (i = left_index + 1; i < right_index; i++) {
1596 for (
int k = 0; k < 3; k++) {
1597 (*bmin)[k] = std::min((*bmin)[k], bboxes[idx].bmin[k]);
1598 (*bmax)[k] = std::max((*bmax)[k], bboxes[idx].bmax[k]);
1607#if defined(NANORT_ENABLE_PARALLEL_BUILD)
1608 template <
typename T>
1609 template <
class P,
class Pred>
1610 unsigned int BVHAccel<T>::BuildShallowTree(std::vector<BVHNode<T> >* out_nodes,
1611 unsigned int left_idx,
1612 unsigned int right_idx,
1614 unsigned int max_shallow_depth,
1615 const P& p,
const Pred& pred) {
1616 assert(left_idx <= right_idx);
1618 unsigned int offset =
static_cast<unsigned int>(out_nodes->size());
1620 if (stats_.max_tree_depth < depth) {
1621 stats_.max_tree_depth = depth;
1624 real3<T> bmin, bmax;
1626#if defined(NANORT_USE_CPP11_FEATURE) && defined(NANORT_ENABLE_PARALLEL_BUILD)
1627 ComputeBoundingBoxThreaded(&bmin, &bmax, &indices_.at(0), left_idx, right_idx,
1633 unsigned int n = right_idx - left_idx;
1634 if ((n <= options_.min_leaf_primitives) ||
1635 (depth >= options_.max_tree_depth)) {
1639 leaf.bmin[0] = bmin[0];
1640 leaf.bmin[1] = bmin[1];
1641 leaf.bmin[2] = bmin[2];
1643 leaf.bmax[0] = bmax[0];
1644 leaf.bmax[1] = bmax[1];
1645 leaf.bmax[2] = bmax[2];
1647 assert(left_idx < std::numeric_limits<unsigned int>::max());
1651 leaf.data[1] = left_idx;
1653 out_nodes->push_back(leaf);
1655 stats_.num_leaf_nodes++;
1663 if (depth >= max_shallow_depth) {
1665 ShallowNodeInfo info;
1666 info.left_idx = left_idx;
1667 info.right_idx = right_idx;
1668 info.offset = offset;
1669 shallow_node_infos_.push_back(info);
1675 out_nodes->push_back(node);
1689 int min_cut_axis = 0;
1690 T cut_pos[3] = { 0.0, 0.0, 0.0 };
1692 BinBuffer bins(options_.bin_size);
1696 options_.cost_t_aabb);
1699 unsigned int mid_idx = left_idx;
1700 int cut_axis = min_cut_axis;
1702 for (
int axis_try = 0; axis_try < 3; axis_try++) {
1703 unsigned int* begin = &indices_[left_idx];
1705 &indices_[right_idx - 1] + 1;
1706 unsigned int* mid = 0;
1709 cut_axis = (min_cut_axis + axis_try) % 3;
1711 pred.Set(cut_axis, cut_pos[cut_axis]);
1716 mid = std::partition(begin, end, pred);
1718 mid_idx = left_idx +
static_cast<unsigned int>((mid - begin));
1720 if ((mid_idx == left_idx) || (mid_idx == right_idx)) {
1724 mid_idx = left_idx + (n >> 1);
1736 node.axis = cut_axis;
1739 out_nodes->push_back(node);
1741 unsigned int left_child_index = 0;
1742 unsigned int right_child_index = 0;
1744 left_child_index = BuildShallowTree(out_nodes, left_idx, mid_idx, depth + 1,
1745 max_shallow_depth, p, pred);
1747 right_child_index = BuildShallowTree(out_nodes, mid_idx, right_idx,
1748 depth + 1, max_shallow_depth, p, pred);
1751 (*out_nodes)[offset].data[0] = left_child_index;
1752 (*out_nodes)[offset].data[1] = right_child_index;
1754 (*out_nodes)[offset].bmin[0] = bmin[0];
1755 (*out_nodes)[offset].bmin[1] = bmin[1];
1756 (*out_nodes)[offset].bmin[2] = bmin[2];
1758 (*out_nodes)[offset].bmax[0] = bmax[0];
1759 (*out_nodes)[offset].bmax[1] = bmax[1];
1760 (*out_nodes)[offset].bmax[2] = bmax[2];
1763 stats_.num_branch_nodes++;
1769 template <
typename T>
1770 template <
class P,
class Pred>
1773 unsigned int left_idx,
1774 unsigned int right_idx,
unsigned int depth,
1775 const P& p,
const Pred& pred) {
1776 assert(left_idx <= right_idx);
1778 unsigned int offset =
static_cast<unsigned int>(out_nodes->size());
1785 if (!bboxes_.empty()) {
1786 GetBoundingBox(&bmin, &bmax, bboxes_, &indices_.at(0), left_idx, right_idx);
1792 unsigned int n = right_idx - left_idx;
1793 if ((n <= options_.min_leaf_primitives) ||
1794 (depth >= options_.max_tree_depth)) {
1798 leaf.
bmin[0] = bmin[0];
1799 leaf.
bmin[1] = bmin[1];
1800 leaf.
bmin[2] = bmin[2];
1802 leaf.
bmax[0] = bmax[0];
1803 leaf.
bmax[1] = bmax[1];
1804 leaf.
bmax[2] = bmax[2];
1806 assert(left_idx < std::numeric_limits<unsigned int>::max());
1810 leaf.
data[1] = left_idx;
1812 out_nodes->push_back(leaf);
1826 int min_cut_axis = 0;
1827 T cut_pos[3] = { 0.0, 0.0, 0.0 };
1833 options_.cost_t_aabb);
1836 unsigned int mid_idx = left_idx;
1837 int cut_axis = min_cut_axis;
1839 for (
int axis_try = 0; axis_try < 3; axis_try++) {
1840 unsigned int* begin = &indices_[left_idx];
1841 unsigned int* end = &indices_[right_idx - 1] + 1;
1842 unsigned int* mid = 0;
1845 cut_axis = (min_cut_axis + axis_try) % 3;
1847 pred.Set(cut_axis, cut_pos[cut_axis]);
1853 mid = std::partition(begin, end, pred);
1855 mid_idx = left_idx +
static_cast<unsigned int>((mid - begin));
1857 if ((mid_idx == left_idx) || (mid_idx == right_idx)) {
1861 mid_idx = left_idx + (n >> 1);
1873 node.
axis = cut_axis;
1876 out_nodes->push_back(node);
1878 unsigned int left_child_index = 0;
1879 unsigned int right_child_index = 0;
1882 BuildTree(out_stat, out_nodes, left_idx, mid_idx, depth + 1, p, pred);
1885 BuildTree(out_stat, out_nodes, mid_idx, right_idx, depth + 1, p, pred);
1888 (*out_nodes)[offset].data[0] = left_child_index;
1889 (*out_nodes)[offset].data[1] = right_child_index;
1891 (*out_nodes)[offset].bmin[0] = bmin[0];
1892 (*out_nodes)[offset].bmin[1] = bmin[1];
1893 (*out_nodes)[offset].bmin[2] = bmin[2];
1895 (*out_nodes)[offset].bmax[0] = bmax[0];
1896 (*out_nodes)[offset].bmax[1] = bmax[1];
1897 (*out_nodes)[offset].bmax[2] = bmax[2];
1905 template <
typename T>
1906 template <
class Prim,
class Pred>
1914#if defined(NANORT_ENABLE_PARALLEL_BUILD)
1915 shallow_node_infos_.clear();
1918 assert(options_.bin_size > 1);
1920 if (num_primitives == 0) {
1924 unsigned int n = num_primitives;
1931#if defined(NANORT_USE_CPP11_FEATURE)
1933 size_t num_threads = std::min(
1934 size_t(kNANORT_MAX_THREADS),
1935 std::max(
size_t(1),
size_t(std::thread::hardware_concurrency())));
1937 if (n < num_threads) {
1941 std::vector<std::thread> workers;
1943 size_t ndiv = n / num_threads;
1945 for (
size_t t = 0; t < num_threads; t++) {
1946 workers.emplace_back(std::thread([&, t]() {
1947 size_t si = t * ndiv;
1948 size_t ei = (t == (num_threads - 1)) ? n : std::min((t + 1) * ndiv,
size_t(n));
1950 for (
size_t k = si; k < ei; k++) {
1951 indices_[k] =
static_cast<unsigned int>(k);
1956 for (
auto& t : workers) {
1964#pragma omp parallel for
1966 for (
int i = 0; i < static_cast<int>(n); i++) {
1967 indices_[
static_cast<size_t>(i)] =
static_cast<unsigned int>(i);
1977 bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<T>::max();
1978 bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<T>::max();
1982 for (
size_t i = 0; i < n; i++) {
1983 unsigned int idx = indices_[i];
1986 p.BoundingBox(&(bbox.
bmin), &(bbox.
bmax),
static_cast<unsigned int>(i));
1987 bboxes_[idx] = bbox;
1990 for (
int k = 0; k < 3; k++) {
1991 bmin[k] = std::min(bmin[k], bbox.
bmin[k]);
1992 bmax[k] = std::max(bmax[k], bbox.
bmax[k]);
1998#if defined(NANORT_USE_CPP11_FEATURE)
1999 ComputeBoundingBoxThreaded(&bmin, &bmax, &indices_.at(0), 0, n, p);
2000#elif defined(_OPENMP)
2001 ComputeBoundingBoxOMP(&bmin, &bmax, &indices_.at(0), 0, n, p);
2010#if defined(NANORT_ENABLE_PARALLEL_BUILD)
2011#if defined(NANORT_USE_CPP11_FEATURE)
2018 assert(shallow_node_infos_.size() > 0);
2021 std::vector<std::vector<BVHNode<T> > > local_nodes(
2022 shallow_node_infos_.size());
2023 std::vector<BVHBuildStatistics> local_stats(shallow_node_infos_.size());
2025 size_t num_threads = std::min(
2026 size_t(kNANORT_MAX_THREADS),
2027 std::max(
size_t(1),
size_t(std::thread::hardware_concurrency())));
2028 if (shallow_node_infos_.size() < num_threads) {
2029 num_threads = shallow_node_infos_.size();
2032 std::vector<std::thread> workers;
2033 std::atomic<uint32_t> i(0);
2035 for (
size_t t = 0; t < num_threads; t++) {
2036 workers.emplace_back(std::thread([&]() {
2038 while ((idx = (i++)) < shallow_node_infos_.size()) {
2041 const Pred local_pred = pred;
2042 unsigned int left_idx = shallow_node_infos_[size_t(idx)].left_idx;
2043 unsigned int right_idx = shallow_node_infos_[size_t(idx)].right_idx;
2044 BuildTree(&(local_stats[size_t(idx)]), &(local_nodes[size_t(idx)]),
2045 left_idx, right_idx, options.shallow_depth, p, local_pred);
2050 for (
auto& t : workers) {
2055 for (
size_t ii = 0; ii < local_nodes.size(); ii++) {
2056 assert(!local_nodes[ii].empty());
2057 size_t offset = nodes_.size();
2060 for (
size_t j = 0; j < local_nodes[ii].size(); j++) {
2061 if (local_nodes[ii][j].flag == 0) {
2062 local_nodes[ii][j].data[0] += offset - 1;
2063 local_nodes[ii][j].data[1] += offset - 1;
2068 nodes_[shallow_node_infos_[ii].offset] = local_nodes[ii][0];
2071 nodes_.insert(nodes_.end(), local_nodes[ii].begin() + 1,
2072 local_nodes[ii].end());
2076 for (
size_t ii = 0; ii < local_nodes.size(); ii++) {
2077 stats_.max_tree_depth =
2078 std::max(stats_.max_tree_depth, local_stats[ii].max_tree_depth);
2079 stats_.num_leaf_nodes += local_stats[ii].num_leaf_nodes;
2080 stats_.num_branch_nodes += local_stats[ii].num_branch_nodes;
2086 BuildTree(&stats_, &nodes_, 0, n,
2090#elif defined(_OPENMP)
2097 assert(shallow_node_infos_.size() > 0);
2100 std::vector<std::vector<BVHNode<T> > > local_nodes(
2101 shallow_node_infos_.size());
2102 std::vector<BVHBuildStatistics> local_stats(shallow_node_infos_.size());
2104#pragma omp parallel for
2105 for (
int i = 0; i < static_cast<int>(shallow_node_infos_.size()); i++) {
2106 unsigned int left_idx = shallow_node_infos_[size_t(i)].left_idx;
2107 unsigned int right_idx = shallow_node_infos_[size_t(i)].right_idx;
2108 const Pred local_pred = pred;
2109 BuildTree(&(local_stats[
size_t(i)]), &(local_nodes[
size_t(i)]), left_idx,
2114 for (
size_t i = 0; i < local_nodes.size(); i++) {
2115 assert(!local_nodes[
size_t(i)].empty());
2116 size_t offset = nodes_.size();
2119 for (
size_t j = 0; j < local_nodes[i].size(); j++) {
2120 if (local_nodes[i][j].flag == 0) {
2121 local_nodes[i][j].data[0] += offset - 1;
2122 local_nodes[i][j].data[1] += offset - 1;
2127 nodes_[shallow_node_infos_[i].offset] = local_nodes[i][0];
2130 nodes_.insert(nodes_.end(), local_nodes[i].begin() + 1,
2131 local_nodes[i].end());
2135 for (
size_t i = 0; i < local_nodes.size(); i++) {
2136 stats_.max_tree_depth =
2137 std::max(stats_.max_tree_depth, local_stats[i].max_tree_depth);
2138 stats_.num_leaf_nodes += local_stats[i].num_leaf_nodes;
2139 stats_.num_branch_nodes += local_stats[i].num_branch_nodes;
2145 BuildTree(&stats_, &nodes_, 0, n,
2151 BuildTree(&stats_, &nodes_, 0, n,
2159 BuildTree(&stats_, &nodes_, 0, n,
2167 template <
typename T>
2169 for (
size_t i = 0; i < indices_.size(); i++) {
2170 printf(
"index[%d] = %d\n",
int(i),
int(indices_[i]));
2173 for (
size_t i = 0; i < nodes_.size(); i++) {
2174 printf(
"node[%d] : bmin %f, %f, %f, bmax %f, %f, %f\n",
int(i),
2175 nodes_[i].bmin[0], nodes_[i].bmin[1], nodes_[i].bmin[1],
2176 nodes_[i].bmax[0], nodes_[i].bmax[1], nodes_[i].bmax[1]);
2180#if defined(NANORT_ENABLE_SERIALIZATION)
2181 template <
typename T>
2183 FILE* fp = fopen(filename,
"wb");
2189 size_t numNodes = nodes_.size();
2190 assert(nodes_.size() > 0);
2192 size_t numIndices = indices_.size();
2195 r = fwrite(&numNodes,
sizeof(
size_t), 1, fp);
2198 r = fwrite(&nodes_.at(0),
sizeof(BVHNode<T>), numNodes, fp);
2199 assert(r == numNodes);
2201 r = fwrite(&numIndices,
sizeof(
size_t), 1, fp);
2204 r = fwrite(&indices_.at(0),
sizeof(
unsigned int), numIndices, fp);
2205 assert(r == numIndices);
2212 template <
typename T>
2213 bool BVHAccel<T>::Dump(FILE* fp)
const {
2214 size_t numNodes = nodes_.size();
2215 assert(nodes_.size() > 0);
2217 size_t numIndices = indices_.size();
2220 r = fwrite(&numNodes,
sizeof(
size_t), 1, fp);
2223 r = fwrite(&nodes_.at(0),
sizeof(BVHNode<T>), numNodes, fp);
2224 assert(r == numNodes);
2226 r = fwrite(&numIndices,
sizeof(
size_t), 1, fp);
2229 r = fwrite(&indices_.at(0),
sizeof(
unsigned int), numIndices, fp);
2230 assert(r == numIndices);
2235 template <
typename T>
2236 bool BVHAccel<T>::Load(
const char* filename) {
2237 FILE* fp = fopen(filename,
"rb");
2247 r = fread(&numNodes,
sizeof(
size_t), 1, fp);
2249 assert(numNodes > 0);
2251 nodes_.resize(numNodes);
2252 r = fread(&nodes_.at(0),
sizeof(BVHNode<T>), numNodes, fp);
2253 assert(r == numNodes);
2255 r = fread(&numIndices,
sizeof(
size_t), 1, fp);
2258 indices_.resize(numIndices);
2260 r = fread(&indices_.at(0),
sizeof(
unsigned int), numIndices, fp);
2261 assert(r == numIndices);
2268 template <
typename T>
2269 bool BVHAccel<T>::Load(FILE* fp) {
2274 r = fread(&numNodes,
sizeof(
size_t), 1, fp);
2276 assert(numNodes > 0);
2278 nodes_.resize(numNodes);
2279 r = fread(&nodes_.at(0),
sizeof(BVHNode<T>), numNodes, fp);
2280 assert(r == numNodes);
2282 r = fread(&numIndices,
sizeof(
size_t), 1, fp);
2285 indices_.resize(numIndices);
2287 r = fread(&indices_.at(0),
sizeof(
unsigned int), numIndices, fp);
2288 assert(r == numIndices);
2294 template <
typename T>
2297 T min_t, T max_t,
const T bmin[3],
const T bmax[3],
2299 int ray_dir_sign[3]);
2303 float min_t,
float max_t,
2304 const float bmin[3],
const float bmax[3],
2307 int ray_dir_sign[3]) {
2310 const float min_x = ray_dir_sign[0] ? bmax[0] : bmin[0];
2311 const float min_y = ray_dir_sign[1] ? bmax[1] : bmin[1];
2312 const float min_z = ray_dir_sign[2] ? bmax[2] : bmin[2];
2313 const float max_x = ray_dir_sign[0] ? bmin[0] : bmax[0];
2314 const float max_y = ray_dir_sign[1] ? bmin[1] : bmax[1];
2315 const float max_z = ray_dir_sign[2] ? bmin[2] : bmax[2];
2318 const float tmin_x = (min_x - ray_org[0]) * ray_inv_dir[0];
2321 const float tmax_x = (max_x - ray_org[0]) * ray_inv_dir[0] * 1.00000024f;
2324 const float tmin_y = (min_y - ray_org[1]) * ray_inv_dir[1];
2325 const float tmax_y = (max_y - ray_org[1]) * ray_inv_dir[1] * 1.00000024f;
2328 const float tmin_z = (min_z - ray_org[2]) * ray_inv_dir[2];
2329 const float tmax_z = (max_z - ray_org[2]) * ray_inv_dir[2] * 1.00000024f;
2346 double min_t,
double max_t,
2347 const double bmin[3],
const double bmax[3],
2350 int ray_dir_sign[3]) {
2353 const double min_x = ray_dir_sign[0] ? bmax[0] : bmin[0];
2354 const double min_y = ray_dir_sign[1] ? bmax[1] : bmin[1];
2355 const double min_z = ray_dir_sign[2] ? bmax[2] : bmin[2];
2356 const double max_x = ray_dir_sign[0] ? bmin[0] : bmax[0];
2357 const double max_y = ray_dir_sign[1] ? bmin[1] : bmax[1];
2358 const double max_z = ray_dir_sign[2] ? bmin[2] : bmax[2];
2361 const double tmin_x = (min_x - ray_org[0]) * ray_inv_dir[0];
2363 const double tmax_x =
2364 (max_x - ray_org[0]) * ray_inv_dir[0] * 1.0000000000000004;
2367 const double tmin_y = (min_y - ray_org[1]) * ray_inv_dir[1];
2368 const double tmax_y =
2369 (max_y - ray_org[1]) * ray_inv_dir[1] * 1.0000000000000004;
2372 const double tmin_z = (min_z - ray_org[2]) * ray_inv_dir[2];
2373 const double tmax_z =
2374 (max_z - ray_org[2]) * ray_inv_dir[2] * 1.0000000000000004;
2388 template <
typename T>
2391 const I& intersector)
const {
2394 unsigned int num_primitives = node.
data[0];
2395 unsigned int offset = node.
data[1];
2397 T t = intersector.GetT();
2400 ray_org[0] = ray.
org[0];
2401 ray_org[1] = ray.
org[1];
2402 ray_org[2] = ray.
org[2];
2405 ray_dir[0] = ray.
dir[0];
2406 ray_dir[1] = ray.
dir[1];
2407 ray_dir[2] = ray.
dir[2];
2409 for (
unsigned int i = 0; i < num_primitives; i++) {
2410 unsigned int prim_idx = indices_[i + offset];
2413 if (intersector.Intersect(&local_t, prim_idx)) {
2417 intersector.Update(t, prim_idx);
2426 template <
typename T>
template<
class I,
class H,
class Comp>
2428 std::priority_queue<H, std::vector<H>, Comp>* isect_pq,
2429 int max_intersections,
2432 const I& intersector)
const {
2435 unsigned int num_primitives = node.
data[0];
2436 unsigned int offset = node.
data[1];
2438 T t = std::numeric_limits<T>::max();
2439 if (isect_pq->size() >=
static_cast<size_t>(max_intersections)) {
2440 t = isect_pq->top().t;
2444 ray_org[0] = ray.
org[0];
2445 ray_org[1] = ray.
org[1];
2446 ray_org[2] = ray.
org[2];
2449 ray_dir[0] = ray.
dir[0];
2450 ray_dir[1] = ray.
dir[1];
2451 ray_dir[2] = ray.
dir[2];
2453 for (
unsigned int i = 0; i < num_primitives; i++) {
2454 unsigned int prim_idx = indices_[i + offset];
2456 T local_t = t, u = 0.0f, v = 0.0f;
2458 if (intersector.Intersect(&local_t, &u, &v, prim_idx))
2461 if ((local_t > ray.
min_t))
2463 if (isect_pq->size() <
static_cast<size_t>(max_intersections))
2470 isect.prim_id = prim_idx;
2471 isect_pq->push(isect);
2478 else if (local_t < isect_pq->top().t)
2487 hit.prim_id = prim_idx;
2488 isect_pq->push(hit);
2491 t = isect_pq->top().t;
2503 template <
typename T>
2504 template <
class I,
class H>
2507 const int kMaxStackDepth = 512;
2508 (void)kMaxStackDepth;
2510 T hit_t = ray.
max_t;
2512 int node_stack_index = 0;
2513 unsigned int node_stack[512];
2517 intersector.Update(hit_t,
static_cast<unsigned int>(-1));
2519 intersector.PrepareTraversal(ray, options);
2522 dir_sign[0] = ray.
dir[0] <
static_cast<T
>(0.0) ? 1 : 0;
2523 dir_sign[1] = ray.
dir[1] <
static_cast<T
>(0.0) ? 1 : 0;
2524 dir_sign[2] = ray.
dir[2] <
static_cast<T
>(0.0) ? 1 : 0;
2528 ray_dir[0] = ray.
dir[0];
2529 ray_dir[1] = ray.
dir[1];
2530 ray_dir[2] = ray.
dir[2];
2535 ray_org[0] = ray.
org[0];
2536 ray_org[1] = ray.
org[1];
2537 ray_org[2] = ray.
org[2];
2539 T min_t = std::numeric_limits<T>::max();
2540 T max_t = -std::numeric_limits<T>::max();
2542 while (node_stack_index >= 0) {
2543 unsigned int index = node_stack[node_stack_index];
2549 node.
bmax, ray_org, ray_inv_dir, dir_sign);
2553 if (node.
flag == 0) {
2554 int order_near = dir_sign[node.
axis];
2555 int order_far = 1 - order_near;
2558 node_stack[++node_stack_index] = node.
data[order_far];
2559 node_stack[++node_stack_index] = node.
data[order_near];
2561 else if (TestLeafNode(node, ray, intersector)) {
2562 hit_t = intersector.GetT();
2569 bool hit = (intersector.GetT() < ray.
max_t);
2570 intersector.PostTraversal(ray, hit, isect);
2575 template <
typename T>
2579 const I& intersector,
2584 unsigned int num_primitives = node.
data[0];
2585 unsigned int offset = node.
data[1];
2588 ray_org[0] = ray.
org[0];
2589 ray_org[1] = ray.
org[1];
2590 ray_org[2] = ray.
org[2];
2593 ray_dir[0] = ray.
dir[0];
2594 ray_dir[1] = ray.
dir[1];
2595 ray_dir[2] = ray.
dir[2];
2597 intersector.PrepareTraversal(ray);
2599 for (
unsigned int i = 0; i < num_primitives; i++) {
2600 unsigned int prim_idx = indices_[i + offset];
2604 if (intersector.Intersect(&min_t, &max_t, prim_idx)) {
2607 isect.
t_min = min_t;
2608 isect.
t_max = max_t;
2611 if (isect_pq->size() <
static_cast<size_t>(max_intersections)) {
2612 isect_pq->push(isect);
2614 else if (min_t < isect_pq->top().t_min) {
2618 isect_pq->push(isect);
2626 template <
typename T>
2629 const Ray<T>& ray,
int max_intersections,
const I& intersector,
2631 const int kMaxStackDepth = 512;
2633 T hit_t = ray.
max_t;
2635 int node_stack_index = 0;
2636 unsigned int node_stack[512];
2640 std::priority_queue<NodeHit<T>, std::vector<NodeHit<T> >,
2647 dir_sign[0] = ray.
dir[0] <
static_cast<T
>(0.0) ? 1 : 0;
2648 dir_sign[1] = ray.
dir[1] <
static_cast<T
>(0.0) ? 1 : 0;
2649 dir_sign[2] = ray.
dir[2] <
static_cast<T
>(0.0) ? 1 : 0;
2654 ray_dir[0] = ray.
dir[0];
2655 ray_dir[1] = ray.
dir[1];
2656 ray_dir[2] = ray.
dir[2];
2661 ray_org[0] = ray.
org[0];
2662 ray_org[1] = ray.
org[1];
2663 ray_org[2] = ray.
org[2];
2667 while (node_stack_index >= 0) {
2668 unsigned int index = node_stack[node_stack_index];
2669 const BVHNode<T>& node = nodes_[
static_cast<size_t>(index)];
2674 node.
bmax, ray_org, ray_inv_dir, dir_sign);
2678 if (node.
flag == 0) {
2679 int order_near = dir_sign[node.
axis];
2680 int order_far = 1 - order_near;
2683 node_stack[++node_stack_index] = node.
data[order_far];
2684 node_stack[++node_stack_index] = node.
data[order_near];
2687 TestLeafNodeIntersections(node, ray, max_intersections, intersector,
2693 assert(node_stack_index < kMaxStackDepth);
2694 (void)kMaxStackDepth;
2696 if (!isect_pq.empty()) {
2698 size_t n = isect_pq.size();
2701 for (
size_t i = 0; i < n; i++) {
2703 (*hits)[n - i - 1] = isect;
2714 template <
typename T>
template<
class I,
class H,
class Comp>
2716 int max_intersections,
2717 const I& intersector,
2720 const int kMaxStackDepth = 512;
2722 T hit_t = ray.
max_t;
2724 int node_stack_index = 0;
2725 unsigned int node_stack[512];
2729 std::priority_queue<H, std::vector<H>, Comp> isect_pq;
2734 intersector.Update(hit_t,
static_cast<unsigned int>(-1));
2736 intersector.PrepareTraversal(ray, options);
2739 dir_sign[0] = ray.
dir[0] <
static_cast<T
>(0.0) ?
static_cast<T
>(1) :
static_cast<T
>(0);
2740 dir_sign[1] = ray.
dir[1] <
static_cast<T
>(0.0) ?
static_cast<T
>(1) :
static_cast<T
>(0);
2741 dir_sign[2] = ray.
dir[2] <
static_cast<T
>(0.0) ?
static_cast<T
>(1) :
static_cast<T
>(0);
2746 ray_dir[0] = ray.
dir[0];
2747 ray_dir[1] = ray.
dir[1];
2748 ray_dir[2] = ray.
dir[2];
2753 ray_org[0] = ray.
org[0];
2754 ray_org[1] = ray.
org[1];
2755 ray_org[2] = ray.
org[2];
2759 while (node_stack_index >= 0)
2761 unsigned int index = node_stack[node_stack_index];
2762 const BVHNode<T>& node = nodes_[
static_cast<size_t>(index)];
2767 node.
bmax, ray_org, ray_inv_dir, dir_sign);
2774 int order_near = dir_sign[node.
axis];
2775 int order_far = 1 - order_near;
2778 node_stack[++node_stack_index] = node.
data[order_far];
2779 node_stack[++node_stack_index] = node.
data[order_near];
2783 if (MultiHitTestLeafNode(&isect_pq, max_intersections, node, ray, intersector))
2786 if (isect_pq.size() >=
static_cast<size_t>(max_intersections))
2788 hit_t = isect_pq.top().t;
2795 assert(node_stack_index < kMaxStackDepth);
2796 (void)kMaxStackDepth;
2798 if (!isect_pq.empty())
2801 size_t n = isect_pq.size();
2804 for (
size_t i = 0; i < n; i++)
2806 const H& isect = isect_pq.top();
2807 (*hits)[n - i - 1] = isect;
2819#pragma clang diagnostic pop
#define kNANORT_MAX_STACK_DEPTH
#define kNANORT_MIN_PRIMITIVES_FOR_PARALLEL_BUILD
#define kNANORT_SHALLOW_DEPTH
void ComputeBoundingBox(real3< T > *bmin, real3< T > *bmax, const unsigned int *indices, unsigned int left_index, unsigned int right_index, const P &p)
T CalculateSurfaceArea(const real3< T > &min, const real3< T > &max)
T vdot(const real3< T > a, const real3< T > b)
T SAH(size_t ns1, T leftArea, size_t ns2, T rightArea, T invS, T Taabb, T Ttri)
real3< T > vnormalize(const real3< T > &rhs)
const T & safemin(const T &a, const T &b)
const T & safemax(const T &a, const T &b)
void GetBoundingBoxOfTriangle(real3< T > *bmin, real3< T > *bmax, const T *vertices, const unsigned int *faces, unsigned int index)
real3< T > vcross(const real3< T > a, const real3< T > b)
void GetBoundingBox(real3< T > *bmin, real3< T > *bmax, const std::vector< BBox< T > > &bboxes, unsigned int *indices, unsigned int left_index, unsigned int right_index)
void ContributeBinBuffer(BinBuffer *bins, const real3< T > &scene_min, const real3< T > &scene_max, unsigned int *indices, unsigned int left_idx, unsigned int right_idx, const P &p)
const real * get_vertex_addr(const real *p, const size_t idx, const size_t stride_bytes)
bool IntersectRayAABB< double >(double *tminOut, double *tmaxOut, double min_t, double max_t, const double bmin[3], const double bmax[3], real3< double > ray_org, real3< double > ray_inv_dir, int ray_dir_sign[3])
bool IntersectRayAABB(T *tminOut, T *tmaxOut, T min_t, T max_t, const T bmin[3], const T bmax[3], real3< T > ray_org, real3< T > ray_inv_dir, int ray_dir_sign[3])
real3< T > vsafe_inverse(const real3< T > v)
T vlength(const real3< T > &rhs)
bool IntersectRayAABB< float >(float *tminOut, float *tmaxOut, float min_t, float max_t, const float bmin[3], const float bmax[3], real3< float > ray_org, real3< float > ray_inv_dir, int ray_dir_sign[3])
real3< T > operator*(T f, const real3< T > &v)
bool FindCutFromBinBuffer(T *cut_pos, int *minCostAxis, const BinBuffer *bins, const real3< T > &bmin, const real3< T > &bmax, size_t num_primitives, T costTaabb)
real3< T > vneg(const real3< T > &rhs)
std::allocator< T >::size_type size_type
pointer allocate(size_type n, void *hint=0)
std::allocator< T >::pointer pointer
StackAllocator< U, stack_capacity > other
void deallocate(pointer p, size_type n)
StackAllocator(const StackAllocator< T, stack_capacity > &rhs)
StackAllocator(Source *source)
StackAllocator(const StackAllocator< U, other_capacity > &other)
char stack_buffer_[sizeof(T[stack_capacity])]
const T * stack_buffer() const
ContainerType * operator->()
const ContainerType & container() const
ContainerType::value_type ContainedType
const ContainerType * operator->() const
StackContainer(const StackContainer &)
ContainerType & container()
TContainerType ContainerType
void operator=(const StackContainer &)
StackAllocator< ContainedType, stack_capacity > Allocator
Allocator::Source stack_data_
StackVector(const StackVector< T, stack_capacity > &other)
const T & operator[](size_t i) const
StackVector< T, stack_capacity > & operator=(const StackVector< T, stack_capacity > &other)
real3 operator/(const real3 &f2) const
real3 operator*(const real3 &f2) const
real3 operator*(T f) const
real3 operator+(const real3 &f2) const
T operator[](int i) const
real3 & operator+=(const real3 &f2)
real3 operator-(const real3 &f2) const
BVHNode(const BVHNode &rhs)
BVHNode & operator=(const BVHNode &rhs)
bool operator()(const H &a, const H &b) const
unsigned int min_primitives_for_parallel_build
unsigned int max_tree_depth
unsigned int min_leaf_primitives
unsigned int shallow_depth
unsigned int num_leaf_nodes
unsigned int max_tree_depth
unsigned int num_branch_nodes
unsigned int skip_prim_id
unsigned char pad[3]
Padding (not used)
unsigned int prim_ids_range[2]
Hit class for traversing nodes.
NodeHit & operator=(const NodeHit< T > &rhs)
NodeHit(const NodeHit< T > &rhs)
Comparator object for NodeHit.
bool operator()(const NodeHit< T > &a, const NodeHit< T > &b)
Bounding Volume Hierarchy acceleration.
std::vector< unsigned int > indices_
bool TestLeafNodeIntersections(const BVHNode< T > &node, const Ray< T > &ray, const int max_intersections, const I &intersector, std::priority_queue< NodeHit< T >, std::vector< NodeHit< T > >, NodeHitComparator< T > > *isect_pq) const
bool Traverse(const Ray< T > &ray, const I &intersector, H *isect, const BVHTraceOptions &options=BVHTraceOptions()) const
Traverse into BVH along ray and find closest hit point & primitive if found.
BVHBuildOptions< T > options_
bool ListNodeIntersections(const Ray< T > &ray, int max_intersections, const I &intersector, StackVector< NodeHit< T >, 128 > *hits) const
List up nodes which intersects along the ray. This function is useful for two-level BVH traversal....
void BoundingBox(T bmin[3], T bmax[3]) const
Returns bounding box of built BVH.
bool Build(const unsigned int num_primitives, const Prim &p, const Pred &pred, const BVHBuildOptions< T > &options=BVHBuildOptions< T >())
Build BVH for input primitives.
const std::vector< unsigned int > & GetIndices() const
const std::vector< BVHNode< T > > & GetNodes() const
bool TestLeafNode(const BVHNode< T > &node, const Ray< T > &ray, const I &intersector) const
std::vector< BBox< T > > bboxes_
unsigned int BuildTree(BVHBuildStatistics *out_stat, std::vector< BVHNode< T > > *out_nodes, unsigned int left_idx, unsigned int right_idx, unsigned int depth, const P &p, const Pred &pred)
Builds BVH tree recursively.
BVHBuildStatistics stats_
std::vector< BVHNode< T > > nodes_
BVHBuildStatistics GetStatistics() const
Get statistics of built BVH tree. Valid after Build()
const size_t vertex_stride_bytes_
const unsigned int * faces_
void Set(int axis, T pos) const
TriangleSAHPred(const TriangleSAHPred< T > &rhs)
TriangleSAHPred(const T *vertices, const unsigned int *faces, size_t vertex_stride_bytes)
TriangleSAHPred< T > & operator=(const TriangleSAHPred< T > &rhs)
bool operator()(unsigned int i) const
TriangleMesh(const T *vertices, const unsigned int *faces, const size_t vertex_stride_bytes)
const size_t vertex_stride_bytes_
const unsigned int * faces_
void BoundingBox(real3< T > *bmin, real3< T > *bmax, unsigned int prim_index) const
Compute bounding box for prim_indexth triangle. This function is called for each primitive in BVH bui...
void PrepareTraversal(const Ray< T > &ray, const BVHTraceOptions &trace_options) const
Prepare BVH traversal (e.g. compute inverse ray direction) This function is called only once in BVH t...
const size_t vertex_stride_bytes_
TriangleIntersector(const T *vertices, const unsigned int *faces, const size_t vertex_stride_bytes)
void PostTraversal(const Ray< T > &ray, bool hit, H *isect) const
Post BVH traversal stuff. Fill isect if there is a hit.
T GetT() const
Returns the nearest hit distance.
void Update(T t, unsigned int prim_idx) const
Update is called when initializing intersection and nearest hit is found.
BVHTraceOptions trace_options_
bool Intersect(T *t_inout, const unsigned int prim_index) const
Do ray intersection stuff for prim_index th primitive and return hit distance t, barycentric coordina...
const unsigned int * faces_
BinBuffer(unsigned int size)
std::vector< size_t > bin