kdTreeAccel.h

Go to the documentation of this file.
00001 /**<!-------------------------------------------------------------------->
00002    @class  kdTreeAccel
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 #ifndef KD_TREE_ACCEL_H_
00030 #define KD_TREE_ACCEL_H_
00031 
00032 #include "accel/SpatialAccel.h"
00033 
00034 #define KD_MAX_DEPTH       (24)
00035 
00036 struct kdNode;
00037 struct kdWorkBuffer;
00038 struct kdSplitPlane;
00039 struct kdSAHCost;
00040 
00041 DECLARE_STL_TYPEDEF(std::vector<unsigned>, IndexedIntersectableList);
00042 
00043 class kdTreeAccel : public SpatialAccel {
00044    
00045    public:
00046       /**
00047        * @brief Supported split plane generation techniques
00048        */
00049       enum SplitPlaneType {
00050          SPLIT_PLANE_MIDDLE = 0, 
00051          SPLIT_PLANE_MEDIAN, 
00052          SPLIT_PLANE_SAH     // default
00053       };
00054       
00055       /**
00056        * @brief Supported split axis selection techniques
00057        */
00058       enum SplitAxisType {
00059          SPLIT_AXIS_ROUND_ROBIN = 0, // default
00060          SPLIT_AXIS_LONGEST_EXTENT
00061       };
00062       
00063       /**
00064        * @brief Parameters controlling construction of a kdTreeAccel
00065        */
00066       struct BuildParams {
00067          /// split plane generation method (defaults to SPLIT_PLANE_SAH)
00068          SplitPlaneType kdSplitPlaneType;
00069          
00070          /// split axis selection method (defaults to SPLIT_AXIS_ROUND_ROBIN)
00071          SplitAxisType kdSplitAxisType;
00072          
00073          /// minimum number of primitives s.t. a leaf cell will automatically
00074          /// be created (below this number, further subdivision either won't 
00075          /// help or requires too much memory)
00076          unsigned kdMinPrimitives;
00077          
00078          /// maximum depth of tree
00079          unsigned kdMaxDepth;
00080          
00081          /// number of threads to use during construction
00082          unsigned kdNoThreads;
00083          
00084          /// if true, after construction, will attempt to reorganize memory 
00085          /// layout efficiently in memory
00086          bool kdPostCompress;
00087          
00088          /// SAH-specific parameters
00089          real_t kdCostTraversal;
00090          real_t kdEmptyBias;
00091          
00092          /**
00093           * Constructs default kd-Tree parameters
00094           */
00095          BuildParams(SplitPlaneType splitType = SPLIT_PLANE_SAH, 
00096                      SplitAxisType  splitAxis = SPLIT_AXIS_ROUND_ROBIN, 
00097                      unsigned minPrimitives   = 3, 
00098                      unsigned maxDepth        = KD_MAX_DEPTH, 
00099                      unsigned noThreads       = 1, 
00100                      bool postCompress        = true, 
00101                      real_t costTraversal     = 1, 
00102                      real_t emptyBias         = 0.9)
00103             : kdSplitPlaneType(splitType), 
00104               kdSplitAxisType(splitAxis), 
00105               kdMinPrimitives(minPrimitives), 
00106               kdMaxDepth(maxDepth), 
00107               kdNoThreads(noThreads), 
00108               kdPostCompress(postCompress), 
00109               kdCostTraversal(costTraversal), 
00110               kdEmptyBias(emptyBias)
00111          {
00112             ASSERT(kdMaxDepth <= KD_MAX_DEPTH);
00113          }
00114       };
00115       
00116    public:
00117       ///@name Constructors
00118       //@{-----------------------------------------------------------------
00119       
00120       explicit kdTreeAccel();
00121       virtual ~kdTreeAccel();
00122       
00123       
00124       //@}-----------------------------------------------------------------
00125       ///@name Initialization Routines
00126       //@{-----------------------------------------------------------------
00127       
00128       inline void setBuildParams(const BuildParams &buildParams) {
00129          m_buildParams = buildParams;
00130       }
00131       
00132       /**
00133        * Constructs a kd-Tree with the current BuildParams
00134        * @overridden
00135        */
00136       virtual void init();
00137       
00138       
00139       //@}-----------------------------------------------------------------
00140       ///@name Main usage interface
00141       //@{-----------------------------------------------------------------
00142       
00143       virtual real_t getIntersection(const Ray &ray, SurfacePoint &pt);
00144       
00145       virtual bool intersects(const Ray &ray, 
00146                               real_t tMax = INFINITY);
00147       
00148       virtual void preview();
00149       
00150       
00151       //@}-----------------------------------------------------------------
00152       ///@name Accessors
00153       //@{-----------------------------------------------------------------
00154       
00155       inline const BuildParams &getBuildParams() const {
00156          return m_buildParams;
00157       }
00158       
00159 #if DEBUG
00160       inline const std::vector<kdNode*> &getIntersectedDebugList() const {
00161          return m_intersected;
00162       }
00163 #endif
00164       
00165       //@}-----------------------------------------------------------------
00166       
00167    protected:
00168       void        _buildTree(kdWorkBuffer *);
00169       void        _buildTreeHelper(kdWorkBuffer *, kdNode *node, 
00170                                    IndexedIntersectableList *primitives, 
00171                                    const unsigned splitAxis, 
00172                                    const real_t   splitPos, 
00173                                    const unsigned depth);
00174       unsigned    _computeSplitAxis(kdWorkBuffer *) const;
00175       
00176       void        _postCompressTree();
00177       
00178       typedef void (kdTreeAccel::*SplitFunction) (kdWorkBuffer *) const;
00179       
00180       SplitFunction m_splitAxisFunction;
00181       SplitFunction m_splitPlaneFunction;
00182       
00183       // split axis functions
00184       void _computeSplitAxisRoundRobin(kdWorkBuffer *) const;
00185       void _computeSplitAxisLongestExtent(kdWorkBuffer *) const;
00186       
00187       // split position functions
00188       void _computeSplitPlaneMiddle(kdWorkBuffer *) const;
00189       void _computeSplitPlaneMedian(kdWorkBuffer *) const;
00190       void _computeSplitPlaneSAH   (kdWorkBuffer *) const;
00191       
00192       /// @returns number of candidate planes (planes stored in 'outPlanes')
00193       inline unsigned _computeSplitPlanesSAH(
00194          const IndexedIntersectableList &primitives, 
00195          const unsigned int noPrimitives, 
00196          const unsigned int splitAxis, 
00197          kdSplitPlane *outPlanes) const;
00198       
00199       /// @returns Surface Area Heuristic (SAH) cost for given subdivision
00200       ///    in out variable 'outCost'
00201       inline void     _computeSplitCostSAH(const kdWorkBuffer *, 
00202                                            real_t splitPos, 
00203                                            const unsigned splitAxis, 
00204                                            unsigned noLeft, 
00205                                            unsigned noPlane, 
00206                                            unsigned noRight, 
00207                                            kdSAHCost &outCost) const;
00208       
00209    protected:
00210       BuildParams    m_buildParams;
00211       
00212       // TODO: internal data structures
00213       kdNode        *m_root; 
00214       
00215    private:
00216       void _initProperties(kdWorkBuffer &);
00217       
00218       void _reset();
00219       
00220 #if DEBUG
00221    private:
00222       // for visualizing / debugging the order in which nodes are traversed
00223       std::vector<kdNode*> m_intersected;
00224 #endif
00225 };
00226 
00227 #endif // KD_TREE_ACCEL_H_
00228 

Generated on 28 Feb 2009 for Milton by doxygen 1.5.6