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 &param  = 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 &param2 = 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 doxygen 1.5.6