/******************************************************************/ /* BVH.h */ /* ----------------------- */ /* */ /* The file defines an object container (i.e., an object that */ /* contains numerous others). This container creates a */ /* bounding volume hierarchy of the geometry stored inside. */ /* This allows for significantly improved traversal speeds. */ /* However, this may or may not be the most efficient */ /* acceleration structure, and the heuristic for dividing */ /* the geometry may need improvement! */ /* */ /* Chris Wyman (10/26/2006) */ /******************************************************************/ #ifndef NaiveBVH_H #define NaiveBVH_H #include "DataTypes/Array1D.h" #include "Objects/Object.h" #include "Objects/Group.h" #include "Core/Ray.h" using namespace std; // These are internal classed (described below) that // represent the tree, and a temporary structure used // during BVH creation. class NaiveBVHNode; class NaiveBVHSortable; // The NaiveBVH class! class NaiveBVH : public Group { public: // Constructors and destructors. // The BVH is implemented using an array of nodes with implicit indexing // to move from parent->child. Because of that, in order to use "naive" // median splitting to split geometry into two equal chunks, extra unused // nodes must be allocated. This can be avoided by using a different // choice for how to partition geometry. // Setting useMinimalNodeCount to true will generate a BVH tree using 2*N-1 // nodes, whereas setting it to false will generate a tree using up to // 4*N-1 nodes, with up to half remaining unused. NaiveBVH( bool useMinimalNodeCount=true ); virtual ~NaiveBVH(); // NaiveBVH::Preprocess() not only creates the tree structure necessary for // traversal, it also calls obj->Preprocess() on all geometry contained // inside the NaiveBVH. virtual void Preprocess( void ); // NaiveBVH::Intersect() traverses the BVH tree to reasonably efficiently // find intersections with the contained geometry. virtual void Intersect( Ray &ray ); private: // A flag that determins if the tree has been built. Not really necessary. bool bvhBuildComplete; // Stores the parameter passed to the NaiveBVH at creation. bool useMinimalNodeCount; // An array containing nodes in out BVH tree (once it's been created!) Array1D nodes; // BuildHierarchy() handles the heavy lifting when creating the BVH. This // function is called by Preprocess() void BuildHierarchy( unsigned int parentIdx, unsigned int startIdx, unsigned int endIdx, NaiveBVHSortable *data ); // IntersectBBox() and IntersectNode() do the heavy lifting for traversing // the BVH tree inside of Intersect(). bool IntersectBBox( Ray &ray, Point *bounds ) const; void IntersectNode( Ray &ray, unsigned int index ); // These are sorting functions needed by BuildHierarchy() static int SortObjectsByX( const void *A, const void *B ); static int SortObjectsByY( const void *A, const void *B ); static int SortObjectsByZ( const void *A, const void *B ); }; // Bitmasks used on the flags member of the NaiveBVHNode. #define NAIVEBVHNODE_LEAFMASK 0x00000001 #define NAIVEBVHNODE_ISLEAF 0x00000000 #define NAIVEBVHNODE_NOTLEAF 0x00000001 // This is the class that stores BVH tree nodes after it's been created class NaiveBVHNode { public: Point bounds[2]; // bound[0] = min of volume, bound[1] = max of volume union { Object *ptr; unsigned int flags; }; inline bool IsLeaf( void ) { return ( flags & NAIVEBVHNODE_LEAFMASK ) == NAIVEBVHNODE_ISLEAF; } // methods for moving around in the implicitly stored tree static inline unsigned int GetLeftChild( unsigned int parentIdx ) { return 2*parentIdx+1; } static inline unsigned int GetRightChild( unsigned int parentIdx ) { return 2*parentIdx+2; } static inline unsigned int GetParentNode( unsigned int childIdx ) { return (childIdx-1)/2; } }; // This is a slightly larger structure used during BVH creation. Feel free // to add variables and functionality here to improve build quality (or speed). // Try to avoid increasing the size of the NaiveBVHNode. class NaiveBVHSortable { public: BBox bbox; Object *ptr; unsigned int finalNodeIdx; bool counted; }; #endif