source: trunk/VUT/GtpVisibilityPreprocessor/src/VspBspTree.h @ 437

Revision 437, 19.6 KB checked in by mattausch, 19 years ago (diff)

detected leak in BspTree?
added specialised fast view cell bsp tree called VspBspTree?

Line 
1#ifndef _VspBspTree_H__
2#define _VspBspTree_H__
3
4#include "Mesh.h"
5#include "Containers.h"
6#include "Polygon3.h"
7#include <stack>
8#include "Statistics.h"
9#include "VssRay.h"
10#include "RayInfo.h"
11
12class ViewCell;
13class BspViewCell;
14class Plane3;
15class VspBspTree; 
16class VspBspInterior;
17class VspBspNode;
18class AxisAlignedBox3;
19class Ray;
20
21class VspBspNodeGeometry
22{
23public:
24        VspBspNodeGeometry()
25        {}; 
26
27        ~VspBspNodeGeometry();
28
29        float GetArea() const;
30       
31        /** Computes new cell based on the old cell definition and a new split plane
32                @param side indicates which side of the halfspace
33        */
34        void SplitGeometry(VspBspNodeGeometry &front,
35                                           VspBspNodeGeometry &back,
36                                           const VspBspTree &tree,
37                                           const Plane3 &splitPlane) const;
38
39        Polygon3 *SplitPolygon(Polygon3 *poly, const VspBspTree &tree) const;
40
41        PolygonContainer mPolys;
42};
43
44/** Data structure used for optimized ray casting.
45*/
46struct VspBspRayTraversalData
47{
48    VspBspNode *mNode;
49    Vector3 mExitPoint;
50    float mMaxT;
51   
52    VspBspRayTraversalData() {}
53
54    VspBspRayTraversalData(VspBspNode *n, const Vector3 &extp, const float maxt):
55    mNode(n), mExitPoint(extp), mMaxT(maxt)
56        {}
57};
58
59class VspBspTreeStatistics: public StatisticsBase
60{
61public:
62        // total number of nodes
63        int nodes;
64        // number of splits
65        int splits;
66        // totals number of rays
67        int rays;
68        // maximal reached depth
69        int maxDepth;
70        // minimal depth
71        int minDepth;
72       
73        // max depth nodes
74        int maxDepthNodes;
75        // minimum depth nodes
76        int minDepthNodes;
77        // max depth nodes
78        int minPvsNodes;
79        // nodes with minimum PVS
80        int minRaysNodes;
81        // max ray contribution nodes
82        int maxRayContribNodes;
83        // minimum area nodes
84        int minAreaNodes;
85
86        // max number of rays per node
87        int maxObjectRefs;
88        // accumulated depth (used to compute average)
89        int accumDepth;
90        // number of initial polygons
91        int polys;
92        /// samples contributing to pvs
93        int contributingSamples;
94        /// sample contributions to pvs
95        int sampleContributions;
96        /// largest pvs
97        int largestPvs;
98
99        // Constructor
100        VspBspTreeStatistics()
101        {
102                Reset();
103        }
104
105        int Nodes() const {return nodes;}
106        int Interior() const { return nodes / 2; }
107        int Leaves() const { return (nodes / 2) + 1; }
108       
109        // TODO: computation wrong
110        double AvgDepth() const { return accumDepth / (double)Leaves();};
111 
112        void Reset()
113        {
114                nodes = 0;
115                splits = 0;
116               
117                maxDepth = 0;
118                minDepth = 99999;
119                polys = 0;
120                accumDepth = 0;
121       
122                maxDepthNodes = 0;
123                minPvsNodes = 0;
124                minRaysNodes = 0;
125                maxRayContribNodes = 0;
126                minAreaNodes = 0;
127
128                contributingSamples = 0;
129                sampleContributions = 0;
130        }
131
132        void Print(ostream &app) const;
133
134        friend ostream &operator<<(ostream &s, const VspBspTreeStatistics &stat)
135        {
136                stat.Print(s);
137                return s;
138        }
139};
140
141class VspBspViewCellsStatistics: public StatisticsBase
142{
143public:
144
145        /// number of view cells
146        int viewCells;
147
148        /// size of the PVS
149        int pvs;
150 
151        /// largest PVS of all view cells
152        int maxPvs;
153
154        /// smallest PVS of all view cells
155        int minPvs;
156
157        /// view cells with empty PVS
158        int emptyPvs;
159
160        /// number of bsp leaves covering the view space
161        int bspLeaves;
162
163        /// largest number of leaves covered by one view cell 
164        int maxVspBspLeaves;
165
166    // Constructor
167        VspBspViewCellsStatistics()
168        {
169                Reset();
170        }
171
172        double AvgVspBspLeaves() const {return (double)bspLeaves / (double)viewCells;};
173        double AvgPvs() const {return (double)pvs / (double)viewCells;};
174 
175        void Reset()
176        {
177                viewCells = 0; 
178                pvs = 0; 
179                maxPvs = 0;
180
181                minPvs = 999999;
182                emptyPvs = 0;
183                bspLeaves = 0;
184                maxVspBspLeaves = 0;
185        }
186
187        void Print(ostream &app) const;
188
189        friend ostream &operator<<(ostream &s, const VspBspViewCellsStatistics &stat)
190        {
191                stat.Print(s);
192                return s;
193        } 
194};
195
196/**
197    VspBspNode abstract class serving for interior and leaf node implementation
198*/
199class VspBspNode
200{
201        friend class VspBspTree;
202
203public:
204        VspBspNode();
205        virtual ~VspBspNode(){};
206        VspBspNode(VspBspInterior *parent);
207
208        /** Determines whether this node is a leaf or not
209        @return true if leaf
210        */
211        virtual bool IsLeaf() const = 0;
212
213        /** Determines whether this node is a root
214        @return true if root
215        */
216        virtual bool IsRoot() const;
217
218        /** Returns parent node.
219        */
220        VspBspInterior *GetParent();
221
222        /** Sets parent node.
223        */
224        void SetParent(VspBspInterior *parent);
225
226       
227        static int sMailId;
228        int mMailbox;
229 
230        void Mail() { mMailbox = sMailId; }
231        static void NewMail() { ++ sMailId; }
232        bool Mailed() const { return mMailbox == sMailId; }
233
234protected:
235
236        /// parent of this node
237        VspBspInterior *mParent;
238};
239
240/** BSP interior node implementation
241*/
242class VspBspInterior : public VspBspNode
243{
244        friend class VspBspTree;
245public:
246        /** Standard contructor taking split plane as argument.
247        */
248        VspBspInterior(const Plane3 &plane);
249        ~VspBspInterior();
250        /** @return false since it is an interior node
251        */
252        bool IsLeaf() const;
253
254        VspBspNode *GetBack();
255        VspBspNode *GetFront();
256
257        Plane3 *GetPlane();
258
259        void ReplaceChildLink(VspBspNode *oldChild, VspBspNode *newChild);
260        void SetupChildLinks(VspBspNode *b, VspBspNode *f);
261
262        /** Splits polygons with respect to the split plane.
263                @param polys the polygons to be split. the polygons are consumed and
264                           distributed to the containers frontPolys, backPolys, coincident.
265                @param frontPolys returns the polygons in the front of the split plane
266                @param backPolys returns the polygons in the back of the split plane
267                @param coincident returns the polygons coincident to the split plane
268
269                @returns the number of splits   
270        */
271        int SplitPolygons(PolygonContainer &polys,
272                                          PolygonContainer &frontPolys,
273                                          PolygonContainer &backPolys,
274                                          PolygonContainer &coincident);
275
276        friend ostream &operator<<(ostream &s, const VspBspInterior &A)
277        {
278                return s << A.mPlane;
279        }
280
281protected:
282
283        /// Splitting plane corresponding to this node
284        Plane3 mPlane;
285        /// back node
286        VspBspNode *mBack;
287        /// front node
288        VspBspNode *mFront;
289};
290
291/** BSP leaf node implementation.
292*/
293class VspBspLeaf : public VspBspNode
294{
295        friend class VspBspTree;
296
297public:
298        VspBspLeaf();
299        VspBspLeaf(BspViewCell *viewCell);
300        VspBspLeaf(VspBspInterior *parent);
301        VspBspLeaf(VspBspInterior *parent, BspViewCell *viewCell);
302
303        /** @return true since it is an interior node
304        */
305        bool IsLeaf() const;
306       
307        /** Returns pointer of view cell.
308        */
309        BspViewCell *GetViewCell() const;
310
311        /** Sets pointer to view cell.
312        */
313        void SetViewCell(BspViewCell *viewCell);
314
315        /** Adds ray sample contributions to the PVS.
316                @param sampleContributions the number contributions of the samples
317                @param contributingSampels the number of contributing rays
318               
319        */
320        void AddToPvs(const RayInfoContainer &rays,
321                                  int &sampleContributions,
322                                  int &contributingSamples,
323                                  bool storeLeavesWithRays = false);
324
325protected:
326
327        /// if NULL this does not correspond to feasible viewcell
328        BspViewCell *mViewCell;
329};
330
331/** Implementation of the view cell BSP tree.
332*/
333class VspBspTree
334{
335public:
336       
337        /** Additional data which is passed down the BSP tree during traversal.
338        */
339        struct VspBspTraversalData
340        { 
341                /// the current node
342                VspBspNode *mNode;
343                /// polygonal data for splitting
344                PolygonContainer *mPolygons;
345                /// current depth
346                int mDepth;
347                /// the view cell associated with this subdivsion
348                ViewCell *mViewCell;
349                /// rays piercing this node
350                RayInfoContainer *mRays;
351                /// area of current node
352                float mArea;
353                /// geometry of current node induced by split planes
354                VspBspNodeGeometry *mGeometry;
355
356                /// pvs size
357                int mPvs;
358               
359                /** Returns average ray contribution.
360                */
361                float GetAvgRayContribution() const
362                {
363                        return (float)mPvs / ((float)mRays->size() + Limits::Small);
364                }
365
366
367                VspBspTraversalData():
368                mNode(NULL),
369                mPolygons(NULL),
370                mDepth(0),
371                mViewCell(NULL),
372                mRays(NULL),
373                mPvs(0),
374                mArea(0.0),
375                mGeometry(NULL)
376                {}
377               
378                VspBspTraversalData(VspBspNode *node,
379                                                 PolygonContainer *polys,
380                                                 const int depth,
381                                                 ViewCell *viewCell,
382                                                 RayInfoContainer *rays,
383                                                 int pvs,
384                                                 float area,
385                                                 VspBspNodeGeometry *cell):
386                mNode(node),
387                mPolygons(polys),
388                mDepth(depth),
389                mViewCell(viewCell),
390                mRays(rays),
391                mPvs(pvs),
392                mArea(area),
393                mGeometry(cell)
394                {}
395    };
396       
397        typedef std::stack<VspBspTraversalData> VspBspTraversalStack;
398
399        /** Default constructor creating an empty tree.
400                @param viewCell view cell corresponding to unbounded space
401        */
402        VspBspTree(BspViewCell *viewCell);
403
404        ~VspBspTree();
405
406        const VspBspTreeStatistics &GetStatistics() const;
407 
408
409        /** Constructs the tree from a given set of rays.
410                @param sampleRays the set of sample rays the construction is based on
411                @param viewCells if not NULL, new view cells are
412                created in the leafs and stored in the conatainer
413        */
414        void Construct(const VssRayContainer &sampleRays);
415
416        /** Returns list of BSP leaves.
417        */
418        void CollectLeaves(vector<VspBspLeaf *> &leaves) const;
419
420        /** Returns box which bounds the whole tree.
421        */
422        AxisAlignedBox3 GetBoundingBox()const;
423
424        /** Returns root of BSP tree.
425        */
426        VspBspNode *GetRoot() const;
427
428        /** Exports VspBsp tree to file.
429        */
430        bool Export(const string filename);
431
432        /** Collects the leaf view cells of the tree
433                @param viewCells returns the view cells
434        */
435        void CollectViewCells(ViewCellContainer &viewCells) const;
436
437        /** A ray is cast possible intersecting the tree.
438                @param the ray that is cast.
439                @returns the number of intersections with objects stored in the tree.
440        */
441        int CastRay(Ray &ray);
442
443        /** Set to true if new view cells shall be generated in each leaf.
444        */
445        void SetGenerateViewCells(int generateViewCells);
446
447        /// bsp tree construction types
448        enum {FROM_INPUT_VIEW_CELLS, FROM_SCENE_GEOMETRY, FROM_SAMPLES};
449
450        /** Returns statistics.
451        */
452        VspBspTreeStatistics &GetStat();
453
454        /** finds neighbouring leaves of this tree node.
455        */
456        int FindNeighbors(VspBspNode *n, vector<VspBspLeaf *> &neighbors,
457                                          const bool onlyUnmailed) const;
458
459        /** Constructs geometry associated with the half space intersections
460                leading to this node.
461        */
462        void ConstructGeometry(VspBspNode *n, PolygonContainer &cell) const;
463
464        /** Construct geometry and stores it in a geometry node container.
465        */
466        void ConstructGeometry(VspBspNode *n, VspBspNodeGeometry &cell) const;
467
468        /** Returns random leaf of BSP tree.
469                @param halfspace defines the halfspace from which the leaf is taken.
470        */
471        VspBspLeaf *GetRandomLeaf(const Plane3 &halfspace);
472
473        /** Returns random leaf of BSP tree.
474                @param onlyUnmailed if only unmailed leaves should be returned.
475        */
476        VspBspLeaf *GetRandomLeaf(const bool onlyUnmailed = false);
477
478        /** Returns true if merge criteria are reached.
479        */
480    bool ShouldMerge(VspBspLeaf *front, VspBspLeaf *back) const;
481
482        /** Merges view cells based on some criteria
483            E.g., empty view cells can pe purged, view cells which have
484                a very similar PVS can be merged to one larger view cell.
485
486                @returns true if merge was successful.
487        */
488        bool MergeViewCells(VspBspLeaf *front, VspBspLeaf *back) const;
489
490        /** Traverses tree and counts all view cells as well as their PVS size.
491        */
492        void EvaluateViewCellsStats(VspBspViewCellsStatistics &stat) const;
493
494
495protected:
496
497        // --------------------------------------------------------------
498        // For sorting objects
499        // --------------------------------------------------------------
500        struct SortableEntry
501        {
502                enum {POLY_MIN, POLY_MAX};
503   
504                int type;
505                float value;
506                Polygon3 *poly;
507                SortableEntry() {}
508                SortableEntry(const int t, const float v, Polygon3 *poly):
509                type(t), value(v), poly(poly) {}
510               
511                bool operator<(const SortableEntry &b) const
512                {
513                        return value < b.value;
514                } 
515        };
516
517        /** Evaluates tree stats in the BSP tree leafs.
518        */
519        void EvaluateLeafStats(const VspBspTraversalData &data);
520
521        /** Subdivides node with respect to the traversal data.
522            @param tStack current traversal stack
523                @param tData traversal data also holding node to be subdivided
524                @returns new root of the subtree
525        */
526        VspBspNode *Subdivide(VspBspTraversalStack &tStack, VspBspTraversalData &tData);
527
528        /** Constructs the tree from the given list of polygons and rays.
529                @param polys stores set of polygons on which subdivision may be based
530                @param rays storesset of rays on which subdivision may be based
531        */
532        void Construct(PolygonContainer *polys, RayInfoContainer *rays);
533
534        /** Selects the best possible splitting plane.
535                @param leaf the leaf to be split
536                @param polys the polygon list on which the split decition is based
537                @param rays ray container on which selection may be based
538                @note the polygons can be reordered in the process
539                @returns the split plane
540        */
541        Plane3 SelectPlane(VspBspLeaf *leaf,
542                                           VspBspTraversalData &data);
543
544       
545        /** Strategies where the effect of the split plane is tested
546            on all input rays.
547
548                @returns the cost of the candidate split plane
549        */
550        float SplitPlaneCost(const Plane3 &candidatePlane,
551                                                 const VspBspTraversalData &data);
552
553
554
555        /** Subdivide leaf.
556                @param leaf the leaf to be subdivided
557               
558                @param polys the polygons to be split
559                @param frontPolys returns the polygons in front of the split plane
560                @param backPolys returns the polygons in the back of the split plane
561               
562                @param rays the polygons to be filtered
563                @param frontRays returns the polygons in front of the split plane
564                @param backRays returns the polygons in the back of the split plane
565
566                @returns the root of the subdivision
567        */
568
569        VspBspInterior *SubdivideNode(VspBspTraversalData &tData,
570                                                           VspBspTraversalData &frontData,
571                                                           VspBspTraversalData &backData,
572                                                           PolygonContainer &coincident);
573
574        /** Selects the split plane in order to construct a tree with
575                certain characteristics (e.g., balanced tree, least splits,
576                2.5d aligned)
577                @param polygons container of polygons
578                @param rays bundle of rays on which the split can be based
579        */
580        Plane3 SelectPlaneHeuristics(VspBspLeaf *leaf,
581                                                                 VspBspTraversalData &data);
582
583        /** Extracts the meshes of the objects and adds them to polygons.
584                Adds object aabb to the aabb of the tree.
585                @param maxPolys the maximal number of objects to be stored as polygons
586                @returns the number of polygons
587        */
588        int AddToPolygonSoup(const ObjectContainer &objects,
589                                                 PolygonContainer &polys,
590                                                 int maxObjects = 0);
591
592        /** Extracts the meshes of the view cells and and adds them to polygons.
593                Adds view cell aabb to the aabb of the tree.
594                @param maxPolys the maximal number of objects to be stored as polygons
595                @returns the number of polygons
596        */
597        int AddToPolygonSoup(const ViewCellContainer &viewCells,
598                                                 PolygonContainer &polys,
599                                                 int maxObjects = 0);
600
601        /** Extract polygons of this mesh and add to polygon container.
602                @param mesh the mesh that drives the polygon construction
603                @param parent the parent intersectable this polygon is constructed from
604                @returns number of polygons
605        */
606        int AddMeshToPolygons(Mesh *mesh, PolygonContainer &polys, MeshInstance *parent);
607
608        /** returns next candidate index and reorders polygons so no candidate is chosen two times
609                @param the current candidate index
610                @param max the range of candidates
611        */
612        int GetNextCandidateIdx(int currentIdx, PolygonContainer &polys);
613       
614        /** Computes best cost ratio for the suface area heuristics for axis aligned
615                splits. This heuristics minimizes the cost for ray traversal.
616                @param polys the polygons guiding the ratio computation
617                @param box the bounding box of the leaf
618                @param axis the current split axis
619                @param position returns the split position
620                @param objectsBack the number of objects in the back of the split plane
621                @param objectsFront the number of objects in the front of the split plane
622        */
623        float BestCostRatio(const PolygonContainer &polys,
624                                                const AxisAlignedBox3 &box,
625                                                const int axis,
626                                                float &position,
627                                                int &objectsBack,
628                                                int &objectsFront) const;
629       
630        /** Sorts split candidates for surface area heuristics for axis aligned splits.
631                @param polys the input for choosing split candidates
632                @param axis the current split axis
633                @param splitCandidates returns sorted list of split candidates
634        */
635        void SortSplitCandidates(const PolygonContainer &polys,
636                                                         const int axis,
637                                                         vector<SortableEntry> &splitCandidates) const;
638
639        /** Selects an axis aligned split plane.
640                Returns true if split is valied
641        */
642        bool SelectAxisAlignedPlane(Plane3 &plane, const PolygonContainer &polys) const;
643
644        /** Bounds ray and returns minT and maxT.
645                @returns true if ray hits BSP tree bounding box
646        */
647        bool BoundRay(const Ray &ray, float &minT, float &maxT) const;
648
649        /** Subdivides the rays into front and back rays according to the split plane.
650               
651                @param plane the split plane
652                @param rays contains the rays to be split. The rays are
653                           distributed into front and back rays.
654                @param frontRays returns rays on the front side of the plane
655                @param backRays returns rays on the back side of the plane
656               
657                @returns the number of splits
658        */
659        int SplitRays(const Plane3 &plane,
660                                  RayInfoContainer &rays,
661                              RayInfoContainer &frontRays,
662                                  RayInfoContainer &backRays);
663
664
665        /** Extracts the split planes representing the space bounded by node n.
666        */
667        void ExtractHalfSpaces(VspBspNode *n, vector<Plane3> &halfSpaces) const;
668
669        /** Adds the object to the pvs of the front and back leaf with a given classification.
670
671                @param obj the object to be added
672                @param cf the ray classification regarding the split plane
673                @param frontPvs returns the PVS of the front partition
674                @param backPvs returns the PVS of the back partition
675       
676        */
677        void AddObjToPvs(Intersectable *obj, const int cf, int &frontPvs, int &backPvs) const;
678       
679        /** Computes PVS size induced by the rays.
680        */
681        int ComputePvsSize(const RayInfoContainer &rays) const;
682
683        /** Returns true if tree can be terminated.
684        */
685        inline bool TerminationCriteriaMet(const VspBspTraversalData &data) const;
686
687        /** Computes accumulated ray lenght of this rays.
688        */
689        float AccumulatedRayLength(const RayInfoContainer &rays) const;
690
691
692
693        /// Pointer to the root of the tree
694        VspBspNode *mRoot;
695               
696        VspBspTreeStatistics mStat;
697
698        /// Strategies for choosing next split plane.
699        enum {NO_STRATEGY = 0,
700                  RANDOM_POLYGON = 1,
701                  AXIS_ALIGNED = 2,
702                  LEAST_SPLITS = 4,
703                  BALANCED_POLYS = 8,
704                  BALANCED_VIEW_CELLS = 16,
705                  LARGEST_POLY_AREA = 32,
706                  VERTICAL_AXIS = 64,
707                  BLOCKED_RAYS = 128,
708                  LEAST_RAY_SPLITS = 256,
709                  BALANCED_RAYS = 512,
710                  PVS = 1024
711                };
712
713        /// box around the whole view domain
714        AxisAlignedBox3 mBox;
715
716        /// view cell corresponding to unbounded space
717        BspViewCell *mRootCell;
718
719        /// minimal number of rays before subdivision termination
720        int mTermMinRays;
721        /// maximal possible depth
722        int mTermMaxDepth;
723        /// mininum area
724        float mTermMinArea;
725        /// mininum PVS
726        int mTermMinPvs;
727
728        /// minimal number of rays for axis aligned split
729        int mTermMinRaysForAxisAligned;
730        /// minimal number of objects for axis aligned split
731        int mTermMinObjectsForAxisAligned;
732        /// maximal contribution per ray
733        float mTermMaxRayContribution;
734        /// minimal accumulated ray length
735        float mTermMinAccRayLength;
736
737
738        /// strategy to get the best split plane
739        int mSplitPlaneStrategy;
740        /// number of candidates evaluated for the next split plane
741        int mMaxPolyCandidates;
742        /// number of candidates for split planes evaluated using the rays
743        int mMaxRayCandidates;
744       
745        float mCtDivCi;
746
747        /// if intersected leaves should be stored with a sample
748        bool mStoreLeavesWithRays;
749
750        /// axis aligned split criteria
751        float mAaCtDivCi;
752        float mSplitBorder;
753        float mMaxCostRatio;
754
755        // factors guiding the split plane heuristics
756        float mBlockedRaysFactor;
757        float mLeastRaySplitsFactor;
758        float mBalancedRaysFactor;
759        float mPvsFactor;
760        float mLeastSplitsFactor;
761
762        //-- thresholds used for view cells merge
763        int mMinPvsDif;
764        int mMinPvs;
765        int mMaxPvs;
766
767        /// if area or accumulated ray lenght should be used for PVS heuristics
768        bool mPvsUseArea;
769
770private:
771       
772        static const float sLeastRaySplitsTable[5];
773        /** Evaluates split plane classification with respect to the plane's
774                contribution for balanced rays.
775        */
776        static const float sBalancedRaysTable[5];
777
778        /// Generates unique ids for PVS criterium
779        static void GenerateUniqueIdsForPvs();
780
781        //-- unique ids for PVS criterium
782        static int sFrontId;
783        static int sBackId;
784        static int sFrontAndBackId;
785};
786
787#endif
Note: See TracBrowser for help on using the repository browser.