source: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/Bvh.h @ 3243

Revision 3243, 20.1 KB checked in by mattausch, 15 years ago (diff)
Line 
1// This file has been written by Jiri Bittner, October 2006
2
3#ifndef __BVH_H
4#define __BVH_H
5
6#include "common.h"
7#include "Vector3.h"
8#include "AxisAlignedBox3.h"
9
10
11
12namespace CHCDemoEngine
13{
14
15// the number of visibility states
16#define NUM_STATES 2
17
18////////
19//-- Forward declarations
20
21class SceneEntity;
22class Camera;
23class RenderState;
24
25
26/** A node in the bv hierarchy.
27*/
28class BvhNode
29{
30        friend class Bvh;
31        friend class BvhLoader;
32        friend class mygreaterdistance;
33
34public:
35
36        /** visibility related options
37        */
38        struct VisibilityInfo
39        {
40                VisibilityInfo() { Reset(); }           
41                /** Reset the visibility info.
42                */
43                void Reset();
44
45                /// if the node is visible
46                bool mIsVisible;
47                /// frame id until this node is assumed to stay visible
48                int mAssumedVisibleFrameId;
49                /// the frame when this node was last touched during traversal
50                int mLastVisitedFrame;
51                /// #times this node was invisible (only valid if the node actually is invisible)
52                int mTimesInvisible;
53                /// if the node is view frustum culled
54                bool mIsFrustumCulled;
55                /// if the node is newly processed with no prior history available
56                bool mIsNew;
57                /// the frame this node was last queried
58                int mLastQueriedFrame;
59        };
60
61        /** Constructor taking the parent node.
62        */
63        BvhNode(BvhNode *parent);
64        /** Virtual destructor doing nothing.
65        */
66        virtual ~BvhNode();
67        /** Reset the status of this node.
68        */
69        virtual void ResetVisibility();
70        /** Returns true if this node is a leaf.
71        */
72        virtual bool IsLeaf() const = 0;
73        /** Depth of this node in the tree.
74        */
75        inline int GetDepth() const;
76        /** Returns parent of this bvh node, NULL if it is root.
77        */
78        inline BvhNode *GetParent();
79        /** Number of leaves in the subtree induced by this node.
80        */
81        inline int GetNumLeaves() const;
82        /** Returns true if this node is a "virtual" leaf,
83                i.e., the node is handled as a leaf during traversal.
84        */
85        inline bool IsVirtualLeaf() const;
86        /** Returns the stored distance to the near plane.
87        */
88        inline float GetDistance() const;
89
90
91        ////////////////
92        //-- visibility culling related functions
93
94        inline int GetLastVisitedFrame() const;
95
96        inline void SetLastVisitedFrame(int lastVisited);
97        /** If this node is considered visible.
98        */
99        inline bool IsVisible() const;
100        /** Set visibility flag of the node.
101        */
102        inline void SetVisible(bool visible);
103        /** The frame id until this node is assumed visible
104        */
105        inline void SetAssumedVisibleFrameId(int t);
106        /** See set.
107        */
108        inline int GetAssumedVisibleFrameId() const;
109        /** Increases the #times this node was
110                successfully tested invisible.
111        */
112        inline void IncTimesTestedInvisible();
113       
114        inline int GetTimesTestedInvisible() const;
115        inline void SetTimesTestedInvisible(int t);
116       
117        inline int GetTurnedVisibleFrame() const;
118        inline void SetTurnedVisibleFrame(int turnedVisibleFrame);
119
120        inline int GetLastQueriedFrame() const;
121        inline void SetLastQueriedFrame(int lastTested);
122       
123        inline bool IsViewFrustumCulled() const;
124        inline void SetViewFrustumCulled(bool frustumCulled);
125
126        inline bool IsNew() const;
127        inline void SetIsNew(bool isNew);
128
129
130        /** Returns the bounding box of this node.
131        */
132        inline const AxisAlignedBox3 &GetBox() const;
133        /** Return index of this node.
134        */
135        inline int GetId() const;
136        /** See get
137        */
138        inline void SetId(int id);
139       
140
141        //////////
142        //-- rendering
143       
144        /** Returns the frame in which this node was last rendered.
145        */
146        inline int GetLastRenderedFrame() const;
147        /** See get.
148        */
149        inline void SetLastRenderedFrame(int lastRenderedFrame);
150        /** Does this node contain renderable geometry?
151        */
152        inline bool Empty() const;
153        /** Counts #geometry stored in the subtree.
154        */
155        inline int CountPrimitives() const;
156        /** This function is important in case you have more than one
157                view position within a frame (e.g., camera view and shadow view for
158                shadow mapping), because each camera needs its own state in
159                order to not break temporal coherency.
160        */
161        inline static void SetCurrentState(int _state);
162
163
164protected:
165
166        /// the depth of this node
167        unsigned char mDepth;
168        /// the split axis
169        char mAxis;
170        /// the parent node
171        BvhNode *mParent;
172
173
174        //////////////
175        //-- members definig the current visibility state (one state per camera)
176
177        /// the currently used state
178        static int sCurrentState;
179
180        /// stores the visibility related info
181        VisibilityInfo mVisibility[NUM_STATES];
182        /// when the node was last rendered
183        int mLastRenderedFrame[NUM_STATES];
184
185
186        ///////////////
187        //-- members that help to speed up view frustum culling
188
189        /// masks out planes of the frustum that do not have to be tested against
190        int mPlaneMask[NUM_STATES];
191        /// the plane that is usually responsible for culling this node.
192        /** if our educated guess was right, we save up to 5 comparisons.
193        */
194        int mPreferredPlane[NUM_STATES];
195
196
197        ////////////////////
198
199
200        /// #leaves under this node
201        int mNumLeaves;
202        /// Area of this node
203        float mArea;
204        /// distance to the camera
205        float mDistance;
206        /// the index of this node
207        unsigned int mId;
208        /// the bounding box
209        AxisAlignedBox3 mBox;
210        /// if this node is a virtual leaf
211        bool mIsVirtualLeaf;
212        /** This marks the maximal depth where a virtual leaf can be defined.
213            From this point on it makes no sense to traverse down further, as all
214                nodes below contain the same geometry, so no further refinement of visibility
215                can be archieved. All nodes below this point can merely used to define the
216                tighter bounds.
217        */
218        bool mIsMaxDepthForVirtualLeaf;
219
220
221        ////////////
222        //-- rendering related options
223       
224        // Indices to first and last triangle in the triangle array
225        // assumes the triangle are placed in continuous chunk of memory
226        // however this need not be a global array!
227       
228        /// the index of the first triangle
229        int mFirst;
230        /// the index of the last triangle
231        int mLast;
232
233
234        ////////////////
235        //-- rendering related options
236
237        /// the bounding boxes of the test nodes are queries instead of the actual node
238        int mTestNodesIdx;
239        /// the number of these test nodes
240        int mNumTestNodes;
241        /// used for efficient element array rendering
242        int mIndicesPtr;
243};
244
245
246
247/////////////////
248//-- public inline functions
249
250
251int BvhNode::GetLastVisitedFrame() const
252{
253        return mVisibility[sCurrentState].mLastVisitedFrame;
254}
255
256
257void BvhNode::SetLastVisitedFrame(const int lastVisited)
258{
259        mVisibility[sCurrentState].mLastVisitedFrame = lastVisited;
260}
261
262
263bool BvhNode::IsVisible() const
264{
265        return mVisibility[sCurrentState].mIsVisible;
266}
267
268
269void BvhNode::SetVisible(bool visible)
270{
271        mVisibility[sCurrentState].mIsVisible = visible;
272}
273
274
275void BvhNode::IncTimesTestedInvisible()
276{
277        ++ mVisibility[sCurrentState].mTimesInvisible;
278}
279
280
281int BvhNode::GetTimesTestedInvisible() const
282{
283        return mVisibility[sCurrentState].mTimesInvisible;
284}
285
286
287void BvhNode::SetTimesTestedInvisible(int t)
288{
289        mVisibility[sCurrentState].mTimesInvisible = t;
290}
291
292
293bool BvhNode::IsViewFrustumCulled() const
294{
295        return mVisibility[sCurrentState].mIsFrustumCulled;
296}
297
298
299void BvhNode::SetViewFrustumCulled(bool frustumCulled)
300{
301        mVisibility[sCurrentState].mIsFrustumCulled = frustumCulled;
302}
303
304
305bool BvhNode::IsNew() const
306{
307        return mVisibility[sCurrentState].mIsNew;
308}
309
310
311void BvhNode::SetIsNew(bool isNew)
312{
313        mVisibility[sCurrentState].mIsNew = isNew;
314}
315
316
317void BvhNode::SetAssumedVisibleFrameId(int t)
318{
319        mVisibility[sCurrentState].mAssumedVisibleFrameId = t;
320}
321
322
323int BvhNode::GetAssumedVisibleFrameId() const
324{
325        return mVisibility[sCurrentState].mAssumedVisibleFrameId;
326}
327
328
329int BvhNode::GetLastQueriedFrame() const
330{
331        return mVisibility[sCurrentState].mLastQueriedFrame;
332}
333
334
335void BvhNode::SetLastQueriedFrame(int lastTested)
336{
337        mVisibility[sCurrentState].mLastQueriedFrame = lastTested;
338}
339
340
341int BvhNode::GetLastRenderedFrame() const
342{
343        return mLastRenderedFrame[sCurrentState];
344}
345       
346
347void BvhNode::SetLastRenderedFrame(int lastRenderedFrame)
348{
349        mLastRenderedFrame[sCurrentState] = lastRenderedFrame;
350}
351       
352       
353bool BvhNode::Empty() const
354{
355        return (mFirst == -1);
356}
357
358
359int BvhNode::CountPrimitives() const
360{
361        return mLast - mFirst + 1;
362}
363
364int BvhNode::GetDepth() const
365{
366        return mDepth;
367}
368
369
370BvhNode *BvhNode::GetParent()
371{
372        return mParent;
373}
374
375
376int BvhNode::GetNumLeaves() const
377{
378        return mNumLeaves;
379}
380
381
382bool BvhNode::IsVirtualLeaf() const
383{
384        return mIsVirtualLeaf;
385}
386
387
388float BvhNode::GetDistance() const
389{
390        return mDistance;
391}
392
393       
394const AxisAlignedBox3 &BvhNode::GetBox() const
395{
396        return mBox;
397}
398
399
400int BvhNode::GetId() const
401{
402        return mId;
403}
404
405
406void BvhNode::SetId(int id)
407{
408        mId = id;
409}
410
411
412void BvhNode::SetCurrentState(int _state)
413{
414        sCurrentState = _state;
415}
416
417
418/** Internal node of the bv hierarchy.
419*/
420class BvhInterior: public BvhNode
421{
422        friend class Bvh;
423        friend class BvhLoader;
424
425public:
426
427        BvhInterior(BvhNode *parent): mBack(NULL), mFront(NULL), BvhNode(parent)
428        {}
429        virtual bool IsLeaf() const { return false; }
430        /** Back child.
431        */
432        inline BvhNode *GetBack() { return mBack; }
433        /** Front child.
434        */
435        inline BvhNode *GetFront() { return mFront; }
436        /** Recursivly delete hierarchy.
437        */
438        virtual ~BvhInterior();
439
440
441protected:
442
443        BvhNode *mBack;
444        BvhNode *mFront;
445};
446
447
448class BvhLeaf: public BvhNode
449{
450        friend class Bvh;
451        friend class BvhLoader;
452
453public:
454
455        BvhLeaf(BvhNode *parent): BvhNode(parent)
456        {}
457
458        ~BvhLeaf();
459
460        virtual bool IsLeaf() const { return true; }
461};
462
463
464/**     This class implements the compare operator for the priority queue.
465        a lower distance has a higher value in the queue
466*/
467class GtDistance
468{
469public:
470        bool operator() (BvhNode *v1, BvhNode *v2) const
471    {
472                return (v1->GetDistance() > v2->GetDistance());
473    }
474};
475
476typedef std::priority_queue<BvhNode *, std::vector<BvhNode *>, GtDistance> TraversalQueue;
477
478
479/** Class representing a bounding volume hierarchy.
480*/
481class Bvh
482{
483        friend class BvhLoader;
484
485        /** Bvh properties
486        */
487        struct BvhStats
488        {
489                BvhStats() { Reset(); }
490
491                void Reset()
492                {
493                        mInteriorSA = .0f;
494                        mLeafSA = .0f;
495                        mInteriorVol = .0f;
496                        mLeafVol = .0f;
497                        mTriangleRatio = .0f;
498                        mGeometryRatio = .0f;
499
500                        mTriangles = 0;
501                        mLeaves = 0;
502                }
503
504                ///////////////////
505
506                float mInteriorSA;
507                float mLeafSA;
508                float mInteriorVol;
509                float mLeafVol;
510               
511                float mTriangleRatio;
512                float mGeometryRatio;
513
514                int mTriangles;
515                int mLeaves;
516        };
517
518public:
519
520        /** Destructor.
521        */
522        ~Bvh();
523        /** Returns number of bvh nodes.
524        */
525        inline int GetNumNodes() const;
526        /** Returns number of bvh leaves.
527        */
528        inline int GetNumLeaves() const;
529        /** Returns number of 'virtual' nodes in the hierarchy, i.e.
530                the number of nodes actually used for traversal.
531        */
532        inline int GetNumVirtualNodes() const;
533        /** Returns number of bvh leaves.
534        */
535        inline int GetNumVirtualLeaves() const;
536        /** Returns root node of the bvh.
537        */
538        inline BvhNode *GetRoot();
539        /** Returns the static root node of the bvh.
540        */
541        inline BvhNode *GetStaticRoot();
542        /** Returns the dynamic root node of the bvh.
543        */
544        inline BvhNode *GetDynamicRoot();
545        /** Returns the bounding box of this bvh.
546        */
547        inline const AxisAlignedBox3 &GetBox() const;
548        /** Returns true if the current bvh node intersects the near plane.
549        */
550        bool IntersectsNearPlane(BvhNode *node) const;
551
552
553        ///////////////
554        //-- functions collecting nodes based on some criteria
555
556        /** Collect all child nodes in a given depth from the specified node.
557        */
558        void CollectNodes(BvhNode *node, BvhNodeContainer &nodes, int depth);
559        void CollectNodes(BvhNode *node, BvhNodeContainer &nodes);
560        /** Collect the "physical" leaves of the hierarchy
561        */
562        void CollectLeaves(BvhNode *node, BvhLeafContainer &leaves);
563        /** Collect only the virtual leaves (can be anywhere in the hierarchy).
564        */
565        void CollectVirtualLeaves(BvhNode *node, BvhNodeContainer &leaves);
566
567
568        //////////////////////
569
570        /** Returns geometry by reference (faster).
571        */
572        SceneEntity **GetGeometry(BvhNode *node, int &size) const;
573
574
575        /////////////
576        //-- Rendering related options
577
578        /** Renders the bounds of this node
579            (the box of the node or the tigher bounds of some subnodes).
580        */
581        void RenderBounds(BvhNode *node, RenderState *state, bool useTightBounds);
582        /** Renders bounding boxes of the collection of nodes.
583                @returns #rendered boxes
584        */
585        int RenderBounds(const BvhNodeContainer &nodes, RenderState *state, bool useTightBounds);
586       
587
588
589        //////////////
590        //-- Traversal related options
591
592        /** Pulls up visible classification.
593        */
594        void MakeParentsVisible(BvhNode *node);
595        /** Does the view frustum culling for this node with respect to the previous culls
596                @returns: 0 if completely outside, 1 if completely inside, -1 if intersecting (partly inside),
597        */
598        int     IsWithinViewFrustum(BvhNode *node);
599        /** Sets frame dependent values
600        */
601        void InitFrame(Camera *camera, RenderState *state);
602        /** Stores the orthogonal distance from the viewpoint to a point on the node.
603                We choose the the nearest bounding box vertex .
604                Note that negative values can appear because culling is done only afterwards
605        */
606        void UpdateDistance(BvhNode *node) const;
607        /** Returns the maximum distance from the near plane to this node.
608        */
609        float CalcMaxDistance(BvhNode *node) const;
610        /** Pulls up the last visited classification in the bvh.
611        */
612        void PullUpLastVisited(BvhNode *node, int frameId) const;
613        /** Resets the node classifications in the tree.
614        */
615        void ResetNodeClassifications();
616        /** Count triangles the node contains.
617        */
618        int CountTriangles(BvhNode *node) const;
619        /** Returns area of the the node.
620        */
621        float GetArea(BvhNode *node) const;
622        /** Compute unique ids for the nodes.
623        */
624        void ComputeIds();
625        /** Assign virtual leaves based on specified number of triangles per leaf.
626                That means that we try to set the leaves at a point where we
627                have less than numTriangles triangles within this leaf and beyond.
628
629                Virtual leaves are nodes that are determined to be the leaves
630                of the hierarchy during render traversal. These nodes are not necessarily
631                the same as the real leaves of the hierarchy and can be anywhere
632                in the hierarchy.
633                Please refer to the article for more info about virtual leaves
634        */
635        void SetVirtualLeaves(int numTriangles);
636       
637
638        ////////////
639        //-- functions influencing the tightness of the bounds that are used for testing
640
641
642        /** Sets maximal depth for taking the bounding boxes to test the
643                visibility of a node.
644                Deeper level means that the bounds adapt more to the geometry but
645                also that more boxes are rendered
646        */
647        void SetMaxDepthForTestingChildren(int maxDepth);
648        /** The ratio of area between node and subnodes where
649                testing the subnodes as proxy is still considered feasable
650        */
651        void SetAreaRatioThresholdForTestingChildren(float ratio);
652
653
654        ////////////////////////////
655
656        /** Returns stats.
657        */
658        const BvhStats &GetBvhStats() const { return mBvhStats; }
659        /** Render wireframe bvh for visualization purpose.
660        */
661        void RenderBoundsForViz(BvhNode *node, RenderState *state, bool useTightBounds);
662
663
664protected:
665
666        ////////////////////
667
668        /** protected constructor: do nothing.
669        */
670        Bvh();
671        /** Protected constructor taking scene geometry into account
672                Sets the static and dynamic objects for the hierarchy.
673        */
674        const Bvh(const SceneEntityContainer &staticEntities,
675                      const SceneEntityContainer &dynamicEntities);
676        /** Protected constructor taking scene geometry into account
677                Sets the static and dynamic objects for the hierarchy.
678        */
679        const Bvh(const SceneEntityContainer &staticEntities,
680                      const SceneEntityContainer &dynamicEntities,
681                          int maxDepthForTestingChildren);
682        /** Called by the constructor. Initializes important members.
683        */
684        void Init();
685
686        /////////////
687        /** Traverse hierarchy and compute stats.
688        */
689        void ComputeBvhStats(BvhNode *root, BvhStats &bvhStats);
690        /** Output the bvh statistics.
691        */
692        void PrintBvhStats(const BvhStats &bvhStats) const;
693
694
695        //////////
696        //-- Helper methods for bounding box rendering in immediate and vbo mode.
697       
698        void PrepareVertices();
699        /** Prepare nodes for vbo rendering.
700        */
701        int PrepareBoundsWithDrawArrays(const BvhNodeContainer &nodes);
702        /** Render the nodes from the vbo prepared previously.
703        */
704        void RenderBoundsWithDrawArrays(int numNodes, RenderState *state);
705
706        /** Create the indices that each node needs to use vbo rendering.
707        */
708        void CreateIndices();
709        /** Create the list of nodes whose bounding boxes are tested instead of the
710                bounding box of the node itself.
711        */
712        bool CreateNodeRenderList(BvhNode *node);
713        /** Recursivly updates indices so we can
714                render also interior nodes without traversing hierarchy
715        */
716        void UpdateInteriors(BvhNode *node);
717        /** Recomputes the boundaries of the nodes.
718            This function is always called if some boundary options are changed.
719        */
720        void RecomputeBounds();
721        /** Does some postprocessing on the nodes.
722        */
723        void PostProcess();
724        /** Helper method that updates the number of leaves in the subtree under
725                this node.
726        */
727        void UpdateNumLeaves(BvhNode *node) const;
728        /** Frustum tests the ith plane.
729        */
730        inline bool TestPlane(BvhNode *node, int i, bool &bIntersect);
731        /** Renders a bounding box in immediate mode.
732        */
733        void RenderBoundingBoxImmediate(const AxisAlignedBox3 &box);
734
735
736        /////////////////////////////
737        //-- functions used to construct the dynamic part of the hierarchy
738
739        int SortTriangles(BvhLeaf *leaf,
740                              int axis,
741                                          float position);
742
743        int SortTrianglesSpatialMedian(BvhLeaf *leaf,
744                                           int axis);
745
746        BvhNode *SubdivideLeaf(BvhLeaf *leaf,
747                                   int parentAxis);
748        /** Recompute the dynamic branch of the hierarchy.
749        */
750        void CreateDynamicBranch();
751
752        void UpdateDynamicBranch(BvhNode *node);
753
754        inline bool TerminationCriteriaMet(BvhLeaf *leaf) const;
755
756        void ComputeMaxDepthForVirtualLeaves();
757
758        void CreateRoot();
759
760        void UpdateDynamicBounds(RenderState *state);
761
762
763        ////////////////////////
764       
765        /// the bounding box of the bvh
766        AxisAlignedBox3 mBox;
767        /// the root of the hierarchy
768        BvhInterior *mRoot;
769        /// the root of static part of the the hierarchy
770        BvhNode *mStaticRoot;
771        /// the root of dynamic part of the the hierarchy
772        BvhNode *mDynamicRoot;
773        /// pointers to the geometry associated with this node
774        SceneEntity **mGeometry;
775        /// #of entities
776        size_t mGeometrySize;
777        /// #of static entities
778        size_t mStaticGeometrySize;
779        /// #of dynamic entities
780        size_t mDynamicGeometrySize;
781
782
783        ////////////////
784        //-- tigher bounds termination criteria
785
786        /** maximal depth from which children are fetched for
787                testing instead of the current node
788        */
789        int mMaxDepthForTestingChildren;
790        /// threshold for computing tighter bounds
791        float mAreaRatioThreshold;
792       
793       
794        ////////////////
795        //-- statistics
796
797        BvhStats mBvhStats;
798        /// the overall number of nodes
799        int mNumNodes;
800        /// the number of "virtual" (=actually used) nodes
801        int mNumVirtualNodes;
802
803
804        ////////////
805        //-- rendering stuff
806
807        /// these proxy nodes are tested instead of the current node
808        BvhNodeContainer mTestNodes;
809        /// the indices used for vbo index buffering
810        unsigned int *mTestIndices;
811        /// a pointer to the end of the indices array
812        int mCurrentIndicesPtr;
813        /// the vbo id
814        unsigned int mVboId;
815        /// a vertex array used if working with indexed arrays (without vbo)
816        Vector3 *mVertices;
817        /// indices used for draw array rendering
818        unsigned int *mIndices;
819
820
821        ///////////
822        //-- termination criteria for dynamic branch
823
824        int mMaxDepthForDynamicBranch;
825
826        //SceneEntityContainer mDynamicEntities;
827};
828
829
830
831/////////////////
832//-- public inline functions
833
834
835int Bvh::GetNumNodes() const
836{
837        return mNumNodes;
838}
839
840
841int Bvh::GetNumLeaves() const
842{
843        return mNumNodes / 2 + 1;
844}
845
846
847int Bvh::GetNumVirtualNodes() const 
848{
849        return mNumVirtualNodes;
850}
851
852
853int Bvh::GetNumVirtualLeaves() const
854{
855        return mNumVirtualNodes / 2 + 1;
856}
857
858
859BvhNode *Bvh::GetRoot()
860{
861        return mRoot;
862}
863
864
865BvhNode *Bvh::GetDynamicRoot()
866{
867        return mDynamicRoot;
868}
869
870
871BvhNode *Bvh::GetStaticRoot()
872{
873        return mStaticRoot;
874}
875
876
877const AxisAlignedBox3 &Bvh::GetBox() const
878{
879        return mBox;
880}
881
882
883}
884
885#endif // __BVH_H
Note: See TracBrowser for help on using the repository browser.