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

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