src/SAHKDTree.cpp

Go to the documentation of this file.
00001 
00002 #include <algorithm>
00003 #include <map>
00004 
00005 #include "SAHKDTree.h"
00006 #include "Node.h"
00007 #include "Event.h"
00008 #include "SplitPlane.h"
00009 #include "Primitive.h"
00010 
00011 
00014 SAHKDTree::~SAHKDTree()
00015 {
00016 }
00017 
00018 
00024 void SAHKDTree::buildTree(  const PrimitiveList &   list,
00025                             const Box &             bbox )
00026 {
00027     KDTree::buildTree(list, bbox);
00028 
00029     // create sorted initial event list
00030     EventList events;
00031     PrimitiveList::const_iterator it = list.begin();
00032     for (; it != list.end(); ++it)
00033     {
00034         generateEvents(events, *it, bbox);
00035     }
00036     std::sort(events.begin(), events.end());
00037 
00038     // create the tree recursively
00039     buildTree(mRootNode, bbox, events, 0);
00040 
00041     LOG("Building kd-tree done");
00042 }
00043 
00044 
00052 void SAHKDTree::buildTree(  Node *          node,
00053                             const Box &     bbox,
00054                             EventList &     events,
00055                             unsigned int    depth ) const
00056 {
00057     assert(node);
00058     assert(!node->left());
00059     assert(!node->right());
00060 
00061     // find best split plane
00062     float minCost = INFINITY;
00063     SplitPlane bestPlane = findBestPlane(minCost, node, bbox, events);
00064 
00065 //    LOG("\n\ndepth: " << depth << " :: " << node->primitives_count() << " prims , " << events.size()
00066 //            << " events \nbbox: [" << bbox.minVertex() << " , " << bbox.maxVertex() << "] , split dir/side/pos: "
00067 //            << bestPlane.direction() << " " << bestPlane.side() << " " << bestPlane.position()
00068 //            << "   cost: " << minCost);
00069 
00070     if (terminate(node, minCost, depth))
00071     {
00072         // make leaf node
00073         node->setSplitAxis(NO_AXIS);
00074         return;
00075     }
00076     assert(events.size() > 0);
00077 
00078     // setup node's split axis and plane
00079     node->setSplitPlane(bestPlane.position());
00080     node->setSplitAxis(bestPlane.direction());
00081 
00082     // create both children
00083     Node * left     = new Node();
00084     Node * right    = new Node();
00085     node->setLeftRight(left, right);
00086 
00087     // Event lists for children
00088     EventList eLeft;
00089     EventList eRight;
00090 
00091     // create event and primitive lists for children
00092     std::pair<Box, Box> boxes = classifyAndSplice(eLeft, eRight, node, bbox, events, bestPlane);
00093 
00094     // free some memory before recursing
00095     node->clear_primitives();
00096     events.clear();
00097 
00098     // setup subtrees
00099     buildTree(left, boxes.first, eLeft, depth + 1);
00100     buildTree(right, boxes.second, eRight, depth + 1);
00101 }
00102 
00103 
00114 bool SAHKDTree::terminate(  const Node *    current,
00115                             float           minCost,
00116                             unsigned int    depth ) const
00117 {
00118     return KDTree::terminate(current, minCost, depth) || minCost > mKIntersect * current->primitives_count();
00119 }
00120 
00121 
00133 float SAHKDTree::SAH(   Side &              side,   // out param
00134                         const Box &         bbox,
00135                         const SplitPlane &  plane,
00136                         unsigned int        number_left,
00137                         unsigned int        number_right,
00138                         unsigned int        number_middle ) const
00139 {
00140     float probability_left  = bbox.area(plane);
00141     float probability_right = 1.0f - probability_left;  // FIXME maybe calculate accurate probabilities
00142     float left_cost     = cost(probability_left, probability_right, number_left + number_middle, number_right);
00143     float right_cost    = cost(probability_left, probability_right, number_left, number_right + number_middle);
00144 
00145     if (left_cost < right_cost)
00146     {
00147         side = S_LEFT;
00148         return left_cost;
00149     }
00150     else
00151     {
00152         side = S_RIGHT;
00153         return right_cost;
00154     }
00155 }
00156 
00157 
00158 
00169 SplitPlane SAHKDTree::findBestPlane(    float &             minCost,    // out param
00170                                         const Node *        node,
00171                                         const Box &         bbox,
00172                                         const EventList &   events ) const
00173 {
00174     // triangle counters
00175     unsigned int NL[3];
00176     unsigned int NP[3];
00177     unsigned int NR[3];
00178 
00179     // initialize counters
00180     for (int k=0; k<3; k++)
00181     {
00182         NL[k] = NP[k] = 0;
00183         NR[k] = node->primitives_count();
00184     }
00185 
00186     SplitPlane plane;
00187     minCost = INFINITY;
00188 
00189     // find best split plane out of all candidates
00190     EventList::const_iterator it = events.begin();
00191     while (it != events.end())
00192     {
00193         unsigned int p_end      = 0;
00194         unsigned int p_planar   = 0;
00195         unsigned int p_start    = 0;
00196 
00197         SplitPlane p = it->plane();
00198 
00199         // count different events untill the next plane is found
00200         while (it != events.end()
00201                 && p.direction() == it->plane().direction()
00202                 && p.position() <= it->plane().position()
00203                 && it->type() == ET_END)
00204         {
00205             ++p_end;
00206             ++it;
00207         }
00208         while (it != events.end()
00209                 && p.direction() == it->plane().direction()
00210                 && p.position() <= it->plane().position()
00211                 && it->type() == ET_PLANAR)
00212         {
00213             ++p_planar;
00214             ++it;
00215         }
00216         while (it != events.end()
00217                 && p.direction() == it->plane().direction()
00218                 && p.position() <= it->plane().position()
00219                 && it->type() == ET_START)
00220         {
00221             ++p_start;
00222             ++it;
00223         }
00224 
00225         // incrementally update counters
00226         NP[p.direction()] = p_planar;
00227         NR[p.direction()] -= p_planar + p_end;
00228 
00229         // calculate costs
00230         Side side;
00231         float cost = SAH(side, bbox, p, NL[p.direction()], NR[p.direction()], NP[p.direction()]);
00232 
00233         // keep plane with minimal costs
00234         if (cost < minCost
00235                 && bbox.minVertex()[p.direction()] + EPSILON < p.position()
00236                 && p.position() < bbox.maxVertex()[p.direction()] - EPSILON)
00237         {
00238             plane       = p;
00239             minCost     = cost;
00240             plane.setSide(side);
00241         }
00242 
00243         // incrementally update counters
00244         NL[p.direction()] += p_planar + p_start;
00245         NP[p.direction()] = 0;
00246     }
00247 
00248     return plane;
00249 }
00250 
00251 
00258 void SAHKDTree::generateEvents( EventList &     events,     // out param
00259                                 Primitive *     primitive,
00260                                 const Box &     bbox ) const
00261 {
00262     Box b = primitive->bounds().clip(bbox);
00263     for (int k=0; k<3; k++) // for all dimensions
00264     {
00265         // if bounding box is planar in current dimension
00266         if (b.minVertex()[k] >= b.maxVertex()[k] - EPSILON)
00267         {
00268             events.push_back(Event(primitive, SplitPlane(b.minVertex()[k], Axis(k)), ET_PLANAR));
00269         }
00270         else
00271         {
00272             events.push_back(Event(primitive, SplitPlane(b.minVertex()[k], Axis(k)), ET_START));
00273             events.push_back(Event(primitive, SplitPlane(b.maxVertex()[k], Axis(k)), ET_END));
00274         }
00275     }
00276 }
00277 
00278 
00291 std::pair<Box, Box> SAHKDTree::classifyAndSplice(   EventList &         eLeft,  // out param
00292                                                     EventList &         eRight, // out param
00293                                                     Node *              node,
00294                                                     const Box &         bbox,
00295                                                     const EventList &   events,
00296                                                     const SplitPlane &  plane ) const
00297 {
00298     // create a map of primitives to markers for classification
00299     std::map<Primitive *, Side> prims;
00300     for (unsigned int i=0; i<node->primitives_count(); i++)
00301     {
00302         prims[node->primitive(i)] = S_BOTH;
00303     }
00304     assert(node->primitives_count() == prims.size());
00305 
00306     // generate event and primitive lists for children
00307     // old left-only and right-only events are sorted and stored before split iterator
00308     // newly generated both-side events are stored after split iterator
00309 
00310     // classify
00311     EventList::const_iterator it = events.begin();
00312     for (; it != events.end(); ++it)
00313     {
00314         if (it->type() == ET_END
00315                 && it->plane().direction() == plane.direction()
00316                 && it->plane().position() <= plane.position())
00317         {
00318             // left only
00319             prims[it->primitive()] = S_LEFT;
00320         }
00321         else if (it->type() == ET_START
00322                     && it->plane().direction() == plane.direction()
00323                     && it->plane().position() >= plane.position())
00324         {
00325             // right only
00326             prims[it->primitive()] = S_RIGHT;
00327         }
00328         else if (it->type() == ET_PLANAR
00329                     && it->plane().direction() == plane.direction())
00330         {
00331             if (it->plane().position() < plane.position()
00332                     || (it->plane().position() <= plane.position()
00333                         && plane.side() == S_LEFT))
00334             {
00335                 // left only
00336                 prims[it->primitive()] = S_LEFT;
00337             }
00338             if (it->plane().position() > plane.position()
00339                     || (it->plane().position() >= plane.position()
00340                         && plane.side() == S_RIGHT))
00341             {
00342                 // right only
00343                 prims[it->primitive()] = S_RIGHT;
00344             }
00345         }
00346         // both -> generate new events for clipped primitives (later)
00347     }
00348 
00349     // splice
00350     for (it = events.begin(); it != events.end(); ++it)
00351     {
00352         if (prims[it->primitive()] == S_LEFT)
00353         {
00354             eLeft.push_back(*it);
00355         }
00356         else if (prims[it->primitive()] == S_RIGHT)
00357         {
00358             eRight.push_back(*it);
00359         }
00360     }
00361 
00362     // save sizes of sorted parts
00363     unsigned int leftSize   = eLeft.size();
00364     unsigned int rightSize  = eRight.size();
00365 
00366     // bounding volumes for children FIXME do we need to calculate correct bounding volumes?
00367     std::pair<Box, Box> boxes = bbox.split(plane);
00368 
00369     // generate new events for overlapping primitives and copy primitives to children
00370     std::map<Primitive *, Side>::iterator mapit = prims.begin();
00371     for (; mapit != prims.end(); ++mapit)
00372     {
00373         if (mapit->second == S_LEFT)
00374         {
00375             node->left()->add(mapit->first);
00376         }
00377         else if (mapit->second == S_RIGHT)
00378         {
00379             node->right()->add(mapit->first);
00380         }
00381         else
00382         {
00383             generateEvents(eLeft, mapit->first, boxes.first);
00384             generateEvents(eRight, mapit->first, boxes.second);
00385 
00386             node->left()->add(mapit->first);
00387             node->right()->add(mapit->first);
00388         }
00389     }
00390 
00391 //    LOG("event split: " << leftSize << " -- " << eLeft.size()-leftSize
00392 //            << " --- " << eRight.size()-rightSize << " -- " << rightSize);
00393 
00394     // iterators between sorted and unsorted parts
00395     EventList::iterator leftBoth    = eLeft.begin() + leftSize;
00396     EventList::iterator rightBoth   = eRight.begin() + rightSize;
00397 
00398     // debug
00399     assert(eLeft.begin() <= leftBoth && leftBoth <= eLeft.end());
00400     assert(eRight.begin() <= rightBoth && rightBoth <= eRight.end());
00401 
00402     // sort new events and merge them with old events
00403     std::sort(leftBoth, eLeft.end());
00404     std::sort(rightBoth, eRight.end());
00405     std::inplace_merge(eLeft.begin(), leftBoth, eLeft.end());
00406     std::inplace_merge(eRight.begin(), rightBoth, eRight.end());
00407 
00408     return boxes;
00409 }
00410 
00411 

Generated on Fri Feb 1 00:01:42 2008 for Grayfall by  doxygen 1.5.1