kdTreeAccel.cpp
Go to the documentation of this file.00001 /**<!--------------------------------------------------------------------> 00002 @file kdTreeAccel.cpp 00003 @author Travis Fischer (fisch0920@gmail.com) 00004 @date Fall 2008 00005 00006 @brief 00007 An N-dimensional kd-Tree is an axis-aligned binary spatial partitioning 00008 data structure. Each internal node is split along one of the N principle 00009 axes, where the split plane is typically chosen at each node based on some 00010 sort of heuristic. 00011 This kd-Tree implementation supports several common 00012 split plane generation methods, namely: spatial midpoint, median of 00013 geometry, and surface area heuristic (SAH). Note that a kd-Tree 00014 constructed by choosing the spatial midpoint along the current split axis 00015 as the next split plane is equivalent to an Octree. Also note that though 00016 the SAH produces the best quality tree overall with respect to visibility 00017 tests, it can take a long time to build and is thus mainly suitable for 00018 static scenes (whereas other acceleration data structures may be more 00019 appropriate for dynamic geometry & animations). 00020 The SAH kd-Tree may be tweaked with several parameters. See 00021 kdTreeAccelParams for more info. The O(nlog n) SAH construction has 00022 been implemented as opposed to the O(n) or O(n^2) alternatives (using 00023 std::sort for internal sorting). This choice was made because the O(n) 00024 solutions which exist both have large constants (which diminish their 00025 utility in practice), and are nowhere near as readable or easy to 00026 understand as the relatively straightforward O(nlog n) alternative. 00027 <!-------------------------------------------------------------------->**/ 00028 00029 #include "kdTreeAccel.h" 00030 00031 #include <SurfacePoint.h> 00032 #include <ResourceManager.h> 00033 #include <Random.h> 00034 #include <QtCore> 00035 #include <Log.h> 00036 00037 #include <GL/gl.h> 00038 #include <boost/static_assert.hpp> 00039 #include <algorithm> 00040 #include <climits> 00041 using namespace std; 00042 00043 // notes on debugging kd-Trees: 00044 // If issues arise, the first thing you want to do is determine whether the 00045 // problem is in tree construction or tree traversal. To narrow this down, I'd 00046 // recommend replacing the traversal with a really simple / naive DFS that will 00047 // traverse the entire data structure without any pruning at all, recording the 00048 // minimum t-value along the way. If you're still experiencing problems, then 00049 // the problem is likely with the construction of your tree. Needless to say, 00050 // you should also test with no acceleration data structure at all (linear 00051 // traversal through all primitives in the scene ala NaiveSpatialAccel), to 00052 // determine whether the problem lies in a primitive intersection routine of 00053 // in the acceleration data structure itself. 00054 // Note the presense of kdNode::preview which recursively draws a version 00055 // of the kd-Tree (starting with the root kdNode) in OpenGL. This method has 00056 // been invaluable in visualizing and debugging edge cases with planar 00057 // primitives and subtle, yet complex scenes. 00058 00059 00060 // ------------------------------------------------------------------------- 00061 // Internal data structures 00062 // ------------------------------------------------------------------------- 00063 00064 #define KD_FLAG_BITS (3) 00065 #define KD_LEAF_FLAG (3) 00066 00067 #define KD_FLAG(node) ((node)->flag & KD_FLAG_BITS) 00068 00069 #define KD_LEAF_NODE(node) (KD_FLAG(node) == KD_LEAF_FLAG) 00070 #define KD_INTERNAL_NODE(node) (KD_FLAG(node) != KD_LEAF_FLAG) 00071 00072 #define KD_SPLIT_AXIS(node) (KD_FLAG(node)) 00073 #define KD_SPLIT_POS(node) ((node)->splitPos) 00074 #define KD_NO_PRIMITIVES(node) ((node)->noPrimitives >> 2) 00075 00076 // left/right children stored next to each other on 16 byte boundary 00077 // right child is stored at left child + 8 bytes 00078 #define KD_LEFT_CHILD(node) \ 00079 ((kdNode*)((node)->flag & ~KD_FLAG_BITS)) 00080 #define KD_RIGHT_CHILD(node) \ 00081 (KD_LEFT_CHILD(node) + 1) 00082 #define KD_CHILD(node, n) \ 00083 (((kdNode*)((node)->flag & ~KD_FLAG_BITS)) + n) 00084 00085 #define KD_INIT_INTERNAL(node, leftChild, splitAxis, pos) \ 00086 do { \ 00087 (node)->child = (leftChild); \ 00088 (node)->flag |= (splitAxis); \ 00089 (node)->splitPos = (pos); \ 00090 ASSERT(KD_INTERNAL_NODE((node))); \ 00091 workBuf->log.noInternal++; \ 00092 } while(0) 00093 00094 #define KD_INIT_LEAF(node, prims, noPrims) \ 00095 do { \ 00096 (node)->noPrimitives = ((noPrims) << 2); \ 00097 (node)->flag |= (KD_LEAF_FLAG); \ 00098 (node)->primitives = (prims); \ 00099 ASSERT(KD_LEAF_NODE((node))); \ 00100 workBuf->log.noLeaves++; \ 00101 workBuf->log.minPrimitives = \ 00102 MIN(workBuf->log.minPrimitives, (unsigned) (noPrims)); \ 00103 workBuf->log.maxPrimitives = \ 00104 MAX(workBuf->log.maxPrimitives, (unsigned) (noPrims)); \ 00105 workBuf->log.avgPrimitives += (unsigned) (noPrims); \ 00106 workBuf->log.minDepth = \ 00107 MIN(workBuf->log.minDepth, workBuf->depth); \ 00108 workBuf->log.maxDepth = \ 00109 MAX(workBuf->log.maxDepth, workBuf->depth); \ 00110 workBuf->log.avgDepth += workBuf->depth; \ 00111 } while(0) 00112 00113 /// 8 byte packed struct optimized for cache performance, 00114 /// (represents a single node in the kd-Tree) 00115 struct kdNode { 00116 union { // 4 bytes 00117 kdNode *child; 00118 unsigned int noPrimitives; 00119 unsigned int flag; 00120 }; 00121 union { // 4 bytes 00122 IndexedIntersectableList *primitives; 00123 float splitPos; 00124 }; 00125 00126 inline void cleanup() { 00127 if (KD_INTERNAL_NODE(this)) { 00128 kdNode *leftChild = KD_LEFT_CHILD(this); 00129 kdNode *rightChild = KD_RIGHT_CHILD(this); 00130 00131 ASSERT(leftChild && rightChild); 00132 rightChild->cleanup(); 00133 leftChild->cleanup(); 00134 00135 // no need to free right child as both children share the same malloc 00136 // i.e. they're twins -- born at the same time & die at the same time 00137 // ... creepy :) 00138 free(leftChild); 00139 } else { // leaf node 00140 if (primitives) 00141 delete primitives; 00142 } 00143 } 00144 00145 void preview(const AABB &aabb, kdTreeAccel *accel, unsigned depth = 0) const { 00146 bool displayNormal = true; 00147 00148 #if DEBUG 00149 // handy view which allows the visualizer to step through and display 00150 // each node encountered during a given traversal of the kd-Tree 00151 if ((displayNormal = ResourceManager::contains("kdTreeIndex"))) { 00152 const std::vector<kdNode*> &intersected = 00153 accel->getIntersectedDebugList(); 00154 00155 const unsigned index = 00156 ResourceManager::getValue<unsigned>("kdTreeIndex"); 00157 00158 const bool draw = 00159 (index < intersected.size() && this == intersected[index]); 00160 00161 if (draw) { 00162 if (KD_INTERNAL_NODE(this)) 00163 glColor4f(1, 0, 0, 1); 00164 else 00165 glColor4f(0, 1, 0, 1); 00166 00167 aabb.preview(); 00168 } 00169 } 00170 #endif 00171 00172 if (KD_INTERNAL_NODE(this)) { 00173 kdNode *leftChild = KD_LEFT_CHILD(this); 00174 kdNode *rightChild = KD_RIGHT_CHILD(this); 00175 00176 ASSERT(leftChild && rightChild); 00177 const unsigned splitAxis = KD_SPLIT_AXIS(this); 00178 const float splitPlane = KD_SPLIT_POS(this); 00179 00180 ASSERT(aabb.min[splitAxis] < splitPlane); 00181 ASSERT(aabb.max[splitAxis] > splitPlane); 00182 00183 if (displayNormal) { 00184 #if 0 00185 glColor4f(1, 1, 1, 1); 00186 aabb.preview(); 00187 #else 00188 AABB split(aabb); 00189 split.min[splitAxis] = splitPlane; 00190 split.max[splitAxis] = splitPlane; 00191 00192 // draw opaque bounding box of current split plane, colored by 00193 // RGB = XYZ according to the current split axis 00194 const unsigned axis = splitAxis;//depth % 3; 00195 glColor4f((axis == 0), (axis == 1), (axis == 2), 1); 00196 split.preview(); 00197 00198 // draw transparent quad representing split plane 00199 glColor4f(1, 1, 1, 0.5f); 00200 00201 glBegin(GL_QUADS); 00202 00203 glNormal3f((splitAxis == 0), (splitAxis == 1), (splitAxis == 2)); 00204 00205 if (splitAxis == 0) { 00206 glVertex3real_t(split.min[0], split.min[1], split.min[2]); 00207 glVertex3real_t(split.min[0], split.min[1], split.max[2]); 00208 00209 glVertex3real_t(split.min[0], split.max[1], split.max[2]); 00210 glVertex3real_t(split.min[0], split.max[1], split.min[2]); 00211 } else if (splitAxis == 1) { 00212 glVertex3real_t(split.min[0], split.min[1], split.min[2]); 00213 glVertex3real_t(split.min[0], split.min[1], split.max[2]); 00214 00215 glVertex3real_t(split.max[0], split.min[1], split.max[2]); 00216 glVertex3real_t(split.max[0], split.min[1], split.min[2]); 00217 } else { 00218 ASSERT(splitAxis == 2); 00219 00220 glVertex3real_t(split.min[0], split.min[1], split.min[2]); 00221 glVertex3real_t(split.min[0], split.max[1], split.min[2]); 00222 00223 glVertex3real_t(split.max[0], split.max[1], split.min[2]); 00224 glVertex3real_t(split.max[0], split.min[1], split.min[2]); 00225 } 00226 00227 glEnd(); 00228 #endif 00229 } 00230 00231 { // recur on left child 00232 AABB left(aabb); 00233 left.max[splitAxis] = splitPlane; 00234 leftChild->preview(left, accel, depth + 1); 00235 } 00236 00237 { // recur on right child 00238 AABB right(aabb); 00239 right.min[splitAxis] = splitPlane; 00240 rightChild->preview(right, accel, depth + 1); 00241 } 00242 } else { 00243 /*#ifdef DEBUG 00244 IntersectableList *prims = accel->getIntersectables(); 00245 00246 // ensure kd-Tree integrity 00247 for(unsigned i = prims->size(); i--;) { 00248 Intersectable *isect = (*prims)[i]; 00249 ASSERT(isect); 00250 00251 if (isect->getAABB().intersects(aabb)) { 00252 bool found = false; 00253 00254 for(unsigned i = KD_NO_PRIMITIVES(this); i--;) { 00255 const Intersectable *const curIntersectable = (*prims)[(*primitives)[i]]; 00256 00257 if ((found = (isect == curIntersectable))) 00258 break; 00259 } 00260 00261 ASSERT(found); 00262 } 00263 } 00264 #endif*/ 00265 } 00266 } 00267 }; 00268 00269 //BOOST_STATIC_ASSERT(sizeof(kdNode) == 8); 00270 00271 struct kdSplitPlane { 00272 enum SPLIT_TYPE { SPLIT_MAX = 0, SPLIT_PLANE = 1, SPLIT_MIN = 2 }; 00273 00274 real_t splitPos; 00275 SPLIT_TYPE splitType; 00276 00277 inline bool operator< (const kdSplitPlane &p) const { 00278 if (splitPos < p.splitPos) return true; 00279 if (splitPos > p.splitPos) return false; 00280 return (splitType < p.splitType); 00281 /*return 00282 ((splitPos < p.splitPos) || 00283 (splitPos == p.splitPos && splitType < p.splitType));*/ 00284 } 00285 00286 inline bool operator==(const kdSplitPlane &p) const { 00287 return (splitType == p.splitType && splitPos == p.splitPos); 00288 } 00289 }; 00290 00291 struct kdSAHCost { 00292 real_t totalExpCost; 00293 real_t splitPos; 00294 unsigned splitAxis; 00295 }; 00296 00297 /// fixed-size stack used during traversal 00298 struct kdStack { 00299 struct kdStackNode { 00300 kdNode *node; 00301 real_t tMax; 00302 }; 00303 00304 kdStackNode nodes[KD_MAX_DEPTH]; 00305 kdStackNode *top; 00306 00307 inline kdStack() 00308 : top(nodes) 00309 { } 00310 00311 inline bool isEmpty() const { 00312 return (top == nodes); 00313 } 00314 00315 inline void push(kdNode *node, real_t tMax) { 00316 top->node = node; 00317 top->tMax = tMax; 00318 ++top; 00319 } 00320 00321 inline void pop(kdNode *&node, real_t &tMax) { 00322 ASSERT(!isEmpty()); 00323 00324 --top; 00325 node = top->node; 00326 tMax = top->tMax; 00327 } 00328 }; 00329 00330 struct kdTreeAccelLog { 00331 // internal node statistics 00332 unsigned noInternal; 00333 unsigned minDepth; 00334 unsigned maxDepth; 00335 unsigned avgDepth; 00336 00337 // leaf node statistics 00338 unsigned noLeaves; 00339 unsigned minPrimitives; 00340 unsigned maxPrimitives; 00341 real_t avgPrimitives; 00342 00343 inline kdTreeAccelLog() 00344 : noInternal(0), minDepth(std::numeric_limits<unsigned>::max()), 00345 maxDepth(0), avgDepth(0), 00346 noLeaves(0), minPrimitives(std::numeric_limits<unsigned>::max()), 00347 maxPrimitives(0), avgPrimitives(0) 00348 { } 00349 }; 00350 00351 /// buffer used internally / extensively during tree construction 00352 struct kdWorkBuffer : public Log { 00353 kdNode *node; 00354 00355 kdTreeAccelLog log; 00356 00357 // indices of active primitives at current level 00358 IndexedIntersectableList *primitives; 00359 unsigned noPrimitives; 00360 00361 unsigned splitAxis; 00362 real_t splitPos; 00363 00364 kdSplitPlane *splitPlanes; 00365 00366 unsigned depth; 00367 AABB aabb; 00368 00369 // SAH-specific 00370 bool forceLeaf; // if SAH implies leaf 00371 00372 inline kdWorkBuffer() 00373 : node(NULL), log(), primitives(NULL), noPrimitives(0), 00374 splitAxis(3), splitPos(0), splitPlanes(NULL), 00375 depth(0), forceLeaf(false) 00376 { 00377 init(); 00378 } 00379 00380 inline ~kdWorkBuffer() { 00381 safeDeleteArray(splitPlanes); 00382 } 00383 }; 00384 00385 00386 // ------------------------------------------------------------------------- 00387 // Main public interface 00388 // ------------------------------------------------------------------------- 00389 00390 00391 kdTreeAccel::kdTreeAccel() 00392 : SpatialAccel(), m_buildParams(), m_root(NULL) 00393 { 00394 _reset(); 00395 } 00396 00397 kdTreeAccel::~kdTreeAccel() { 00398 _reset(); 00399 } 00400 00401 void kdTreeAccel::init() { 00402 kdWorkBuffer workBuf; 00403 00404 if (m_primitives->size() > 1) 00405 workBuf << "initializing kdTree: " << m_primitives->size() << " primitives" << endl; 00406 00407 // free any prior data structures 00408 _reset(); 00409 00410 // initialize global AABB 00411 SpatialAccel::init(); 00412 00413 // initialize build parameters from PropertyMap 00414 _initProperties(workBuf); 00415 00416 // initialize split position member function 00417 SplitFunction splitPositionFunctions[] = { 00418 &kdTreeAccel::_computeSplitPlaneMiddle, 00419 &kdTreeAccel::_computeSplitPlaneMedian, 00420 &kdTreeAccel::_computeSplitPlaneSAH, 00421 }; 00422 00423 ASSERT(m_buildParams.kdSplitPlaneType < 3); 00424 m_splitPlaneFunction = splitPositionFunctions[m_buildParams.kdSplitPlaneType]; 00425 00426 // initialize split axis member function 00427 SplitFunction splitAxisFunctions[] = { 00428 &kdTreeAccel::_computeSplitAxisRoundRobin, 00429 &kdTreeAccel::_computeSplitAxisLongestExtent, 00430 }; 00431 00432 ASSERT(m_buildParams.kdSplitAxisType < 2); 00433 m_splitAxisFunction = splitAxisFunctions[m_buildParams.kdSplitAxisType]; 00434 00435 // create the root node 00436 m_root = (kdNode*) malloc(sizeof(kdNode)); 00437 00438 // initialize working buffer 00439 workBuf.splitPlanes = new kdSplitPlane[m_primitives->size() * 2]; 00440 workBuf.aabb = m_aabb; 00441 workBuf.splitAxis = 3; 00442 00443 IndexedIntersectableList *primitives = new IndexedIntersectableList(m_primitives->size()); 00444 for(unsigned i = primitives->size(); i--;) 00445 (*primitives)[i] = i; 00446 00447 // build the tree! 00448 _buildTreeHelper(&workBuf, m_root, primitives, 0, 0, 0); 00449 00450 // optional post-processing (memory pooling) 00451 if (m_buildParams.kdPostCompress) 00452 _postCompressTree(); 00453 00454 const kdTreeAccelLog &log = workBuf.log; 00455 ASSERT(log.noLeaves > log.noInternal); 00456 00457 // print out useful debugging info / stats 00458 if (m_primitives->size() > 1) { 00459 workBuf << " " << "minDepth: " << log.minDepth << endl; 00460 workBuf << " " << "maxDepth: " << log.maxDepth << endl; 00461 workBuf << " " << "avgDepth: " << 00462 (log.avgDepth / log.noLeaves) << endl; 00463 workBuf << " " << "noInternal: " << log.noInternal << endl; 00464 workBuf << " " << "noLeaves: " << log.noLeaves << endl; 00465 workBuf << " " << "minPrimitives: " << log.minPrimitives << endl; 00466 workBuf << " " << "maxPrimitives: " << log.maxPrimitives << endl; 00467 workBuf << " " << "avgPrimitives: " << 00468 (log.avgPrimitives / log.noLeaves) << endl; 00469 } 00470 } 00471 00472 00473 // ------------------------------------------------------------------------- 00474 // Internal construction methods 00475 // ------------------------------------------------------------------------- 00476 00477 00478 void kdTreeAccel::_reset() { 00479 if (m_root) { 00480 m_root->cleanup(); 00481 free(m_root); 00482 m_root = NULL; 00483 } 00484 } 00485 00486 void kdTreeAccel::_initProperties(kdWorkBuffer &workBuf) { 00487 const char *const splitPlaneTypes[] = { 00488 "splitPlaneMiddle", "splitPlaneMedian", "splitPlaneSAH", NULL 00489 }; 00490 00491 const char *const splitAxisTypes[] = { 00492 "splitAxisRoundRobin", "splitAxisLongestExtent", NULL 00493 }; 00494 00495 const std::string ¶m = getValue<const std::string>( 00496 "kdSplitPlaneType", splitPlaneTypes[m_buildParams.kdSplitPlaneType]); 00497 00498 if (m_primitives->size() > 1) 00499 workBuf << " kdSplitPlaneType: " << param << endl; 00500 00501 for(int i = 3; i--;) { 00502 if (splitPlaneTypes[i] == param) { 00503 m_buildParams.kdSplitPlaneType = (SplitPlaneType) i; 00504 break; 00505 } 00506 } 00507 00508 const std::string ¶m2 = getValue<const std::string>( 00509 "kdSplitAxisType", splitAxisTypes[m_buildParams.kdSplitAxisType]); 00510 00511 for(int i = 2; i--;) { 00512 if (splitAxisTypes[i] == param2) { 00513 m_buildParams.kdSplitAxisType = (SplitAxisType) i; 00514 break; 00515 } 00516 } 00517 00518 #define GET_PARAM(name, type) \ 00519 m_buildParams.name = getValue<type>(#name, m_buildParams.name); 00520 00521 GET_PARAM(kdMinPrimitives, unsigned); 00522 GET_PARAM(kdMaxDepth, unsigned); 00523 GET_PARAM(kdNoThreads, unsigned); 00524 GET_PARAM(kdPostCompress, bool); 00525 GET_PARAM(kdCostTraversal, real_t); 00526 GET_PARAM(kdEmptyBias, real_t); 00527 00528 #undef GET_PARAM 00529 } 00530 00531 void kdTreeAccel::_buildTree(kdWorkBuffer *workBuf) { 00532 kdNode *node = workBuf->node; 00533 00534 if (workBuf->depth > workBuf->log.maxDepth) 00535 workBuf->log.maxDepth = workBuf->depth; 00536 00537 // Check base cases 00538 // ----------------------------------------------------- 00539 if (workBuf->noPrimitives < m_buildParams.kdMinPrimitives || 00540 workBuf->depth >= m_buildParams.kdMaxDepth) 00541 { 00542 KD_INIT_LEAF(node, workBuf->primitives, workBuf->noPrimitives); 00543 return; 00544 } 00545 00546 // Select split axis and plane (position along axis) 00547 // ----------------------------------------------------- 00548 ((this)->*(m_splitPlaneFunction))(workBuf); 00549 00550 if (workBuf->forceLeaf) 00551 return; 00552 00553 const unsigned splitAxis = workBuf->splitAxis; 00554 const real_t splitPos = workBuf->splitPos; 00555 00556 const real_t nearSplitPos = splitPos;// - EPSILON; 00557 const real_t farSplitPos = splitPos;// + EPSILON; 00558 00559 IndexedIntersectableList *leftPrims = new IndexedIntersectableList(); 00560 IndexedIntersectableList *rightPrims = new IndexedIntersectableList(); 00561 00562 // Partition primitives according to split 00563 // ----------------------------------------------------- 00564 FOREACH(IndexedIntersectableListIter, *workBuf->primitives, iter) { 00565 const unsigned index = *iter; 00566 const Intersectable *const shape = (*m_primitives)[index]; 00567 00568 if (shape->getAABB().isPoint()) 00569 continue; 00570 00571 const real_t min = shape->getMin(splitAxis); 00572 const real_t max = shape->getMax(splitAxis); 00573 ASSERT(min <= max); 00574 00575 if (max > nearSplitPos) 00576 rightPrims->push_back(index); 00577 00578 if (min <= farSplitPos) 00579 leftPrims->push_back(index); 00580 } 00581 00582 // Stop recursion if splitting doesn't help 00583 // ----------------------------------------------------- 00584 if ((workBuf->noPrimitives == leftPrims->size() || 00585 workBuf->noPrimitives == rightPrims->size()) && 00586 (m_splitPlaneFunction != &kdTreeAccel::_computeSplitPlaneSAH || 00587 (workBuf->noPrimitives == leftPrims->size() && 00588 workBuf->noPrimitives == rightPrims->size()))) 00589 { 00590 safeDelete(leftPrims); 00591 safeDelete(rightPrims); 00592 00593 KD_INIT_LEAF(node, workBuf->primitives, workBuf->noPrimitives); 00594 return; 00595 } 00596 00597 safeDelete(workBuf->primitives); 00598 00599 // Prepare children and finalize current node 00600 // ----------------------------------------------------- 00601 kdNode *leftChild = (kdNode*) malloc(sizeof(kdNode) * 2); 00602 kdNode *rightChild = leftChild + 1; 00603 00604 KD_INIT_INTERNAL(node, leftChild, splitAxis, static_cast<float>(splitPos)); 00605 const unsigned int depth = workBuf->depth + 1; 00606 00607 // Recurse on left child 00608 // ----------------------------------------------------- 00609 00610 const real_t prevMax = workBuf->aabb.max[splitAxis]; 00611 workBuf->aabb.max[splitAxis] = splitPos; 00612 ASSERT(prevMax >= splitPos); 00613 00614 _buildTreeHelper(workBuf, leftChild, leftPrims, splitAxis, 00615 splitPos, depth); 00616 workBuf->aabb.max[splitAxis] = prevMax; 00617 00618 // Recurse on right child 00619 // ----------------------------------------------------- 00620 00621 const real_t prevMin = workBuf->aabb.min[splitAxis]; 00622 workBuf->aabb.min[splitAxis] = splitPos; 00623 ASSERT(prevMin <= splitPos); 00624 00625 _buildTreeHelper(workBuf, rightChild, rightPrims, splitAxis, 00626 splitPos, depth); 00627 workBuf->aabb.min[splitAxis] = prevMin; 00628 } 00629 00630 void kdTreeAccel::_buildTreeHelper(kdWorkBuffer *workBuf, kdNode *child, 00631 IndexedIntersectableList *primitives, 00632 const unsigned splitAxis, 00633 const real_t splitPos, 00634 const unsigned depth) 00635 { 00636 // Recursively subdivide node 00637 // ----------------------------------------------------- 00638 unsigned noPrimitives = primitives->size(); 00639 00640 if (noPrimitives > 0) { 00641 workBuf->node = child; 00642 workBuf->primitives = primitives; 00643 workBuf->noPrimitives = noPrimitives; 00644 00645 workBuf->splitAxis = splitAxis; 00646 workBuf->splitPos = splitPos; 00647 00648 workBuf->depth = depth; 00649 workBuf->forceLeaf = false; 00650 00651 // TODO: multithreading spawn thread if depth < threshold 00652 // NOTE: new workBuf as well cause of concurrent access to 00653 // workBuf's members and how to aggregate debugging info 00654 // (kdTreeAccelLog) 00655 00656 _buildTree(workBuf); 00657 } else { // node is empty 00658 KD_INIT_LEAF(child, primitives, 0); 00659 } 00660 } 00661 00662 00663 // split axis functions 00664 // -------------------- 00665 00666 void kdTreeAccel::_computeSplitAxisRoundRobin(kdWorkBuffer *workBuf) const { 00667 unsigned maxTries = 2; 00668 00669 do { 00670 workBuf->splitAxis = (workBuf->splitAxis + 1) % 3; 00671 } while(workBuf->aabb.min[workBuf->splitAxis] >= 00672 workBuf->aabb.max[workBuf->splitAxis] && --maxTries); 00673 00674 ASSERT(workBuf->splitAxis >= 0 && workBuf->splitAxis <= 2); 00675 } 00676 00677 void kdTreeAccel::_computeSplitAxisLongestExtent(kdWorkBuffer *workBuf) const { 00678 const unsigned maxExtent = workBuf->aabb.getMaxExtent(); 00679 00680 workBuf->splitAxis = maxExtent; 00681 00682 // TODO: test speed compared to alternative (below) 00683 //if (oldSplitAxis != maxExtent) 00684 // workBuf->splitAxis = maxExtent; 00685 //else _computeSplitAxisRoundRobin(workBuf); 00686 } 00687 00688 00689 // split position functions 00690 // ------------------------ 00691 00692 void kdTreeAccel::_computeSplitPlaneMiddle(kdWorkBuffer *workBuf) const { 00693 ((this)->*(m_splitAxisFunction))(workBuf); 00694 const unsigned splitAxis = workBuf->splitAxis; 00695 00696 // choosing a split plane in the middle of a principally-aligned axis 00697 // produces a kd-Tree that is functionally equivalent to an Octree 00698 00699 workBuf->splitPos = (workBuf->aabb.min[splitAxis] + 00700 workBuf->aabb.max[splitAxis]) / 2; 00701 } 00702 00703 void kdTreeAccel::_computeSplitPlaneMedian(kdWorkBuffer *workBuf) const { 00704 ((this)->*(m_splitAxisFunction))(workBuf); 00705 00706 // Sort candidate split planes along selected split axis 00707 // ------------------------------------------------------------- 00708 kdSplitPlane *planes = workBuf->splitPlanes; 00709 unsigned int n = _computeSplitPlanesSAH(*workBuf->primitives, 00710 workBuf->noPrimitives, 00711 workBuf->splitAxis, 00712 planes); 00713 00714 // select median split plane 00715 if (n > 0) 00716 workBuf->splitPos = planes[n >> 1].splitPos; 00717 else workBuf->forceLeaf = true; 00718 } 00719 00720 void kdTreeAccel::_computeSplitPlaneSAH(kdWorkBuffer *workBuf) const { 00721 const unsigned noPrimitives = workBuf->noPrimitives; 00722 kdSplitPlane *planes = workBuf->splitPlanes; 00723 kdSAHCost minSAHCost = { INFINITY, 0, 0 }; 00724 00725 // foreach split axis 00726 // ---------------------------------------------------------------- 00727 for(unsigned splitAxis = 0; splitAxis < 3; ++splitAxis) { 00728 00729 // note: the first constraint here produces a slightly less optimal tree 00730 // but trees which have long chains of splits along the same axis are 00731 // generally really deep and empirically, this constraint can drastically 00732 // reduce the number of overall nodes in the tree at the cost of slightly 00733 // more primitives per leaf on average 00734 if (splitAxis == workBuf->splitAxis || 00735 workBuf->aabb.min[splitAxis] >= workBuf->aabb.max[splitAxis]) 00736 { 00737 continue; 00738 } 00739 00740 // Sort candidate split planes along current split axis 00741 // ------------------------------------------------------------- 00742 unsigned int n = _computeSplitPlanesSAH(*workBuf->primitives, 00743 noPrimitives, 00744 splitAxis, 00745 planes); 00746 00747 // Evaluate minimum SAH cost among sorted candidate split planes 00748 // ------------------------------------------------------------- 00749 00750 kdSAHCost curSAHCost; 00751 unsigned index = 0; 00752 unsigned noLeft = 0; 00753 unsigned noRight = noPrimitives; 00754 00755 // foreach candidate split plane 00756 while(index < n - 1) { 00757 const real_t curSplitPlane = planes[index].splitPos; 00758 unsigned noPrims[3] = { 0, 0, 0 }; 00759 00760 // Skip past all equivalent split planes 00761 do { 00762 ++noPrims[planes[index].splitType]; 00763 } while(index < n - 1 && planes[++index].splitPos == curSplitPlane); 00764 00765 // Update running primitive counters 00766 const unsigned int noPlane = noPrims[kdSplitPlane::SPLIT_PLANE]; 00767 noRight -= noPrims[kdSplitPlane::SPLIT_MAX] + noPlane; 00768 00769 // Compute SAH 00770 if (curSplitPlane > workBuf->aabb.min[splitAxis] && 00771 curSplitPlane < workBuf->aabb.max[splitAxis]) 00772 { 00773 _computeSplitCostSAH(workBuf, curSplitPlane, splitAxis, noLeft, 00774 noPlane, noRight, curSAHCost); 00775 00776 if (curSAHCost.totalExpCost < minSAHCost.totalExpCost) 00777 minSAHCost = curSAHCost; 00778 } 00779 00780 noLeft += noPrims[kdSplitPlane::SPLIT_MIN] + noPlane; 00781 } 00782 } 00783 00784 if (minSAHCost.totalExpCost == INFINITY) { 00785 KD_INIT_LEAF(workBuf->node, workBuf->primitives, noPrimitives); 00786 workBuf->forceLeaf = true; 00787 00788 return; 00789 } 00790 00791 const real_t leafCost = 00792 (noPrimitives - m_buildParams.kdCostTraversal) * 00793 workBuf->aabb.getSurfaceArea(); 00794 00795 // if estimated cost of subdivision is greater than the guaranteed cost of 00796 // intersecting this node as-is, then create a leaf instead of splitting 00797 if (minSAHCost.totalExpCost > leafCost) { 00798 KD_INIT_LEAF(workBuf->node, workBuf->primitives, noPrimitives); 00799 workBuf->forceLeaf = true; 00800 00801 return; 00802 } 00803 00804 ASSERT(minSAHCost.totalExpCost < INFINITY); 00805 00806 // record description of minimal-cost split 00807 workBuf->splitPos = minSAHCost.splitPos; 00808 workBuf->splitAxis = minSAHCost.splitAxis; 00809 } 00810 00811 unsigned kdTreeAccel::_computeSplitPlanesSAH( 00812 const IndexedIntersectableList &primitives, 00813 const unsigned int noPrimitives, 00814 const unsigned int splitAxis, 00815 kdSplitPlane *outPlanes) const 00816 { 00817 unsigned n = 0; 00818 00819 // Aggregate candidate split planes (primitive extrema along split axis) 00820 // --------------------------------------------------------------------- 00821 for(unsigned int i = noPrimitives; i--;) { 00822 const Intersectable *const prim = (*m_primitives)[primitives[i]]; 00823 00824 if (prim->getAABB().isPoint()) 00825 continue; 00826 00827 const real_t min = prim->getMin(splitAxis); 00828 const real_t max = prim->getMax(splitAxis); 00829 00830 if (min == max) { 00831 outPlanes[n].splitPos = min; 00832 outPlanes[n].splitType = kdSplitPlane::SPLIT_PLANE; 00833 ++n; 00834 } else { 00835 outPlanes[n].splitPos = min; 00836 outPlanes[n].splitType = kdSplitPlane::SPLIT_MIN; 00837 ++n; 00838 00839 outPlanes[n].splitPos = max; 00840 outPlanes[n].splitType = kdSplitPlane::SPLIT_MAX; 00841 ++n; 00842 } 00843 } 00844 00845 // Sort candidate split planes along current split axis 00846 // --------------------------------------------------------------------- 00847 if (n > 0) 00848 std::sort(outPlanes, outPlanes + n); 00849 00850 return n; 00851 } 00852 00853 void kdTreeAccel::_computeSplitCostSAH(const kdWorkBuffer *workBuf, 00854 real_t splitPos, 00855 const unsigned splitAxis, 00856 unsigned noLeft, 00857 unsigned noPlane, 00858 unsigned noRight, 00859 kdSAHCost &outCost) const 00860 { 00861 real_t leftSA, rightSA; 00862 00863 workBuf->aabb.getMinMaxSurfaceArea(splitAxis, splitPos, 00864 leftSA, rightSA); 00865 00866 noLeft += noPlane; 00867 outCost.totalExpCost = (leftSA * noLeft + rightSA * noRight); 00868 00869 // favor splits which produce empty cells 00870 if (noLeft + noPlane == 0 || noRight == 0) 00871 outCost.totalExpCost *= m_buildParams.kdEmptyBias; 00872 00873 outCost.splitAxis = splitAxis; 00874 outCost.splitPos = splitPos; 00875 } 00876 00877 00878 void kdTreeAccel::_postCompressTree() { 00879 00880 /// @TODO: compress memory 00881 00882 /// @TODO: record stats 00883 } 00884 00885 00886 // ------------------------------------------------------------------------- 00887 // Public intersection tests 00888 // ------------------------------------------------------------------------- 00889 00890 00891 real_t kdTreeAccel::getIntersection(const Ray &ray, SurfacePoint &pt) { 00892 real_t tMin, tMax; 00893 00894 //m_intersected.clear(); 00895 00896 // check for intersection between ray and root node's bounding box 00897 if (!m_aabb.intersects(ray, tMin, tMax)) 00898 return INFINITY; 00899 00900 ASSERT(tMin <= tMax); 00901 00902 /** 00903 * technical note: tMin and tMax are always conservatively offset by EPSILON 00904 * to reduce 99% of numerical robustness issues, the majority of which 00905 * may could be due to inherent floating point arithmetic inprecision, 00906 * compounded by the fact that kdNodes store their split plane positions 00907 * using 32-bit floating point precision, whereas all other math in Milton 00908 * uses 64-bit double floating point precision (real_t) 00909 */ 00910 tMin -= EPSILON; 00911 tMax += EPSILON; 00912 00913 register kdNode *curNode = m_root; 00914 kdNode *farNode; 00915 kdStack stack; 00916 00917 /** 00918 * Each Ray has a unique "ID" stored with it to help prevent multiple 00919 * intersection tests against the same Shape during traversal of an 00920 * acceleration data structure (e.g., kd-Tree -- since a Shape may 00921 * appear in more than one leaf node) 00922 */ 00923 // TODO: thread-save rayIDs 00924 00925 while(1) { 00926 // traverse until we reach a leaf 00927 while(KD_INTERNAL_NODE(curNode)) { 00928 const unsigned splitAxis = KD_SPLIT_AXIS(curNode); 00929 const real_t diff = (KD_SPLIT_POS(curNode) - ray.origin[splitAxis]); 00930 const real_t d = diff * ray.invDir[splitAxis]; 00931 00932 // for visualizing the order in which nodes are traversed 00933 // note: this can't always be active because of multithreading! 00934 //m_intersected.push_back(curNode); 00935 00936 // order near/far children relative to ray's origin and direction 00937 register const bool reverseOrder = 00938 (diff <= 0 ? 00939 (ray.direction[splitAxis] <= 0) : 00940 (ray.direction[splitAxis] < 0)); 00941 //((ray.direction[splitAxis] < 0) || 00942 // (ray.direction[splitAxis] == 0 && diff <= 0)); 00943 00944 curNode = KD_CHILD(curNode, reverseOrder); 00945 00946 // if far node not intersected or ray is perpendicular to split plane 00947 if (d > tMax) 00948 continue; // cull far node 00949 00950 farNode = curNode + 1 - 2 * reverseOrder; 00951 00952 if (d < tMin) { // cull near node 00953 curNode = farNode; 00954 } else { // ray intersects both near and far children 00955 // traverse near node and place far node on stack 00956 stack.push(farNode, tMax); // { farNode, d, tMax } 00957 tMax = d + EPSILON; 00958 } 00959 } 00960 00961 //m_intersected.push_back(curNode); 00962 00963 // check for and record intersections 00964 const IndexedIntersectableList &primitives = *curNode->primitives; 00965 real_t tMinCell = INFINITY; 00966 00967 unsigned normalCase = pt.normalCase; 00968 unsigned index = pt.index; 00969 Shape *shape = pt.shape; 00970 00971 for(unsigned i = KD_NO_PRIMITIVES(curNode); i--;) { 00972 const unsigned primIndex = primitives[i]; 00973 Intersectable *curIntersectable = (*m_primitives)[primIndex]; 00974 00975 // Only test intersection with any given shape once per ray 00976 // (using a mailbox "ID") 00977 //if (curIntersectable->rayID != rayID) { 00978 pt.shape = NULL; 00979 pt.index = (unsigned)(-1); 00980 00981 const real_t t = curIntersectable->getIntersection(ray, pt); 00982 00983 /*if (t == INFINITY) { 00984 curIntersectable->rayID = rayID; 00985 } else */ 00986 if (t > EPSILON && t < tMinCell) { 00987 tMinCell = t; 00988 00989 shape = (pt.shape ? : static_cast<Shape*>(curIntersectable)); 00990 index = (pt.index == ((unsigned)(-1)) ? primIndex : pt.index); 00991 normalCase = pt.normalCase; 00992 } 00993 //} 00994 } 00995 00996 // Early termination! 00997 if (tMinCell <= tMax) { 00998 pt.shape = shape; 00999 pt.normalCase = normalCase; 01000 pt.index = index; 01001 01002 return tMinCell; 01003 } 01004 01005 if (stack.isEmpty()) 01006 return INFINITY; 01007 01008 // no valid intersection found, so traverse back up tree and 01009 // check an alternate path 01010 01011 tMin = tMax - (2 * EPSILON); 01012 stack.pop(curNode, tMax); 01013 } 01014 } 01015 01016 bool kdTreeAccel::intersects(const Ray &ray, real_t clipMax) { 01017 real_t tMin, tMax; 01018 01019 // check for intersection between ray and root node's bounding box 01020 if (!m_aabb.intersects(ray, tMin, tMax) || clipMax < tMin) 01021 return false; 01022 01023 if (clipMax < tMax) 01024 tMax = clipMax; 01025 01026 ASSERT(tMin <= tMax); 01027 tMin -= EPSILON; 01028 tMax += EPSILON; 01029 01030 //const unsigned rayID = QThread::currentThreadId() ^ Random::sampleInt(0, 99999); 01031 register kdNode *curNode = m_root; 01032 kdNode *farNode; 01033 kdStack stack; 01034 01035 while(1) { 01036 // traverse until we reach a leaf 01037 while(KD_INTERNAL_NODE(curNode)) { 01038 const unsigned splitAxis = KD_SPLIT_AXIS(curNode); 01039 const real_t diff = (KD_SPLIT_POS(curNode) - ray.origin[splitAxis]); 01040 const real_t d = diff * ray.invDir[splitAxis]; 01041 01042 // order near/far children relative to ray's origin and direction 01043 register const bool reverseOrder = 01044 (diff <= 0 ? 01045 (ray.direction[splitAxis] <= 0) : 01046 (ray.direction[splitAxis] < 0)); 01047 01048 curNode = KD_CHILD(curNode, reverseOrder); 01049 01050 // if far node not intersected or ray is perpendicular to split plane 01051 if (d > tMax) 01052 continue; // cull far node 01053 01054 farNode = curNode + 1 - 2 * reverseOrder; 01055 01056 if (d < tMin) { // cull near node 01057 curNode = farNode; 01058 } else { // ray intersects both near and far children 01059 // traverse near node and place far node on stack 01060 stack.push(farNode, tMax); // { farNode, d, tMax } 01061 tMax = d + EPSILON; 01062 } 01063 } 01064 01065 // check for and record intersections 01066 const IndexedIntersectableList &primitives = *curNode->primitives; 01067 01068 for(unsigned i = KD_NO_PRIMITIVES(curNode); i--;) { 01069 const unsigned primIndex = primitives[i]; 01070 Intersectable *curIntersectable = (*m_primitives)[primIndex]; 01071 01072 // Only test intersection with any given shape once per ray 01073 // (using a mailbox "ID") 01074 //if (curIntersectable->rayID != rayID) { 01075 // Early termination! 01076 if (curIntersectable->intersects(ray, clipMax)) 01077 return true; 01078 01079 // curIntersectable->rayID = rayID; 01080 //} 01081 } 01082 01083 if (stack.isEmpty()) 01084 return false; 01085 01086 // no valid intersection found, so traverse back up tree and 01087 // check an alternate path 01088 01089 tMin = tMax; 01090 stack.pop(curNode, tMax); 01091 } 01092 } 01093 01094 void kdTreeAccel::preview() { 01095 // save state 01096 glPushAttrib(GL_ENABLE_BIT); 01097 01098 { // enable blending / transparency 01099 glEnable(GL_BLEND); 01100 glBlendFunc(GL_SRC_ALPHA, GL_ONE); 01101 } 01102 01103 { // disable back-face culling and turn on back-facing shading 01104 glDisable(GL_CULL_FACE); 01105 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); 01106 } 01107 01108 // recursively draw each node in the kd-Tree 01109 if (m_root && m_primitives->size() > 1) 01110 m_root->preview(m_aabb, this); 01111 01112 // restore state 01113 glPopAttrib(); // GL_BLEND 01114 // GL_CULL_FACE 01115 01116 // draw AABB last, overlaid atop any other transparent fragments 01117 glColor3f(1, 1, 1); 01118 m_aabb.preview(); 01119 } 01120
Generated on 28 Feb 2009 for Milton by
1.5.6