#ifndef _OspTree_H__ #define _OspTree_H__ #include #include "Mesh.h" #include "Containers.h" #include "Statistics.h" #include "VssRay.h" #include "RayInfo.h" #include "gzstream.h" #include "SubdivisionCandidate.h" namespace GtpVisibilityPreprocessor { class ViewCellLeaf; class Plane3; class AxisAlignedBox3; class Ray; class ViewCellsStatistics; class ViewCellsManager; class MergeCandidate; class Beam; class ViewCellsTree; class Environment; class VspInterior; class VspLeaf; class VspNode; class KdNode; class KdInterior; class KdLeaf; class OspTree; class KdIntersectable; class KdTree; class VspTree; class KdTreeStatistics; class SubdivisionCandidate; /** View space partition statistics. */ class OspTreeStatistics: public StatisticsBase { public: // total number of nodes int nodes; // number of splits int splits[3]; // maximal reached depth int maxDepth; // minimal depth int minDepth; // max depth nodes int maxDepthNodes; // minimum depth nodes int minDepthNodes; // max depth nodes int minPvsNodes; // minimum area nodes int minProbabilityNodes; /// nodes termination because of max cost ratio; int maxCostNodes; // max number of objects per node int maxObjectRefs; int objectRefs; /// samples contributing to pvs int contributingSamples; /// sample contributions to pvs int sampleContributions; /// largest pvs int maxPvs; /// number of invalid leaves int invalidLeaves; /// accumulated number of rays refs int accumRays; /// potentially visible objects from this leaf int pvs; // accumulated depth (used to compute average) int accumDepth; // Constructor OspTreeStatistics() { Reset(); } int Nodes() const {return nodes;} int Interior() const { return nodes / 2; } int Leaves() const { return (nodes / 2) + 1; } // TODO: computation wrong double AvgDepth() const { return accumDepth / (double)Leaves();}; void Reset() { nodes = 0; for (int i = 0; i < 3; ++ i) splits[i] = 0; maxDepth = 0; minDepth = 99999; accumDepth = 0; pvs = 0; maxDepthNodes = 0; minPvsNodes = 0; minProbabilityNodes = 0; maxCostNodes = 0; contributingSamples = 0; sampleContributions = 0; maxPvs = 0; invalidLeaves = 0; objectRefs = 0; maxObjectRefs = 0; } void Print(ostream &app) const; friend ostream &operator<<(ostream &s, const OspTreeStatistics &stat) { stat.Print(s); return s; } }; typedef map KdIntersectableMap; /** View Space Partitioning tree. */ class OspTree { friend class ViewCellsParseHandlers; friend class HierarchyManager; public: /** Additional data which is passed down the BSP tree during traversal. */ class OspTraversalData { public: /// the current node KdLeaf *mNode; /// current depth int mDepth; /// rays piercing this node RayInfoContainer *mRays; /// the probability that this node contains view point float mProbability; /// the bounding box of the node AxisAlignedBox3 mBoundingBox; /// pvs size float mRenderCost; /// how often this branch has missed the max-cost ratio int mMaxCostMisses; // current axis int mAxis; // current priority float mPriority; OspTraversalData(): mNode(NULL), mRays(NULL), mDepth(0), mRenderCost(0), mProbability(0.0), mMaxCostMisses(0), mPriority(0), mAxis(0) {} OspTraversalData(KdLeaf *node, const int depth, RayInfoContainer *rays, const float rc, const float p, const AxisAlignedBox3 &box): mNode(node), mDepth(depth), mRays(rays), mRenderCost(rc), mProbability(p), mBoundingBox(box), mMaxCostMisses(0), mPriority(0), mAxis(0) {} OspTraversalData(const int depth, RayInfoContainer *rays, const AxisAlignedBox3 &box): mNode(NULL), mDepth(depth), mRays(rays), mRenderCost(0), mProbability(0), mMaxCostMisses(0), mAxis(0), mBoundingBox(box) {} /** Returns cost of the traversal data. */ float GetCost() const { //cout << mPriority << endl; return mPriority; } /// deletes contents and sets them to NULL void Clear() { DEL_PTR(mRays); } friend bool operator<(const OspTraversalData &a, const OspTraversalData &b) { return a.GetCost() < b.GetCost(); } }; /** Candidate for a view space split. */ class OspSubdivisionCandidate: public SubdivisionCandidate { public: static OspTree* sOspTree; /// the current split plane AxisAlignedPlane mSplitPlane; /// parent data OspTraversalData mParentData; OspSubdivisionCandidate(const OspTraversalData &tData): mParentData(tData) {}; int Type() const { return OBJECT_SPACE; } void EvalPriority() { sOspTree->EvalSubdivisionCandidate(*this); } bool GlobalTerminationCriteriaMet() const { return sOspTree->GlobalTerminationCriteriaMet(mParentData); } OspSubdivisionCandidate(const AxisAlignedPlane &plane, const OspTraversalData &tData): mSplitPlane(plane), mParentData(tData) {} }; /** Struct for traversing line segment. */ struct LineTraversalData { KdNode *mNode; Vector3 mExitPoint; float mMaxT; LineTraversalData () {} LineTraversalData (KdNode *n, const Vector3 &p, const float maxt): mNode(n), mExitPoint(p), mMaxT(maxt) {} }; /** Default constructor creating an empty tree. */ OspTree(); /** Copies tree from a kd tree. */ OspTree(const KdTree &kdTree); /** Default destructor. */ ~OspTree(); /** Returns tree statistics. */ const OspTreeStatistics &GetStatistics() const; /** Returns bounding box of the specified node. */ AxisAlignedBox3 GetBoundingBox(KdNode *node) const; /** Returns list of leaves with pvs smaller than a certain threshold. @param onlyUnmailed if only the unmailed leaves should be considered @param maxPvs the maximal pvs of a leaf to be added (-1 means unlimited) */ void CollectLeaves(vector &leaves) const; /** Returns bounding box of the whole tree (= bbox of root node) */ AxisAlignedBox3 GetBoundingBox()const; /** Returns root of the view space partitioning tree. */ KdNode *GetRoot() const; /** Collects the leaf view cells of the tree @param viewCells returns the view cells */ void CollectViewCells(ViewCellContainer &viewCells, bool onlyValid) 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); /** finds neighbouring leaves of this tree node. */ int FindNeighbors(KdLeaf *n, vector &neighbors, const bool onlyUnmailed) const; /** Returns random leaf of BSP tree. @param halfspace defines the halfspace from which the leaf is taken. */ KdLeaf *GetRandomLeaf(const Plane3 &halfspace); /** Returns random leaf of BSP tree. @param onlyUnmailed if only unmailed leaves should be returned. */ KdLeaf *GetRandomLeaf(const bool onlyUnmailed = false); /** Returns epsilon of this tree. */ float GetEpsilon() const; /** Casts line segment into the tree. @param origin the origin of the line segment @param termination the end point of the line segment @returns view cells intersecting the line segment. */ int CastLineSegment(const Vector3 &origin, const Vector3 &termination, ViewCellContainer &viewcells); /** Sets pointer to view cells manager. */ void SetViewCellsManager(ViewCellsManager *vcm); /** Writes tree to output stream */ bool Export(OUT_STREAM &stream); /** Returns or creates a new intersectable for use in a kd based pvs. The OspTree is responsible for destruction of the intersectable. */ KdIntersectable *GetOrCreateKdIntersectable(KdNode *node); /** Collects rays stored in the leaves. */ void CollectRays(VssRayContainer &rays); /** Intersects box with the tree and returns the number of intersected boxes. @returns number of view cells found */ int ComputeBoxIntersections(const AxisAlignedBox3 &box, ViewCellContainer &viewCells) const; /** Returns kd leaf the point pt lies in, starting from root. */ KdLeaf *GetLeaf(const Vector3 &pt, KdNode *root = NULL) const; ViewCellsTree *GetViewCellsTree() const { return mViewCellsTree; } void SetViewCellsTree(ViewCellsTree *vt) { mViewCellsTree = vt; } float EvalRenderCost(const VssRayContainer &myrays); float EvalLeafCost(const OspTraversalData &tData); /** Adds this objects to the kd leaf objects. @warning: Can corrupt the tree */ void InsertObjects(KdNode *node, const ObjectContainer &objects); /** Add the leaf to the pvs of the view cell. */ bool AddLeafToPvs( KdLeaf *leaf, ViewCell *vc, const float pdf, float &contribution); protected: // -------------------------------------------------------------- // For sorting objects // -------------------------------------------------------------- struct SortableEntry { /** There is a 3th "event" for rays which intersect a box in the middle. These "events" don't induce a change in pvs size, but may induce a change in view cell volume. */ enum EType { BOX_MIN, BOX_MAX, BOX_INTERSECT }; int mType; //int mPvs; float mPos; VssRay *mRay; Intersectable *mObject; SortableEntry() {} SortableEntry(const int type, //const float pvs, const float pos, Intersectable *obj, VssRay *ray): mType(type), //mPvs(pvs), mPos(pos), mObject(obj), mRay(ray) {} bool operator<(const SortableEntry &b) const { return mPos < b.mPos; } }; /** faster evaluation of split plane cost for kd axis aligned cells. */ float EvalLocalSplitCost(const OspTraversalData &data, const AxisAlignedBox3 &box, const int axis, const float &position, float &pFront, float &pBack) const; /** Evaluates candidate for splitting. */ void EvalSubdivisionCandidate(OspSubdivisionCandidate &splitData); /** Computes priority of the traversal data and stores it in tData. */ void EvalPriority(OspTraversalData &tData) const; /** Evaluates render cost decrease of next split. */ float EvalRenderCostDecrease(const AxisAlignedPlane &candidatePlane, const OspTraversalData &data, float &normalizedOldRenderCost) const; /** Collects view cells in the subtree under root. */ void CollectViewCells(KdNode *root, bool onlyValid, ViewCellContainer &viewCells, bool onlyUnmailed = false) const; /** Evaluates tree stats in the BSP tree leafs. */ void EvaluateLeafStats(const OspTraversalData &data); /** Subdivides node using a best split priority queue. @param tQueue the best split priority queue @param splitCandidate the candidate for the next split @param globalCriteriaMet if the global termination criteria were already met @returns new root of the subtree */ KdNode *Subdivide(SplitQueue &tQueue, SubdivisionCandidate *splitCandidate, const bool globalCriteriaMet); /** Subdivides 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 */ KdInterior *SubdivideNode( const AxisAlignedPlane &splitPlane, const OspTraversalData &tData, OspTraversalData &frontData, OspTraversalData &backData); void SplitObjects(KdLeaf *leaf, const AxisAlignedPlane & splitPlane, const ObjectContainer &objects, ObjectContainer &front, ObjectContainer &back); /** does some post processing on the objects in the new child leaves. */ void ProcessMultipleRefs(KdLeaf *leaf) const; /** Sorts split candidates for cost heuristics using axis aligned splits. @param node the current node @param axis the current split axis */ void SortSubdivisionCandidates(const OspTraversalData &data, const int axis, float minBand, float maxBand); /** Computes best cost for axis aligned planes. */ float EvalLocalCostHeuristics(const OspTraversalData &tData, const AxisAlignedBox3 &box, const int axis, float &position, int &objectsFront, int &objectsBack); /** 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 AxisAlignedPlane &plane, RayInfoContainer &rays, RayInfoContainer &frontRays, RayInfoContainer &backRays) const; int FilterRays(KdLeaf *leaf, const RayInfoContainer &rays, RayInfoContainer &filteredRays); /** 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 UpdateObjPvsContri(Intersectable *obj, const int cf, float &frontPvs, float &backPvs, float &totalPvs) const; /** Returns true if tree can be terminated. */ bool LocalTerminationCriteriaMet(const OspTraversalData &data) const; /** Returns true if global tree can be terminated. */ bool GlobalTerminationCriteriaMet(const OspTraversalData &data) const; /** Selects an axis aligned for the next split. @returns cost for this split */ float SelectSplitPlane( const OspTraversalData &tData, AxisAlignedPlane &plane); /** Propagates valid flag up the tree. */ void PropagateUpValidity(KdNode *node); /** Writes the node to disk @note: should be implemented as visitor. */ void ExportNode(KdNode *node, OUT_STREAM &stream); /** Returns estimated memory usage of tree. */ float GetMemUsage() const; /** Evaluate the contributions of view cell volume of the left and the right view cell. */ void EvalRayContribution( KdLeaf *leaf, const VssRay &ray, float &renderCost); void EvalViewCellContribution( KdLeaf *leaf, ViewCell *viewCell, float &renderCost); /** Evaluates the influence on the pvs of the event. @param ve the visibility event @param pvsLeft updates the left pvs @param rightPvs updates the right pvs */ void EvalHeuristicsContribution(KdLeaf *leaf, const SortableEntry &ci, float &renderCost, ViewCellContainer &touchedViewCells); /** Prepares objects for the cost heuristics. @returns pvs size of the node */ float PrepareHeuristics( const OspTraversalData &tData, ViewCellContainer &touchedViewCells); /** Prepares heuristics for a particular ray. */ void PrepareHeuristics( const VssRay &ray, ViewCellContainer &touchedViewCells); /** Prepares construction for vsp and osp trees. */ void ComputeBoundingBox(const ObjectContainer &objects); void CollectDirtyCandidates(OspSubdivisionCandidate *sc, vector &dirtyList); /** Collect view cells which see this kd leaf. */ void CollectViewCells(KdLeaf *leaf, ViewCellContainer &viewCells); /** Rays will be clipped to the bounding box. */ void PreprocessRays( KdLeaf *root, const VssRayContainer &sampleRays, RayInfoContainer &rays); /** Reads parameters from environment singleton. */ void ReadEnvironment(); /** Returns true if the specified ray end points is inside the kd leaf. @param isTermination if origin or termination point should be checked */ bool EndPointInsideNode(KdLeaf *leaf, VssRay &ray, bool isTermination) const; void AddViewCellVolumeContri( ViewCell *vc, float &frontVol, float &backVol, float &frontAndBackVol) const; /** Classifies and mail view cell with respect to the heuristics contribution. Set view cell mail box according to it's influence on front (0), back (1) and front / back node (2). */ void MailViewCell(ViewCell *vc, const int cf) const; int ClassifyRay(VssRay *ray, KdLeaf *leaf, const AxisAlignedPlane &plane) const; void EvalSubdivisionStats(const SubdivisionCandidate &tData); void AddSubdivisionStats(const int viewCells, const float renderCostDecr, const float totalRenderCost); void EvalViewCellsForHeuristics(const VssRay &ray, float &volLeft, float &volRight); float EvalViewCellsVolume(KdLeaf *leaf, const RayInfoContainer &rays) const; int RemoveParentViewCellsPvs(KdLeaf *leaf, const RayInfoContainer &rays ) const; int UpdateViewCellsPvs(KdLeaf *leaf, const RayInfoContainer &rays) const; int CheckViewCellsPvs(KdLeaf *leaf, const RayInfoContainer &rays) const; bool AddViewCellToObjectPvs( Intersectable *obj, ViewCell *vc, float &contribution, bool onlyMailed) const; int ClassifyRays( const RayInfoContainer &rays, KdLeaf *leaf, const AxisAlignedPlane &plane, RayInfoContainer &frontRays, RayInfoContainer &backRays) const; void CollectTouchedViewCells( const RayInfoContainer &rays, ViewCellContainer &touchedViewCells) const; void AddObjectContribution( KdLeaf *leaf, Intersectable * obj, ViewCellContainer &touchedViewCells, float &renderCost); void SubtractObjectContribution( KdLeaf *leaf, Intersectable * obj, ViewCellContainer &touchedViewCells, float &renderCost); SubdivisionCandidate *PrepareConstruction( const VssRayContainer &sampleRays, const ObjectContainer &objects, RayInfoContainer &rays); protected: /// pointer to the hierarchy of view cells ViewCellsTree *mViewCellsTree; VspTree *mVspTree; /// The view cells manager ViewCellsManager *mViewCellsManager; /// candidates for placing split planes during cost heuristics vector *mSubdivisionCandidates; /// Pointer to the root of the tree KdNode *mRoot; /// Statistics for the object space partition OspTreeStatistics mOspStats; /// box around the whole view domain AxisAlignedBox3 mBoundingBox; //-- local termination /// maximal possible depth int mTermMaxDepth; /// mininum probability float mTermMinProbability; /// minimal number of objects int mTermMinObjects; /// maximal contribution per ray float mTermMaxRayContribution; /// maximal acceptable cost ratio float mTermMaxCostRatio; /// tolerance value indicating how often the max cost ratio can be failed int mTermMissTolerance; //-- global criteria float mTermMinGlobalCostRatio; int mTermGlobalCostMissTolerance; int mGlobalCostMisses; /// maximal number of view cells int mTermMaxLeaves; /// maximal tree memory float mMaxMemory; /// the tree is out of memory bool mOutOfMemory; //-- split heuristics based parameters bool mUseCostHeuristics; /// balancing factor for PVS criterium float mCtDivCi; /// if only driving axis should be used for split bool mOnlyDrivingAxis; /// current time stamp (used for keeping split history) int mTimeStamp; // if rays should be stored in leaves bool mStoreRays; /// epsilon for geometric comparisons float mEpsilon; /// subdivision stats output file ofstream mSubdivisionStats; /// keeps track of cost during subdivision float mTotalCost; /// keeps track of overall pvs size during subdivision int mTotalPvsSize; /// number of currenly generated view cells int mCreatedLeaves; /// represents min and max band for sweep float mSplitBorder; /// weight between render cost decrease and node render cost float mRenderCostDecreaseWeight; /// stores the kd node intersectables used for pvs KdIntersectableMap mKdIntersectables; private: bool mCopyFromKdTree; }; } #endif