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
1.5.6