#ifndef _VspBspTree_H__ #define _VspBspTree_H__ #include "Mesh.h" #include "Containers.h" #include "Polygon3.h" #include #include "Statistics.h" #include "VssRay.h" #include "RayInfo.h" #include "ViewCellBsp.h" class ViewCell; class BspViewCell; class Plane3; class VspBspTree; class BspInterior; class BspNode; class AxisAlignedBox3; class Ray; /*class BspNodeGeometry; class BspTreeStatistics; class BspViewCellsStatistics; class BspNode; class BspLeaf; class BspInterior; */ /** This is a view space partitioning specialised BSPtree. There are no polygon splits, but we split the sample rays. The candidates for the next split plane are evaluated only by checking the sampled visibility information. The polygons are employed merely as candidates for the next split planes. */ class VspBspTree { public: /** Additional data which is passed down the BSP tree during traversal. */ struct VspBspTraversalData { /// the current node BspNode *mNode; /// polygonal data for splitting PolygonContainer *mPolygons; /// current depth int mDepth; /// rays piercing this node RayInfoContainer *mRays; /// area of current node float mArea; /// geometry of node as induced by planes BspNodeGeometry *mGeometry; /// pvs size int mPvs; /** Returns average ray contribution. */ float GetAvgRayContribution() const { return (float)mPvs / ((float)mRays->size() + Limits::Small); } VspBspTraversalData(): mNode(NULL), mPolygons(NULL), mDepth(0), mRays(NULL), mPvs(0), mArea(0.0), mGeometry(NULL) {} VspBspTraversalData(BspNode *node, PolygonContainer *polys, const int depth, RayInfoContainer *rays, int pvs, float area, BspNodeGeometry *geom): mNode(node), mPolygons(polys), mDepth(depth), mRays(rays), mPvs(pvs), mArea(area), mGeometry(geom) {} VspBspTraversalData(PolygonContainer *polys, const int depth, RayInfoContainer *rays, BspNodeGeometry *geom): mNode(NULL), mPolygons(polys), mDepth(depth), mRays(rays), mPvs(0), mArea(0), mGeometry(geom) {} }; typedef std::stack VspBspTraversalStack; /** Default constructor creating an empty tree. */ VspBspTree(); /** Default destructor. */ ~VspBspTree(); /** Returns BSP Tree statistics. */ const BspTreeStatistics &GetStatistics() const; /** Constructs the tree from a given set of rays. @param sampleRays the set of sample rays the construction is based on @param viewCells if not NULL, new view cells are created in the leafs and stored in the container */ void Construct(const VssRayContainer &sampleRays); /** Returns list of BSP leaves. */ void CollectLeaves(vector &leaves) const; /** Returns box which bounds the whole tree. */ AxisAlignedBox3 GetBoundingBox()const; /** Returns root of BSP tree. */ BspNode *GetRoot() const; /** Exports VspBsp tree to file. */ bool Export(const string filename); /** Collects the leaf view cells of the tree @param viewCells returns the view cells */ void CollectViewCells(ViewCellContainer &viewCells) const; /** A ray is cast possible intersecting the tree. @param the ray that is cast. @returns the number of intersections with objects stored in the tree. */ int CastRay(Ray &ray); /// bsp tree construction types enum {FROM_INPUT_VIEW_CELLS, FROM_SCENE_GEOMETRY, FROM_SAMPLES}; /** Returns statistics. */ BspTreeStatistics &GetStat(); /** finds neighbouring leaves of this tree node. */ int FindNeighbors(BspNode *n, vector &neighbors, const bool onlyUnmailed) const; /** Constructs geometry associated with the half space intersections leading to this node. */ void ConstructGeometry(BspNode *n, PolygonContainer &cell) const; /** Constructs geometry associated with the half space intersections leading to this node. */ void ConstructGeometry(BspViewCell *vc, PolygonContainer &cell) const; /** Construct geometry and stores it in a geometry node container. */ void ConstructGeometry(BspNode *n, BspNodeGeometry &cell) const; /** Returns random leaf of BSP tree. @param halfspace defines the halfspace from which the leaf is taken. */ BspLeaf *GetRandomLeaf(const Plane3 &halfspace); /** Returns random leaf of BSP tree. @param onlyUnmailed if only unmailed leaves should be returned. */ BspLeaf *GetRandomLeaf(const bool onlyUnmailed = false); /** Traverses tree and counts all view cells as well as their PVS size. */ void EvaluateViewCellsStats(BspViewCellsStatistics &stat) const; /** Returns view cell corresponding to unbounded space. */ BspViewCell *GetRootCell() const; /** Returns epsilon of this tree. */ float GetEpsilon() const; protected: // -------------------------------------------------------------- // For sorting objects // -------------------------------------------------------------- struct SortableEntry { enum {POLY_MIN, POLY_MAX}; int type; float value; Polygon3 *poly; SortableEntry() {} SortableEntry(const int t, const float v, Polygon3 *poly): type(t), value(v), poly(poly) {} bool operator<(const SortableEntry &b) const { return value < b.value; } }; /** Evaluates tree stats in the BSP tree leafs. */ void EvaluateLeafStats(const VspBspTraversalData &data); /** Subdivides node with respect to the traversal data. @param tStack current traversal stack @param tData traversal data also holding node to be subdivided @returns new root of the subtree */ BspNode *Subdivide(VspBspTraversalStack &tStack, VspBspTraversalData &tData); /** Constructs the tree from the given traversal data. @param polys stores set of polygons on which subdivision may be based @param rays storesset of rays on which subdivision may be based */ void Construct(const PolygonContainer &polys, RayInfoContainer *rays); /** Selects the best possible splitting plane. @param leaf the leaf to be split @param polys the polygon list on which the split decition is based @param rays ray container on which selection may be based @note the polygons can be reordered in the process @returns the split plane */ Plane3 SelectPlane(BspLeaf *leaf, VspBspTraversalData &data); /** Strategies where the effect of the split plane is tested on all input rays. @returns the cost of the candidate split plane */ float SplitPlaneCost(const Plane3 &candidatePlane, const VspBspTraversalData &data); /** Subdivide leaf. @param leaf the leaf to be subdivided @param polys the polygons to be split @param frontPolys returns the polygons in front of the split plane @param backPolys returns the polygons in the back of the split plane @param rays the polygons to be filtered @param frontRays returns the polygons in front of the split plane @param backRays returns the polygons in the back of the split plane @returns the root of the subdivision */ BspInterior *SubdivideNode(VspBspTraversalData &tData, VspBspTraversalData &frontData, VspBspTraversalData &backData, PolygonContainer &coincident); /** Selects the split plane in order to construct a tree with certain characteristics (e.g., balanced tree, least splits, 2.5d aligned) @param polygons container of polygons @param rays bundle of rays on which the split can be based */ Plane3 SelectPlaneHeuristics(BspLeaf *leaf, VspBspTraversalData &data); /** Extracts the meshes of the objects and adds them to polygons. Adds object aabb to the aabb of the tree. @param maxPolys the maximal number of objects to be stored as polygons @returns the number of polygons */ int AddToPolygonSoup(const ObjectContainer &objects, PolygonContainer &polys, int maxObjects = 0); /** Extracts the meshes of the view cells and and adds them to polygons. Adds view cell aabb to the aabb of the tree. @param maxPolys the maximal number of objects to be stored as polygons @returns the number of polygons */ int AddToPolygonSoup(const ViewCellContainer &viewCells, PolygonContainer &polys, int maxObjects = 0); /** Extract polygons of this mesh and add to polygon container. @param mesh the mesh that drives the polygon construction @param parent the parent intersectable this polygon is constructed from @returns number of polygons */ int AddMeshToPolygons(Mesh *mesh, PolygonContainer &polys, MeshInstance *parent); /** returns next candidate index and reorders polygons so no candidate is chosen two times @param the current candidate index @param max the range of candidates */ int GetNextCandidateIdx(int currentIdx, PolygonContainer &polys); /** Computes best cost ratio for the suface area heuristics for axis aligned splits. This heuristics minimizes the cost for ray traversal. @param polys the polygons guiding the ratio computation @param box the bounding box of the leaf @param axis the current split axis @param position returns the split position @param objectsBack the number of objects in the back of the split plane @param objectsFront the number of objects in the front of the split plane */ float BestCostRatio(const PolygonContainer &polys, const AxisAlignedBox3 &box, const int axis, float &position, int &objectsBack, int &objectsFront) const; /** Sorts split candidates for surface area heuristics for axis aligned splits. @param polys the input for choosing split candidates @param axis the current split axis @param splitCandidates returns sorted list of split candidates */ void SortSplitCandidates(const PolygonContainer &polys, const int axis, vector &splitCandidates) const; /** Selects an axis aligned split plane. Returns true if split is valied */ bool SelectAxisAlignedPlane(Plane3 &plane, const PolygonContainer &polys) const; /** Subdivides the rays into front and back rays according to the split plane. @param plane the split plane @param rays contains the rays to be split. The rays are distributed into front and back rays. @param frontRays returns rays on the front side of the plane @param backRays returns rays on the back side of the plane @returns the number of splits */ int SplitRays(const Plane3 &plane, RayInfoContainer &rays, RayInfoContainer &frontRays, RayInfoContainer &backRays); /** Extracts the split planes representing the space bounded by node n. */ void ExtractHalfSpaces(BspNode *n, vector &halfSpaces) const; /** Adds the object to the pvs of the front and back leaf with a given classification. @param obj the object to be added @param cf the ray classification regarding the split plane @param frontPvs returns the PVS of the front partition @param backPvs returns the PVS of the back partition */ void AddObjToPvs(Intersectable *obj, const int cf, int &frontPvs, int &backPvs) const; /** Computes PVS size induced by the rays. */ int ComputePvsSize(const RayInfoContainer &rays) const; /** Returns true if tree can be terminated. */ inline bool TerminationCriteriaMet(const VspBspTraversalData &data) const; /** Computes accumulated ray lenght of this rays. */ float AccumulatedRayLength(const RayInfoContainer &rays) const; /** Splits polygons with respect to the split plane. @param plane the split plane @param polys the polygons to be split. the polygons are consumed and distributed to the containers frontPolys, backPolys, coincident. @param frontPolys returns the polygons in the front of the split plane @param backPolys returns the polygons in the back of the split plane @param coincident returns the polygons coincident to the split plane @returns the number of splits */ int SplitPolygons(const Plane3 &plane, PolygonContainer &polys, PolygonContainer &frontPolys, PolygonContainer &backPolys, PolygonContainer &coincident) const; /** Adds ray sample contributions to the PVS. @param sampleContributions the number contributions of the samples @param contributingSampels the number of contributing rays */ void AddToPvs(BspLeaf *leaf, const RayInfoContainer &rays, int &sampleContributions, int &contributingSamples); /// Pointer to the root of the tree BspNode *mRoot; BspTreeStatistics mStat; /// Strategies for choosing next split plane. enum {NO_STRATEGY = 0, RANDOM_POLYGON = 1, AXIS_ALIGNED = 2, LEAST_RAY_SPLITS = 256, BALANCED_RAYS = 512, PVS = 1024 }; /// box around the whole view domain AxisAlignedBox3 mBox; /// view cell corresponding to unbounded space BspViewCell *mRootCell; /// minimal number of rays before subdivision termination int mTermMinRays; /// maximal possible depth int mTermMaxDepth; /// mininum area float mTermMinArea; /// mininum PVS int mTermMinPvs; /// minimal number of rays for axis aligned split int mTermMinRaysForAxisAligned; /// minimal number of objects for axis aligned split int mTermMinObjectsForAxisAligned; /// maximal contribution per ray float mTermMaxRayContribution; /// minimal accumulated ray length float mTermMinAccRayLength; /// strategy to get the best split plane int mSplitPlaneStrategy; /// number of candidates evaluated for the next split plane int mMaxPolyCandidates; /// number of candidates for split planes evaluated using the rays int mMaxRayCandidates; /// balancing factor for PVS criterium float mCtDivCi; //-- axis aligned split criteria float mAaCtDivCi; float mSplitBorder; float mMaxCostRatio; //-- factors guiding the split plane heuristics float mLeastRaySplitsFactor; float mBalancedRaysFactor; float mPvsFactor; /// if area or accumulated ray lenght should be used for PVS heuristics bool mPvsUseArea; float mEpsilon; int mMaxTests; private: static const float sLeastRaySplitsTable[5]; /** Evaluates split plane classification with respect to the plane's contribution for balanced rays. */ static const float sBalancedRaysTable[5]; /// Generates unique ids for PVS criterium static void GenerateUniqueIdsForPvs(); //-- unique ids for PVS criterium static int sFrontId; static int sBackId; static int sFrontAndBackId; }; #endif