20 #if !defined(__MITSUBA_RENDER_SAHKDTREE3_H_)
21 #define __MITSUBA_RENDER_SAHKDTREE3_H_
30 #define MTS_KD_MAILBOX_ENABLED 1
31 #define MTS_KD_MAILBOX_SIZE 8
32 #define MTS_KD_MAILBOX_MASK (MTS_KD_MAILBOX_SIZE-1)
50 const Float temp = 1.0f / (extents.x * extents.y
51 + extents.y*extents.z + extents.x*extents.z);
53 extents[1] * extents[2],
54 extents[0] * extents[2],
55 extents[0] * extents[1]) * temp;
57 extents[1] + extents[2],
58 extents[0] + extents[2],
59 extents[0] + extents[1]) * temp;
70 return std::pair<Float, Float>(
71 m_temp0[axis] + m_temp1[axis] * leftWidth,
72 m_temp0[axis] + m_temp1[axis] * rightWidth);
106 template <
typename Derived>
114 using Parent::m_nodes;
115 using Parent::m_aabb;
116 using Parent::m_indices;
120 SizeType primCount = cast()->getPrimitiveCount();
121 KDLog(
EInfo,
"Constructing a SAH kd-tree (%i primitives) ..", primCount);
127 return static_cast<Derived *
>(
this);
131 inline const Derived *
cast()
const {
132 return static_cast<const Derived *
>(
this);
178 template<
bool shadowRay> FINLINE
180 Float &t,
void *temp)
const {
183 static const int prevAxisTable[] = { 2, 0, 1 };
184 static const int nextAxisTable[] = { 1, 2, 0 };
187 #if defined(MTS_KD_MAILBOX_ENABLED)
188 HashedMailbox mailbox;
193 stack[enPt].t = mint;
194 stack[enPt].p = ray(mint);
198 stack[exPt].t = maxt;
199 stack[exPt].p = ray(maxt);
200 stack[exPt].node = NULL;
202 bool foundIntersection =
false;
203 const KDNode * __restrict currNode = m_nodes;
204 while (currNode != NULL) {
205 while (EXPECT_TAKEN(!currNode->isLeaf())) {
206 const Float splitVal = (
Float) currNode->getSplit();
207 const int axis = currNode->getAxis();
208 const KDNode * __restrict farChild;
210 if (stack[enPt].p[axis] <= splitVal) {
211 if (stack[exPt].p[axis] <= splitVal) {
213 currNode = currNode->getLeft();
220 if (stack[enPt].p[axis] == splitVal) {
222 currNode = currNode->getRight();
227 currNode = currNode->getLeft();
228 farChild = currNode + 1;
230 if (splitVal < stack[exPt].p[axis]) {
232 currNode = currNode->getRight();
236 farChild = currNode->getLeft();
237 currNode = farChild + 1;
241 Float distToSplit = (splitVal - ray.o[axis]) * ray.dRcp[axis];
249 stack[exPt].prev = tmp;
250 stack[exPt].t = distToSplit;
251 stack[exPt].node = farChild;
256 stack[exPt].p = ray(distToSplit);
257 stack[exPt].p[axis] = splitVal;
259 const int nextAxis = nextAxisTable[axis];
260 const int prevAxis = prevAxisTable[axis];
261 stack[exPt].p[axis] = splitVal;
262 stack[exPt].p[nextAxis] = ray.o[nextAxis]
263 + distToSplit*ray.d[nextAxis];
264 stack[exPt].p[prevAxis] = ray.o[prevAxis]
265 + distToSplit*ray.d[prevAxis];
271 for (
IndexType entry=currNode->getPrimStart(),
272 last = currNode->getPrimEnd(); entry != last; entry++) {
273 const IndexType primIdx = m_indices[entry];
275 #if defined(MTS_KD_MAILBOX_ENABLED)
276 if (mailbox.contains(primIdx))
282 result = cast()->intersect(ray, primIdx, mint, maxt, t, temp);
284 result = cast()->intersect(ray, primIdx, mint, maxt);
290 foundIntersection =
true;
293 #if defined(MTS_KD_MAILBOX_ENABLED)
294 mailbox.put(primIdx);
298 if (stack[exPt].t > maxt)
303 currNode = stack[exPt].node;
304 exPt = stack[enPt].prev;
307 return foundIntersection;
317 uint32_t numIntersections, uint64_t time) :
318 foundIntersection(foundIntersection), numTraversals(numTraversals),
319 numIntersections(numIntersections), time(time) { }
336 stack[enPt].t = mint;
337 stack[enPt].p = ray(mint);
341 stack[exPt].t = maxt;
342 stack[exPt].p = ray(maxt);
343 stack[exPt].node = NULL;
347 uint64_t timer = rdtsc();
348 bool foundIntersection =
false;
350 const KDNode * __restrict currNode = m_nodes;
351 while (currNode != NULL) {
352 while (EXPECT_TAKEN(!currNode->isLeaf())) {
353 const Float splitVal = (
Float) currNode->getSplit();
354 const int axis = currNode->getAxis();
355 const KDNode * __restrict farChild;
358 if (stack[enPt].p[axis] <= splitVal) {
359 if (stack[exPt].p[axis] <= splitVal) {
361 currNode = currNode->getLeft();
368 if (stack[enPt].p[axis] == splitVal) {
370 currNode = currNode->getRight();
375 currNode = currNode->getLeft();
376 farChild = currNode + 1;
378 if (splitVal < stack[exPt].p[axis]) {
380 currNode = currNode->getRight();
384 farChild = currNode->getLeft();
385 currNode = farChild + 1;
389 t = (splitVal - ray.o[axis]) * ray.dRcp[axis];
397 stack[exPt].prev = tmp;
399 stack[exPt].node = farChild;
400 stack[exPt].p = ray(t);
401 stack[exPt].p[axis] = splitVal;
405 for (
unsigned int entry=currNode->getPrimStart(),
406 last = currNode->getPrimEnd(); entry != last; entry++) {
407 const IndexType primIdx = m_indices[entry];
410 bool result = cast()->intersect(ray, primIdx, mint, maxt, t, temp);
414 foundIntersection =
true;
418 if (stack[exPt].t > maxt)
423 currNode = stack[exPt].node;
424 exPt = stack[enPt].prev;
427 return RayStatistics(foundIntersection, numTraversals,
428 numIntersections, rdtsc() - timer);
438 Float mint = mint_, maxt=maxt_;
439 const KDNode *node = m_nodes;
440 bool foundIntersection =
false;
442 while (node != NULL) {
446 if (EXPECT_TAKEN(!node->isLeaf())) {
448 const int axis = node->getAxis();
449 const float tPlane = (split - ray.o[axis]) * ray.dRcp[axis];
450 bool leftOfSplit = (ray.o[axis] < split)
451 || (ray.o[axis] == split && ray.d[axis] <= 0);
453 const KDNode * __restrict left = node->getLeft();
454 const KDNode * __restrict right = left + 1;
455 const KDNode * __restrict first = leftOfSplit ? left : right;
456 const KDNode * __restrict second = leftOfSplit ? right : left;
458 if (tPlane > maxt || tPlane <= 0) {
460 }
else if (tPlane < mint) {
463 stack[stackPos].node = second;
464 stack[stackPos].mint = tPlane;
465 stack[stackPos].maxt = maxt;
471 for (
unsigned int entry=node->getPrimStart(),
472 last = node->getPrimEnd(); entry != last; entry++) {
473 const IndexType primIdx = m_indices[entry];
477 result = cast()->intersect(ray, primIdx, mint, maxt, t, temp);
479 result = cast()->intersect(ray, primIdx, mint, maxt);
485 foundIntersection =
true;
491 node = stack[stackPos].node;
492 mint = stack[stackPos].mint;
493 maxt = stack[stackPos].maxt;
499 return foundIntersection;
512 BSphere bsphere = m_aabb.getBSphere();
513 int nRays = 10000000, warmup = nRays/4;
516 int nIntersections = 0, idx = 0;
518 for (
int i=0; i<nRays; ++i) {
519 Point2 sample1(random->nextFloat(), random->nextFloat()),
520 sample2(random->nextFloat(), random->nextFloat());
525 if (m_aabb.rayIntersect(ray, mint, maxt)) {
526 if (ray.mint > mint) mint = ray.mint;
527 if (ray.maxt < maxt) maxt = ray.maxt;
528 if (EXPECT_TAKEN(maxt > mint)) {
529 RayStatistics statistics =
530 rayIntersectHavranCollectStatistics(ray, mint, maxt, t, temp);
531 if (statistics.foundIntersection)
535 A[idx].y = (
Float) statistics.numTraversals;
536 A[idx].z = (
Float) statistics.numIntersections;
537 b[idx] = (
Float) statistics.time;
545 " intersections)", idx, nIntersections);
551 for (
int i=0; i<3; ++i) {
552 for (
int j=0; j<3; ++j)
553 for (
int k=0; k<idx; ++k)
554 M.m[i][j] += A[k][i]*A[k][j];
555 for (
int k=0; k<idx; ++k)
556 rhs[i] += A[k][i]*b[k];
559 bool success = M.invert(Minv);
564 Float avgRdtsc = 0, avgResidual = 0;
565 for (
int i=0; i<idx; ++i) {
567 Float model = x[0] * A[i][0]
570 avgResidual += std::abs(b[i] - model);
575 for (
int k=0; k<idx; ++k)
583 KDLog(
EDebug,
" Average rdtsc value = %.2f", avgRdtsc);
584 KDLog(
EDebug,
" Avg. residual = %.2f", avgResidual);
593 traversalCost = x[1];
594 intersectionCost = x[2];
RayStatistics(bool foundIntersection, uint32_t numTraversals, uint32_t numIntersections, uint64_t time)
Definition: sahkdtree3.h:316
#define KDLog(level, fmt,...)
Definition: gkdtree.h:642
KDTreeBase< AABB >::SizeType SizeType
Definition: sahkdtree3.h:110
Random number generator based on SIMD-oriented Fast Mersenne Twister
Definition: random.h:88
uint32_t numIntersections
Definition: sahkdtree3.h:313
std::pair< Float, Float > operator()(int axis, Float leftWidth, Float rightWidth) const
Definition: sahkdtree3.h:69
TVector3< Float > Vector
Definition: fwd.h:113
#define KDAssert(expr)
Definition: gkdtree.h:56
Float getSurfaceArea() const
Calculate the surface area of the bounding box.
Definition: aabb.h:464
Bounding sphere data structure in three dimensions.
Definition: bsphere.h:32
Debug message, usually turned off.
Definition: formatter.h:30
Base class of all kd-trees.
Definition: gkdtree.h:441
Normal normalize(const Normal &n)
Definition: normal.h:73
#define MTS_KD_MAXDEPTH
Activate lots of extra checks.
Definition: gkdtree.h:37
uint32_t numTraversals
Definition: sahkdtree3.h:312
Definition: sahkdtree3.h:310
FINLINE bool rayIntersectPBRT(const Ray &ray, Float mint_, Float maxt_, Float &t, void *temp) const
Ray tracing kd-tree traversal loop (PBRT variant)
Definition: sahkdtree3.h:434
More relevant debug / information message.
Definition: formatter.h:31
Ray traversal stack entry for Wald-style incoherent ray tracing.
Definition: sahkdtree3.h:155
KDTreeBase< AABB >::IndexType IndexType
Definition: sahkdtree3.h:111
void put(IndexType primIndex)
Definition: sahkdtree3.h:143
uint32_t prev
Definition: sahkdtree3.h:167
HashedMailbox()
Definition: sahkdtree3.h:139
Float radius
Definition: bsphere.h:34
uint64_t time
Definition: sahkdtree3.h:314
Axis-aligned bounding box data structure in three dimensions.
Definition: aabb.h:437
Implements the 3D surface area heuristic for use by the GenericKDTree construction algorithm...
Definition: sahkdtree3.h:39
Hashed mailbox implementation.
Definition: sahkdtree3.h:138
Float mint
Definition: sahkdtree3.h:157
FINLINE RayStatistics rayIntersectHavranCollectStatistics(const Ray &ray, Float mint, Float maxt, Float &t, void *temp) const
Internal kd-tree traversal implementation (Havran variant)
Definition: sahkdtree3.h:330
Float t
Definition: sahkdtree3.h:165
#define SAssert(cond)
``Static'' assertion (to be used outside of classes that derive from Object)
Definition: logger.h:79
Optimized KD-tree acceleration data structure for n-dimensional (n<=4) shapes and various queries on ...
Definition: gkdtree.h:706
const Derived * cast() const
Cast to the derived class (const version)
Definition: sahkdtree3.h:131
Reference counting helper.
Definition: ref.h:40
Point p
Definition: sahkdtree3.h:169
Parent::KDNode KDNode
Definition: gkdtree.h:717
Vector squareToUniformSphere(const Point2 &sample)
Uniformly sample a vector on the unit sphere with respect to solid angles.
FINLINE bool rayIntersectHavran(const Ray &ray, Float mint, Float maxt, Float &t, void *temp) const
Ray tracing kd-tree traversal loop (Havran variant)
Definition: sahkdtree3.h:179
bool contains(IndexType primIndex) const
Definition: sahkdtree3.h:147
const KDNode *__restrict node
Definition: sahkdtree3.h:156
Basic 4x4 matrix data type.
Definition: matrix.h:656
VectorType getExtents() const
Calculate the bounding box extents.
Definition: aabb.h:292
GenericKDTree< AABB, SurfaceAreaHeuristic3, Derived > Parent
Definition: sahkdtree3.h:109
void buildInternal()
Definition: sahkdtree3.h:119
void findCosts(Float &traversalCost, Float &intersectionCost)
Empirically find the best traversal and intersection cost values.
Definition: sahkdtree3.h:509
#define MTS_KD_MAILBOX_SIZE
Definition: sahkdtree3.h:31
SurfaceAreaHeuristic3(const AABB &aabb)
Initialize the surface area heuristic with the bounds of a parent node.
Definition: sahkdtree3.h:48
KDTreeBase< AABB >::KDNode KDNode
Definition: sahkdtree3.h:112
bool foundIntersection
Definition: sahkdtree3.h:311
const KDNode *__restrict node
Definition: sahkdtree3.h:163
#define MTS_KD_MAILBOX_MASK
Definition: sahkdtree3.h:32
Point center
Definition: bsphere.h:33
Derived * cast()
Cast to the derived class.
Definition: sahkdtree3.h:126
Ray traversal stack entry for Havran-style incoherent ray tracing.
Definition: sahkdtree3.h:161
Specializes GenericKDTree to a three-dimensional tree to be used for ray tracing. ...
Definition: sahkdtree3.h:107
static Float getQuantity(const AABB &aabb)
Definition: sahkdtree3.h:79