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

Revision 3274, 20.7 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 nodes in this subtree
362        */
363        int CountNumNodes(BvhNode *node) const;
364        /** Counts the number of virtual nodes in this subtree
365        */
366        int CountNumVirtualNodes(BvhNode *node) const;
367
368        /** Returns number of bvh leaves.
369        */
370        inline int GetNumLeaves() const;
371        /** Returns number of 'virtual' nodes in the hierarchy, i.e.
372                the number of nodes actually used for traversal.
373        */
374        inline int GetNumVirtualNodes() const;
375        /** Returns number of bvh leaves.
376        */
377        inline int GetNumVirtualLeaves() const;
378        /** Returns root node of the bvh.
379        */
380        inline BvhNode *GetRoot();
381        /** Returns the static root node of the bvh.
382        */
383        inline BvhNode *GetStaticRoot();
384        /** Returns the dynamic root node of the bvh.
385        */
386        inline BvhNode *GetDynamicRoot();
387        /** Returns the bounding box of this bvh.
388        */
389        inline const AxisAlignedBox3 &GetBox() const;
390        /** Returns true if the current bvh node intersects the near plane.
391        */
392        bool IntersectsNearPlane(BvhNode *node) const;
393
394
395        ///////////////
396        //-- functions collecting nodes based on some criteria
397
398        /** Collect all child nodes in a given depth from the specified node.
399        */
400        void CollectNodes(BvhNode *node, BvhNodeContainer &nodes, int depth);
401        /** Collect all child nodes.
402        */
403        void CollectNodes(BvhNode *node, BvhNodeContainer &nodes);
404        /** Collect the "physical" leaves of the hierarchy
405        */
406        void CollectLeaves(BvhNode *node, BvhLeafContainer &leaves);
407        /** Collect only the virtual leaves (can be anywhere in the hierarchy).
408        */
409        void CollectVirtualLeaves(BvhNode *node, BvhNodeContainer &leaves);
410
411
412        //////////////////////
413
414        /** Returns geometry by reference (faster).
415        */
416        SceneEntity **GetGeometry(BvhNode *node, int &size) const;
417
418
419        /////////////
420        //-- Rendering related options
421
422        /** Renders the bounds of this node
423            (the box of the node or the tigher bounds of some subnodes).
424        */
425        void RenderBounds(BvhNode *node, RenderState *state, bool useTightBounds);
426        /** Renders bounding boxes of the collection of nodes.
427                @returns #rendered boxes
428        */
429        int RenderBounds(const BvhNodeContainer &nodes, RenderState *state, bool useTightBounds);
430       
431
432
433        //////////////
434        //-- Traversal related options
435
436        /** Pulls up visible classification.
437        */
438        void MakeParentsVisible(BvhNode *node);
439        /** Does the view frustum culling for this node with respect to the previous culls
440                @returns: 0 if completely outside, 1 if completely inside, -1 if intersecting (partly inside),
441        */
442        int     IsWithinViewFrustum(BvhNode *node);
443        /** Sets frame dependent values
444        */
445        void InitFrame(Camera *camera, RenderState *state);
446        /** Stores the orthogonal distance from the viewpoint to a point on the node.
447                We choose the the nearest bounding box vertex .
448                Note that negative values can appear because culling is done only afterwards
449        */
450        void UpdateDistance(BvhNode *node) const;
451        /** Returns the maximum distance from the near plane to this node.
452        */
453        float CalcMaxDistance(BvhNode *node) const;
454        /** Pulls up the last visited classification in the bvh.
455        */
456        void PullUpLastVisited(BvhNode *node, int frameId) const;
457        /** Resets the node classifications in the tree.
458        */
459        void ResetNodeClassifications();
460        /** Counts the number of triangles contained in this node.
461        */
462        int CountTriangles(BvhNode *node) const;
463        /** Returns area of the the node.
464        */
465        float GetArea(BvhNode *node) const;
466        /** Compute unique ids for the nodes.
467        */
468        void ComputeIds();
469        /** Assign virtual leaves based on specified number of triangles per leaf.
470                That means that we try to set the leaves at a point where we
471                have less than numTriangles triangles within this leaf and beyond.
472
473                Virtual leaves are nodes that are determined to be the leaves
474                of the hierarchy during render traversal. These nodes are not necessarily
475                the same as the real leaves of the hierarchy and can be anywhere
476                in the hierarchy.
477                Please refer to the article for more info about virtual leaves
478        */
479        void SetVirtualLeaves(int numTriangles);
480       
481
482        ////////////
483        //-- these functions determine the 'tightness' of the bounds that are used for querying
484
485
486        /** Sets maximal depth for taking the bounding boxes to test the
487                visibility of a node.
488                Deeper level means that the bounds adapt more to the geometry but
489                also that more boxes are rendered
490        */
491        void SetMaxDepthForTestingChildren(int maxDepth);
492        /** The ratio of area between node and subnodes where
493                testing the subnodes as proxy is still considered feasable
494        */
495        void SetAreaRatioThresholdForTestingChildren(float ratio);
496
497
498        ////////////////////////////
499
500        /** Returns statistics.
501        */
502        const BvhStats &GetBvhStats() const { return mBvhStats; }
503        /** Render wireframe bvh for visualization purpose.
504        */
505        void RenderBoundsForViz(BvhNode *node, RenderState *state, bool useTightBounds);
506
507
508protected:
509
510        ////////////////////
511
512        /** protected constructor: do nothing.
513        */
514        Bvh();
515        /** Protected constructor taking scene geometry into account
516                Sets the static and dynamic objects for the hierarchy.
517        */
518        Bvh(const SceneEntityContainer &staticEntities,
519            const SceneEntityContainer &dynamicEntities);
520        /** Protected constructor taking scene geometry into account
521                Sets the static and dynamic objects for the hierarchy.
522        */
523        Bvh(const SceneEntityContainer &staticEntities,
524            const SceneEntityContainer &dynamicEntities,
525            int maxDepthForTestingChildren);
526        /** Called by the constructor. Initializes important members.
527        */
528        void Init();
529
530        /////////////
531        /** Traverse hierarchy and compute stats.
532        */
533        void ComputeBvhStats(BvhNode *root, BvhStats &bvhStats);
534        /** Output the bvh statistics.
535        */
536        void PrintBvhStats(const BvhStats &bvhStats, BvhNode *root) const;
537
538
539        //////////
540        //-- Helper methods for bounding box rendering in immediate and vbo mode.
541       
542        void PrepareVertices();
543        /** Prepare nodes for vbo rendering.
544        */
545        int PrepareBoundsWithDrawArrays(const BvhNodeContainer &nodes);
546        /** Render the nodes from the vbo prepared previously.
547        */
548        void RenderBoundsWithDrawArrays(int numNodes, RenderState *state);
549
550        /** Create the indices that each node needs to use vbo rendering.
551        */
552        void CreateIndices();
553        /** Create the list of nodes whose bounding boxes are tested instead of the
554                bounding box of the node itself.
555        */
556        bool CreateNodeRenderList(BvhNode *node);
557        /** Recursivly updates indices so we can
558                render also interior nodes without traversing hierarchy
559        */
560        void UpdateInteriors(BvhNode *node);
561        /** Recomputes the boundaries of the nodes.
562            This function is always called if some boundary options are changed.
563        */
564        void RecomputeBounds();
565        /** Does some postprocessing on the nodes.
566        */
567        void PostProcess();
568        /** Helper method that updates the number of leaves in the subtree under
569                this node.
570        */
571        void UpdateNumLeaves(BvhNode *node) const;
572        /** Frustum tests the ith plane.
573        */
574        inline bool TestPlane(BvhNode *node, int i, bool &bIntersect);
575        /** Renders a bounding box in immediate mode.
576        */
577        void RenderBoundingBoxImmediate(const AxisAlignedBox3 &box);
578
579
580        /////////////////////////////
581        //-- functions used to construct the dynamic part of the hierarchy
582
583        int SortTriangles(BvhLeaf *leaf,
584                              int axis,
585                                          float position);
586
587        int SortTrianglesSpatialMedian(BvhLeaf *leaf,
588                                           int axis);
589
590        BvhNode *SubdivideLeaf(BvhLeaf *leaf,
591                                   int parentAxis);
592        /** Recompute the dynamic branch of the hierarchy.
593        */
594        void CreateDynamicBranch();
595
596        void UpdateBoundingBoxes(BvhNode *node);
597
598        inline bool TerminationCriteriaMet(BvhLeaf *leaf) const;
599
600        void ComputeMaxDepthForVirtualLeaves();
601
602        void CreateRoot();
603
604        void UpdateDynamicBounds(RenderState *state);
605
606
607        ////////////////////////
608       
609        /// the bounding box of the bvh
610        AxisAlignedBox3 mBox;
611        /// the root of the hierarchy
612        BvhInterior *mRoot;
613        /// the root of static part of the the hierarchy
614        BvhNode *mStaticRoot;
615        /// the root of dynamic part of the the hierarchy
616        BvhNode *mDynamicRoot;
617        /// pointers to the geometry associated with this node
618        SceneEntity **mGeometry;
619        /// #of entities
620        size_t mGeometrySize;
621        /// #of static entities
622        size_t mStaticGeometrySize;
623        /// #of dynamic entities
624        size_t mDynamicGeometrySize;
625
626
627        ////////////////
628        //-- tigher bounds termination criteria
629
630        /** maximal depth from which children are fetched for
631                testing instead of the current node
632        */
633        int mMaxDepthForTestingChildren;
634        /// threshold for computing tighter bounds
635        float mAreaRatioThreshold;
636       
637       
638        ////////////////
639        //-- statistics
640
641        BvhStats mBvhStats;
642        /// the overall number of nodes
643        int mNumNodes;
644        /// the number of "virtual" (=actually used) nodes
645        int mNumVirtualNodes;
646
647
648        ////////////
649        //-- rendering stuff
650
651        /// these proxy nodes are tested instead of the current node
652        BvhNodeContainer mTestNodes;
653        /// the indices used for vbo index buffering
654        unsigned int *mTestIndices;
655        /// a pointer to the end of the indices array
656        int mCurrentIndicesPtr;
657        /// the vbo id
658        unsigned int mVboId;
659        /// a vertex array used if working with indexed arrays (without vbo)
660        Vector3 *mVertices;
661        /// indices used for draw array rendering
662        unsigned int *mIndices;
663
664
665        ///////////
666        //-- termination criteria for dynamic branch
667
668        int mMaxDepthForDynamicBranch;
669
670        //SceneEntityContainer mDynamicEntities;
671};
672
673
674
675/////////////////
676//-- public inline functions
677
678
679inline int BvhNode::GetLastVisitedFrame() const
680{
681        return mVisibility[sCurrentState].mLastVisitedFrame;
682}
683
684
685inline void BvhNode::SetLastVisitedFrame(const int lastVisited)
686{
687        mVisibility[sCurrentState].mLastVisitedFrame = lastVisited;
688}
689
690
691inline bool BvhNode::IsVisible() const
692{
693        return mVisibility[sCurrentState].mIsVisible;
694}
695
696
697inline void BvhNode::SetVisible(bool visible)
698{
699        mVisibility[sCurrentState].mIsVisible = visible;
700}
701
702
703inline void BvhNode::IncTimesTestedInvisible()
704{
705        ++ mVisibility[sCurrentState].mTimesInvisible;
706}
707
708
709inline int BvhNode::GetTimesTestedInvisible() const
710{
711        return mVisibility[sCurrentState].mTimesInvisible;
712}
713
714
715inline void BvhNode::SetTimesTestedInvisible(int t)
716{
717        mVisibility[sCurrentState].mTimesInvisible = t;
718}
719
720
721inline bool BvhNode::IsViewFrustumCulled() const
722{
723        return mVisibility[sCurrentState].mIsFrustumCulled;
724}
725
726
727inline void BvhNode::SetViewFrustumCulled(bool frustumCulled)
728{
729        mVisibility[sCurrentState].mIsFrustumCulled = frustumCulled;
730}
731
732
733inline bool BvhNode::IsNew() const
734{
735        return mVisibility[sCurrentState].mIsNew;
736}
737
738
739inline void BvhNode::SetIsNew(bool isNew)
740{
741        mVisibility[sCurrentState].mIsNew = isNew;
742}
743
744
745inline void BvhNode::SetAssumedVisibleFrameId(int t)
746{
747        mVisibility[sCurrentState].mAssumedVisibleFrameId = t;
748}
749
750
751inline int BvhNode::GetAssumedVisibleFrameId() const
752{
753        return mVisibility[sCurrentState].mAssumedVisibleFrameId;
754}
755
756
757inline int BvhNode::GetLastQueriedFrame() const
758{
759        return mVisibility[sCurrentState].mLastQueriedFrame;
760}
761
762
763inline void BvhNode::SetLastQueriedFrame(int lastTested)
764{
765        mVisibility[sCurrentState].mLastQueriedFrame = lastTested;
766}
767
768
769inline int BvhNode::GetLastRenderedFrame() const
770{
771        return mLastRenderedFrame[sCurrentState];
772}
773       
774
775inline void BvhNode::SetLastRenderedFrame(int lastRenderedFrame)
776{
777        mLastRenderedFrame[sCurrentState] = lastRenderedFrame;
778}
779       
780       
781inline bool BvhNode::Empty() const
782{
783        return (mFirst == -1);
784}
785
786
787inline int BvhNode::CountPrimitives() const
788{
789        return mLast - mFirst + 1;
790}
791
792inline int BvhNode::GetDepth() const
793{
794        return mDepth;
795}
796
797
798inline BvhNode *BvhNode::GetParent()
799{
800        return mParent;
801}
802
803
804inline int BvhNode::GetNumLeaves() const
805{
806        return mNumLeaves;
807}
808
809
810inline bool BvhNode::IsVirtualLeaf() const
811{
812        return mIsVirtualLeaf;
813}
814
815
816inline float BvhNode::GetDistance() const
817{
818        return mDistance;
819}
820
821       
822inline const AxisAlignedBox3 &BvhNode::GetBox() const
823{
824        return mBox;
825}
826
827
828inline int BvhNode::GetId() const
829{
830        return mId;
831}
832
833
834inline void BvhNode::SetId(int id)
835{
836        mId = id;
837}
838
839
840inline void BvhNode::SetCurrentState(int _state)
841{
842        sCurrentState = _state;
843}
844
845
846inline BvhNode *BvhInterior::GetBack()
847{
848        return mBack;
849}
850
851
852inline BvhNode *BvhInterior::GetFront()
853{
854        return mFront;
855}
856
857
858inline int Bvh::GetNumNodes() const
859{
860        return mNumNodes;
861}
862
863
864inline int Bvh::GetNumLeaves() const
865{
866        return mNumNodes / 2 + 1;
867}
868
869
870inline int Bvh::GetNumVirtualNodes() const 
871{
872        return mNumVirtualNodes;
873}
874
875
876inline int Bvh::GetNumVirtualLeaves() const
877{
878        return mNumVirtualNodes / 2 + 1;
879}
880
881
882inline BvhNode *Bvh::GetRoot()
883{
884        return mRoot;
885}
886
887
888inline BvhNode *Bvh::GetDynamicRoot()
889{
890        return mDynamicRoot;
891}
892
893
894inline BvhNode *Bvh::GetStaticRoot()
895{
896        return mStaticRoot;
897}
898
899
900inline const AxisAlignedBox3 &Bvh::GetBox() const
901{
902        return mBox;
903}
904
905
906}
907
908#endif // __BVH_H
Note: See TracBrowser for help on using the repository browser.