source: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/Bvh.cpp @ 3291

Revision 3291, 33.3 KB checked in by mattausch, 15 years ago (diff)
Line 
1#include "Bvh.h"
2#include "Camera.h"
3#include "Plane3.h"
4#include "glInterface.h"
5#include "Triangle3.h"
6#include "SceneEntity.h"
7#include "Geometry.h"
8#include "RenderState.h"
9#include "Material.h"
10#include "BvhConstructor.h"
11#include "gzstream.h"
12
13#include <queue>
14#include <stack>
15#include <fstream>
16#include <iostream>
17#include <iomanip>
18
19
20#ifdef _CRT_SET
21        #define _CRTDBG_MAP_ALLOC
22        #include <stdlib.h>
23        #include <crtdbg.h>
24
25        // redefine new operator
26        #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
27        #define new DEBUG_NEW
28#endif
29
30#define INVALID_TEST ((unsigned int)-1)
31
32using namespace std;
33
34
35namespace CHCDemoEngine
36{
37
38int BvhNode::sCurrentState = 0;
39
40
41/*
423 x---------x 2
43  |\         \
44  | \         \
45  |  \         \
46  |     4 x---------x 5
47  |   |         |
480 x   |     x 1 |
49   \  |         |
50    \ |         |
51     \|         |
52        7 x---------x 6             
53*/
54
55static unsigned int sIndices[] =       
56{7, // degenerated
57 7, 6, 4, 5, 3, 2, 0, 1,
58 1, 4, // degenerated
59 4, 3, 7, 0, 6, 1, 5, 2,
60 2 // degenerated
61};
62
63
64const static int NUM_INDICES_PER_BOX = 20;
65
66/*      Order of vertices
67        0 = (0, 0, 0)
68        1 = (1, 0, 0)
69        2 = (1, 1, 0)
70        3 = (0, 1, 0)
71        4 = (0, 1, 1)
72        5 = (1, 1, 1)
73        6 = (1, 0, 1)
74        7 = (0, 0, 1)
75*/
76
77static Plane3 sNearPlane;
78static float sNear;
79static Frustum sFrustum;
80
81/// these values are valid for all nodes
82static int sClipPlaneAABBVertexIndices[12];
83
84//#define ALIGN_INDICES
85
86
87BvhNode::BvhNode(BvhNode *parent):
88mParent(parent),
89mAxis(-1),
90mDepth(0),
91mFirst(-1),
92mLast(-1),
93mNumTestNodes(1),
94mTestNodesIdx(-1),
95mIndicesPtr(-1),
96mId(0),
97mIsMaxDepthForVirtualLeaf(false),
98mIsVirtualLeaf(false)
99{
100        for (int i = 0; i < NUM_STATES; ++ i)
101        {
102                mPlaneMask[i] = 0;
103                mPreferredPlane[i]= 0;
104                mLastRenderedFrame[i] = -1;
105        }
106}
107
108
109BvhNode::~BvhNode()
110{
111}
112
113
114void BvhNode::ResetVisibility()
115{
116        for (int i = 0; i < NUM_STATES; ++ i)
117        {
118                mVisibility[i].Reset();
119                mLastRenderedFrame[i] = -1;
120                mPlaneMask[i] = 0;
121                mPreferredPlane[i]= 0;
122        }
123}
124
125
126void BvhNode::VisibilityInfo::Reset()
127{
128        mIsVisible = false;
129        mAssumedVisibleFrameId = 0;
130        mLastVisitedFrame = -1;
131        mTimesInvisible = 0;
132        mIsFrustumCulled = false;
133        mIsNew = true;
134        mLastQueriedFrame = -1;
135}
136
137
138BvhInterior::~BvhInterior()
139{
140        DEL_PTR(mBack);
141        DEL_PTR(mFront);
142}
143
144
145BvhLeaf::~BvhLeaf()
146{
147}
148
149BvhInterior::BvhInterior(BvhNode *parent):
150mBack(NULL), mFront(NULL), BvhNode(parent)
151{}
152
153
154bool BvhInterior::IsLeaf() const
155{
156        return false;
157}
158
159
160
161BvhLeaf::BvhLeaf(BvhNode *parent): BvhNode(parent)
162{}
163
164
165bool BvhLeaf::IsLeaf() const
166{
167        return true;
168}
169
170
171
172/**********************************************************/
173/*                class Bvh implementation                */
174/**********************************************************/
175
176
177Bvh::Bvh()
178{
179        Init();
180}
181
182
183Bvh::Bvh(const SceneEntityContainer &staticEntities,
184                 const SceneEntityContainer &dynamicEntities)
185{
186        Init();
187
188        mGeometrySize = staticEntities.size() + dynamicEntities.size();
189        mGeometry = new SceneEntity*[mGeometrySize];
190
191        mStaticGeometrySize = staticEntities.size();
192        mDynamicGeometrySize = dynamicEntities.size();
193
194        for (size_t i = 0; i < mStaticGeometrySize; ++ i)
195        {
196                mGeometry[i] = staticEntities[i];
197        }
198
199        for (size_t i = 0; i < mDynamicGeometrySize; ++ i)
200        {
201                mGeometry[mStaticGeometrySize + i] = dynamicEntities[i];
202        }
203
204        //cout << "max depth for testing children " << mMaxDepthForTestingChildren << endl;
205}
206
207
208Bvh::Bvh(const SceneEntityContainer &staticEntities,
209                 const SceneEntityContainer &dynamicEntities,
210                 int maxDepthForTestingChildren)
211{
212        Init();
213
214        mGeometrySize = staticEntities.size() + dynamicEntities.size();
215        mGeometry = new SceneEntity*[mGeometrySize];
216
217        mStaticGeometrySize = staticEntities.size();
218        mDynamicGeometrySize = dynamicEntities.size();
219
220        for (size_t i = 0; i < mStaticGeometrySize; ++ i)
221        {
222                mGeometry[i] = staticEntities[i];
223        }
224
225        for (size_t i = 0; i < mDynamicGeometrySize; ++ i)
226        {
227                mGeometry[mStaticGeometrySize + i] = dynamicEntities[i];
228        }
229
230        mMaxDepthForTestingChildren = maxDepthForTestingChildren;
231        //cout << "max depth for testing children " << mMaxDepthForTestingChildren << endl;
232}
233
234
235Bvh::~Bvh()
236{
237        DEL_ARRAY_PTR(mVertices);
238        DEL_ARRAY_PTR(mIndices);
239        DEL_ARRAY_PTR(mTestIndices);
240        DEL_ARRAY_PTR(mGeometry);
241
242        if (mRoot) delete mRoot;
243        // delete vbo
244        glDeleteBuffersARB(1, &mVboId);
245}
246
247
248void Bvh::Init()
249{
250        mStaticRoot = NULL;
251        mDynamicRoot = NULL;
252        mRoot = NULL;
253
254        mVertices = NULL;
255        mIndices = NULL;
256        mTestIndices = NULL;
257        mCurrentIndicesPtr = 0;
258        mNumNodes = 0;
259       
260        // nodes are tested using the subnodes from 3 levels below
261        mMaxDepthForTestingChildren = 3;
262        // the ratio of area between node and subnodes where
263        // testing the subnodes as proxy is still considered feasable
264        mAreaRatioThreshold = 2.0f;
265        //mAreaRatioThreshold = 1.4f;
266
267        mVboId = -1;
268        // bounds the maximal depth of the dynamic branch
269        mMaxDepthForDynamicBranch = 10;
270}
271
272
273
274//////////////////////
275//-- functions that are used during the main traversal
276
277void Bvh::PullUpLastVisited(BvhNode *node, int frameId) const
278{               
279        BvhNode *parent = node->GetParent();
280
281        while (parent && (parent->GetLastVisitedFrame() != frameId))
282        {
283                parent->SetLastVisitedFrame(frameId);
284                parent = parent->GetParent();
285        }
286}
287
288
289void Bvh::MakeParentsVisible(BvhNode *node)
290{
291        BvhNode *parent = node->GetParent();
292
293        while (parent && (!parent->IsVisible()))
294        {
295                parent->SetVisible(true);
296                parent = parent->GetParent();
297        }
298}
299
300
301////////////////////////////////
302
303void Bvh::CollectLeaves(BvhNode *node, BvhLeafContainer &leaves)
304{
305        stack<BvhNode *> tStack;
306        tStack.push(node);
307
308        while (!tStack.empty())
309        {
310                BvhNode *node = tStack.top();
311
312                tStack.pop();
313
314                if (!node->IsLeaf())
315                {
316                        BvhInterior *interior = static_cast<BvhInterior *>(node);
317
318                        tStack.push(interior->mFront);
319                        tStack.push(interior->mBack);
320                }
321                else
322                {
323                        leaves.push_back(static_cast<BvhLeaf *>(node));
324                }
325        }
326}
327
328
329int Bvh::CountNumNodes(BvhNode *node) const
330{
331        int numNodes = 0;
332
333        stack<BvhNode *> tStack;
334
335        tStack.push(node);
336
337        while (!tStack.empty())
338        {
339                BvhNode *node = tStack.top();
340                tStack.pop();
341
342                ++ numNodes;
343
344                if (!node->IsLeaf())
345                {
346                        BvhInterior *interior = static_cast<BvhInterior *>(node);
347
348                        tStack.push(interior->mFront);
349                        tStack.push(interior->mBack);
350                }
351        }
352
353        return numNodes;
354}
355
356
357int Bvh::CountNumVirtualNodes(BvhNode *node) const
358{
359        int numNodes = 0;
360
361        stack<BvhNode *> tStack;
362
363        tStack.push(node);
364
365        while (!tStack.empty())
366        {
367                BvhNode *node = tStack.top();
368                tStack.pop();
369
370                ++ numNodes;
371
372                if (!node->IsVirtualLeaf())
373                {
374                        BvhInterior *interior = static_cast<BvhInterior *>(node);
375
376                        tStack.push(interior->mFront);
377                        tStack.push(interior->mBack);
378                }
379        }
380
381        return numNodes;
382}
383
384
385void Bvh::CollectNodes(BvhNode *node, BvhNodeContainer &nodes)
386{
387        stack<BvhNode *> tStack;
388
389        tStack.push(node);
390
391        while (!tStack.empty())
392        {
393                BvhNode *node = tStack.top();
394                tStack.pop();
395
396                nodes.push_back(node);
397
398                if (!node->IsLeaf())
399                {
400                        BvhInterior *interior = static_cast<BvhInterior *>(node);
401
402                        tStack.push(interior->mFront);
403                        tStack.push(interior->mBack);
404                }
405        }
406}
407
408
409typedef pair<BvhNode *, int> tPair;
410
411void Bvh::CollectNodes(BvhNode *root, BvhNodeContainer &nodes, int depth)
412{
413        stack<tPair> tStack;
414        tStack.push(tPair(root, 0));
415
416        while (!tStack.empty())
417        {
418                BvhNode *node = tStack.top().first;
419                const int d = tStack.top().second;
420
421                tStack.pop();
422
423                // found node in specified depth => take this node
424                if ((d == depth) || (node->IsLeaf()))
425                {
426                        nodes.push_back(node);
427                }
428                else
429                {
430                        BvhInterior *interior = static_cast<BvhInterior *>(node);
431
432                        tStack.push(tPair(interior->mFront, d + 1));
433                        tStack.push(tPair(interior->mBack, d + 1));
434                }
435        }
436}
437
438
439SceneEntity **Bvh::GetGeometry(BvhNode *node, int &geometrySize) const
440{
441        geometrySize = node->CountPrimitives();
442        return mGeometry + node->mFirst;
443}
444
445
446bool Bvh::TestPlane(BvhNode *node, int i, bool &bIntersect)
447{
448        // do the test only if necessary
449        if (!(node->mPlaneMask[BvhNode::sCurrentState] & (1 << i)))
450        {
451                return true;
452        }
453
454
455        ////////
456        //-- test the n-vertex
457               
458        if ((node->mBox.GetDistance(sClipPlaneAABBVertexIndices[i * 2 + 0], sFrustum.mClipPlanes[i]) > 0.0f))
459        {
460                // outside
461                node->mPreferredPlane[BvhNode::sCurrentState] = i;
462                return false;
463        }
464
465        ////////////
466        //-- test the p-vertex
467
468        if (node->mBox.GetDistance(sClipPlaneAABBVertexIndices[i * 2 + 1], sFrustum.mClipPlanes[i]) <= 0.0f)
469        {
470                // completely inside: children don't need to check against this plane no more
471                node->mPlaneMask[BvhNode::sCurrentState] ^= 1 << i;
472        }
473        else
474        {
475                bIntersect = true;
476        }
477       
478        return true;
479}
480
481
482int     Bvh::IsWithinViewFrustum(BvhNode *node)
483{
484        bool bIntersect = false;
485
486        if (node->GetParent())
487                node->mPlaneMask[BvhNode::sCurrentState] = node->GetParent()->mPlaneMask[BvhNode::sCurrentState];
488
489        ////////
490        //-- apply frustum culling for the planes with index mPreferredPlane to 6
491
492        for (int i = node->mPreferredPlane[BvhNode::sCurrentState]; i < 6; ++ i)
493                if (!TestPlane(node, i, bIntersect)) return 0;
494       
495
496        //////////
497        //-- apply frustum culling for the planes with index 0 to mPreferredPlane
498
499        for (int i = 0; i < node->mPreferredPlane[BvhNode::sCurrentState]; ++ i)
500                if (!TestPlane(node, i, bIntersect)) return 0;
501       
502        return bIntersect ? -1 : 1;
503}
504
505
506static void CalcNPVertexIndices(const Frustum &frustum, int *indices)
507{
508        for (int i = 0; i < 6; ++ i)
509        {
510                // n-vertex
511                indices[i * 2 + 0] = AxisAlignedBox3::GetIndexNearestVertex(frustum.mClipPlanes[i].mNormal);
512                // p-vertex
513                indices[i * 2 + 1] = AxisAlignedBox3::GetIndexFarthestVertex(frustum.mClipPlanes[i].mNormal);   
514        }
515}
516
517
518void Bvh::InitFrame(Camera *cam, RenderState *state)
519{
520        // = 0011 1111 which means that at the beginning, all six planes have to frustum culled
521        mRoot->mPlaneMask[BvhNode::sCurrentState] = 0x3f;
522
523        cam->CalcFrustum(sFrustum);
524        CalcNPVertexIndices(sFrustum, sClipPlaneAABBVertexIndices);
525
526        // store near plane
527        sNearPlane = Plane3(cam->GetDirection(), cam->GetPosition());
528        sNear = cam->GetNear();
529
530        // update dynamic part of the hierarchy
531        //if (!mDynamicEntities.empty())
532        if (mDynamicGeometrySize)
533        {
534                UpdateBoundingBoxes(mDynamicRoot);
535                UpdateDynamicBounds(state);
536        }
537}
538
539
540void Bvh::UpdateDistance(BvhNode *node) const
541{
542        // q: should we use distance to center rather than the distance to the near plane?
543        // distance to near plane can also be used for checking near plane intersection
544        //node->mDistance = sNearPlane.Distance(node->GetBox().Center());
545        node->mDistance = node->GetBox().GetMinDistance(sNearPlane);
546}
547
548
549float Bvh::CalcMaxDistance(BvhNode *node) const
550{
551#if 1
552        return node->GetBox().GetMaxDistance(sNearPlane);
553
554#else
555        // use bounding boxes of geometry to determine max dist
556        float maxDist = .0f;
557
558        int geometrySize;
559        SceneEntity **entities = GetGeometry(node, geometrySize);
560
561        for (int i = 0; i < geometrySize; ++ i)
562        {
563                SceneEntity *ent = entities[i];
564                float dist = ent->GetWorldBoundingBox().GetMaxDistance(sNearPlane);
565
566                if (dist > maxDist) maxDist = dist;
567        }
568
569        return maxDist;
570#endif
571}
572
573
574void Bvh::RenderBounds(BvhNode *node, RenderState *state, bool useTightBounds)
575{
576        // hack: use dummy contayiner as wrapper in order to use multibox function
577        static BvhNodeContainer dummy(1);
578        dummy[0] = node;
579        RenderBounds(dummy, state, useTightBounds);
580}
581
582
583int Bvh::RenderBounds(const BvhNodeContainer &nodes,
584                                          RenderState *state,
585                                          bool useTightBounds)
586{
587        int renderedBoxes;
588
589        if (!useTightBounds)
590        {
591                // if not using tight bounds, rendering boxes in immediate mode
592                // is preferable to vertex arrays (less setup time)
593                BvhNodeContainer::const_iterator nit, nit_end = nodes.end();
594                       
595                for (nit = nodes.begin(); nit != nit_end; ++ nit)
596                {
597                        RenderBoundingBoxImmediate((*nit)->GetBox());
598                }
599
600                renderedBoxes = (int)nodes.size();
601        }
602        else
603        {
604                renderedBoxes = PrepareBoundsWithDrawArrays(nodes);
605                RenderBoundsWithDrawArrays(renderedBoxes, state);
606        }
607
608        return renderedBoxes;
609}
610
611
612int Bvh::PrepareBoundsWithDrawArrays(const BvhNodeContainer &nodes)
613{
614        ///////////////////
615        //-- for the first time we come here => create vbo and indices
616
617        if (!mIndices)
618        {       
619                // create list of indices
620                CreateIndices();
621        }
622
623        if (mVboId == -1)
624        {       
625                // prepare the vbo
626                PrepareVertices();
627        }
628
629        ///////////////
630
631        int numNodes = 0;
632
633        BvhNodeContainer::const_iterator nit, nit_end = nodes.end();
634
635        for (nit = nodes.begin(); nit != nit_end; ++ nit)
636        {
637                BvhNode *node = *nit;
638        const int numIndices = node->mNumTestNodes * NUM_INDICES_PER_BOX;
639               
640                // copy indices
641                memcpy(mIndices + numNodes * NUM_INDICES_PER_BOX,
642                           mTestIndices + node->mIndicesPtr,
643                           numIndices * sizeof(unsigned int));
644
645                numNodes += node->mNumTestNodes;
646        }
647
648        return numNodes;
649}
650
651
652void Bvh::RenderBoundsWithDrawArrays(int numNodes, RenderState *state)
653{
654        /////////
655        //-- Render the vbo
656
657        if (state->GetCurrentVboId() != mVboId)
658        {
659                glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
660                // set the vertex pointer to the vertex buffer
661                glVertexPointer(3, GL_FLOAT, 0, (char *)NULL); 
662
663                state->SetCurrentVboId(mVboId);
664        }
665
666        // we don't use the last or the first index (they are generate and only used to connect strips)
667        int numElements = numNodes * NUM_INDICES_PER_BOX - 1;
668        // don't render first degenerate index
669        glDrawElements(GL_TRIANGLE_STRIP, numElements, GL_UNSIGNED_INT, mIndices + 1);
670}
671
672
673void Bvh::CreateIndices()
674{
675        // collect bvh nodes
676        BvhNodeContainer nodes;
677        // also add root
678        nodes.push_back(mRoot);
679        // first collect dynamic nodes so we make sure that they are in the beginning
680        CollectNodes(mDynamicRoot, nodes);
681        // then collect static nodes
682        CollectNodes(mStaticRoot, nodes);
683        //CollectNodes(mRoot, nodes);
684       
685
686        cout << "creating new indices" << endl;
687
688        int numMaxIndices = 0;
689
690        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
691
692        for (lit = nodes.begin(); lit != lit_end; ++ lit)
693        {
694                int offset = (*lit)->mNumTestNodes * NUM_INDICES_PER_BOX;
695#ifdef ALIGN_INDICES
696                // align with 32 in order to speed up memcopy
697                offset = (offset / 32) * 32 + 32;
698#endif
699                numMaxIndices += offset;
700        }
701
702        cout << "creating global indices buffer" << endl;
703
704        if (mIndices)     delete [] mIndices;
705        if (mTestIndices) delete [] mTestIndices;
706
707        // global buffer: create it once so we don't have
708        // to allocate memory for each individual chunk of the node
709        mIndices = new unsigned int[numMaxIndices];
710        // create new index buffer for the individual nodes
711        mTestIndices = new unsigned int[numMaxIndices];
712       
713        mCurrentIndicesPtr = 0;
714
715        for (lit = nodes.begin(); lit != lit_end; ++ lit)
716        {
717                BvhNode *node = *lit;
718               
719                // resize array
720                node->mIndicesPtr = mCurrentIndicesPtr;
721                int numIndices = 0;
722
723                // the bounding boxes of the test nodes are rendered instead of the node itself
724                // => store their indices
725                for (int i = 0; i < node->mNumTestNodes; ++ i, numIndices += NUM_INDICES_PER_BOX)
726                {
727                        BvhNode *testNode = mTestNodes[node->mTestNodesIdx + i];
728
729                        // add vertex indices of boxes to root node
730                        for (int j = 0; j < NUM_INDICES_PER_BOX; ++ j)
731                        {
732                                mTestIndices[mCurrentIndicesPtr + numIndices + j] = sIndices[j] + testNode->GetId() * 8;
733                        }
734                }
735
736                // align with 32
737#ifdef ALIGN_INDICES
738                const int offset = (numIndices / 32) * 32 + 32;
739#else
740                const int offset = numIndices;
741#endif
742                mCurrentIndicesPtr += offset;
743        }
744}
745
746
747void Bvh::ComputeIds()
748{
749        // collect all nodes
750        BvhNodeContainer nodes;
751        // also add root
752        nodes.push_back(mRoot);
753        //CollectNodes(mRoot, nodes);
754        // first collect dynamic nodes so we make sure that they are in the beginning
755        CollectNodes(mDynamicRoot, nodes);
756        // then collect static nodes
757        CollectNodes(mStaticRoot, nodes);
758
759        // assign ids to all nodes of the hierarchy
760        int i = 0;
761        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
762
763        for (lit = nodes.begin(); lit != lit_end; ++ lit, ++ i)
764        {
765                (*lit)->SetId(i);
766        }
767}
768
769
770void Bvh::PrepareVertices()
771{
772        // collect all nodes
773        BvhNodeContainer nodes;
774
775        nodes.reserve(GetNumNodes());
776        // also add root
777        nodes.push_back(mRoot);
778        // first collect dynamic nodes so we make sure that they are in the beginning
779        CollectNodes(mDynamicRoot, nodes);
780        // then collect static nodes
781        CollectNodes(mStaticRoot, nodes);
782
783        const unsigned int bufferSize = 8 * (int)nodes.size();
784        mVertices = new Vector3[bufferSize];
785       
786        int i = 0;
787       
788        // store bounding box vertices
789        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
790
791        for (lit = nodes.begin(); lit != lit_end; ++ lit, i += 8)
792        {
793                BvhNode *node = *lit;
794                Vector3 v;
795
796                for (int j = 0; j < 8; ++ j)
797                {
798                        node->GetBox().GetVertex2(j, v);
799                        (static_cast<Vector3 *>(mVertices))[node->GetId() * 8 + j] = v;
800                }
801        }
802
803        glGenBuffersARB(1, &mVboId);
804        glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
805        glVertexPointer(3, GL_FLOAT, 0, (char *)NULL);
806       
807        glBufferDataARB(GL_ARRAY_BUFFER_ARB,
808                            bufferSize * sizeof(Vector3),
809                            mVertices,
810                                        //GL_STATIC_DRAW_ARB);
811                                        GL_DYNAMIC_DRAW_ARB);
812
813        glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
814
815        // data handled by graphics driver from now on
816        DEL_ARRAY_PTR(mVertices);
817
818        cout << "******** created vbos for tighter bounds *********" << endl;
819}
820
821
822void Bvh::UpdateDynamicBounds(RenderState *state)
823{
824        // vbos not created yet
825        if (mVboId == -1) return;
826
827        // collect all nodes
828        static BvhNodeContainer nodes;
829        nodes.clear();
830
831        // also add root
832        nodes.push_back(mRoot);
833       
834        CollectNodes(mDynamicRoot, nodes);
835
836
837        const unsigned int bufferSize = 8 * (int)nodes.size();
838        if (!mVertices) mVertices = new Vector3[bufferSize];
839       
840        int i = 0;
841       
842        // store bounding box vertices
843        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
844
845        for (lit = nodes.begin(); lit != lit_end; ++ lit, i += 8)
846        {
847                BvhNode *node = *lit;
848
849                for (int j = 0; j < 8; ++ j)
850                {
851                        (static_cast<Vector3 *>(mVertices))[node->GetId() * 8 + j] = node->GetBox().GetVertex(j);
852                }
853        }
854       
855        if (state->GetCurrentVboId() != mVboId)
856        {
857                glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
858                // set the vertex pointer to the vertex buffer
859                glVertexPointer(3, GL_FLOAT, 0, (char *)NULL); 
860                state->SetCurrentVboId(mVboId);
861        }
862
863        glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0,
864                                           bufferSize * sizeof(Vector3),
865                                           mVertices);
866}
867
868
869void Bvh::SetMaxDepthForTestingChildren(int maxDepth)
870{
871        if (maxDepth != mMaxDepthForTestingChildren)
872        {
873                mMaxDepthForTestingChildren = maxDepth;
874                RecomputeBounds();
875        }
876}
877
878
879void Bvh::SetAreaRatioThresholdForTestingChildren(float ratio)
880{
881        if (ratio != mAreaRatioThreshold)
882        {
883                mAreaRatioThreshold = ratio;
884                RecomputeBounds();
885        }
886}
887
888
889void Bvh::RecomputeBounds()
890{
891        // collect all nodes
892        BvhNodeContainer nodes;
893        CollectNodes(mRoot, nodes);
894
895        cout << "\nrecomputing bounds, children will be tested in depth " << mMaxDepthForTestingChildren << endl;
896
897        int success = 0;
898        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
899
900        for (lit = nodes.begin(); lit != lit_end; ++ lit)
901        {
902                BvhNode *node = *lit;
903
904                // recreate list of nodes that will be queried as a proxy
905                if (CreateNodeRenderList(node))
906                        ++ success;
907        }
908
909        float p = 100.0f * (float)success / nodes.size();
910        cout << "created tighter bounds for " << p << " percent of the nodes" << endl;
911
912        // recreate indices used for indirect rendering mode
913        if (mIndices) CreateIndices();
914}
915
916       
917bool Bvh::CreateNodeRenderList(BvhNode *node)
918{
919        BvhNodeContainer children;
920
921        // collect nodes that will be tested instead of the leaf node
922        // in order to get a tighter bounding box test
923        CollectNodes(node, children, mMaxDepthForTestingChildren);
924       
925
926        // using the tighter bounds is not feasable in case
927        // that the tighter bounds represent nearly the same projected area
928        // as the old bounding box. Test this property using either
929        // volume or area heuristics
930
931        float vol = 0;
932        float area = 0;
933
934        BvhNodeContainer::const_iterator cit;
935
936        for (cit = children.begin(); cit != children.end(); ++ cit)
937                area += (*cit)->GetBox().SurfaceArea();
938
939        const float areaRatio = area / node->GetBox().SurfaceArea();
940       
941        bool success;
942
943        if (areaRatio < mAreaRatioThreshold)
944                success = true;
945        else
946        {
947                // hack: only store node itself
948                children.clear();
949                children.push_back(node);
950
951                success = false;
952        }
953
954        // the new test nodes are added at the end of the vector
955        node->mTestNodesIdx = (int)mTestNodes.size();
956
957        // use the collected nodes as proxy for the occlusion tests
958        for (cit = children.begin(); cit != children.end(); ++ cit)
959        {
960                BvhNode *child = *cit;
961                mTestNodes.push_back(child);
962        }
963
964        node->mNumTestNodes = (int)children.size();
965
966        return success;
967}
968
969
970void Bvh::ResetNodeClassifications()
971{
972        BvhNodeContainer nodes;
973
974        nodes.reserve(GetNumNodes());
975        CollectNodes(mRoot, nodes);
976
977        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
978
979        for (lit = nodes.begin(); lit != lit_end; ++ lit)
980        {
981                (*lit)->ResetVisibility();
982        }
983}
984
985
986void Bvh::ComputeBvhStats(BvhNode *root, BvhStats &bvhStats)
987{
988        bvhStats.Reset();
989        std::stack<BvhNode *> nodeStack;
990        nodeStack.push(root);
991
992        int numVirtualLeaves = 0;
993        int numGeometry = 0;
994
995        while (!nodeStack.empty())
996        {
997                BvhNode *node = nodeStack.top();
998                nodeStack.pop();
999
1000                if (node->IsVirtualLeaf())
1001                {
1002                        ++ numVirtualLeaves;
1003                        numGeometry += node->CountPrimitives();
1004
1005                        BvhLeaf *leaf = static_cast<BvhLeaf *>(node);
1006
1007                        bvhStats.mTriangles += CountTriangles(leaf);
1008                        bvhStats.mLeafSA += leaf->mBox.SurfaceArea();
1009                        bvhStats.mLeafVol += leaf->mBox.GetVolume();
1010                }
1011                else
1012                {
1013                        bvhStats.mInteriorSA += node->mBox.SurfaceArea();
1014                        bvhStats.mInteriorVol += node->mBox.GetVolume();
1015
1016                        BvhInterior *interior = static_cast<BvhInterior *>(node);
1017                       
1018                        nodeStack.push(interior->mBack);
1019                        nodeStack.push(interior->mFront);
1020                }
1021        }
1022
1023        bvhStats.mGeometryRatio = (float)numGeometry / numVirtualLeaves;
1024        bvhStats.mTriangleRatio = (float)bvhStats.mTriangles / numVirtualLeaves;
1025        bvhStats.mLeaves = numVirtualLeaves;
1026}
1027
1028
1029void Bvh::PrintBvhStats(const BvhStats &bvhStats, BvhNode *root) const
1030{
1031        cout << "interiorNodesSA = " << bvhStats.mInteriorSA / root->mBox.SurfaceArea() << endl;
1032        cout << "leafNodesSA = " << bvhStats.mLeafSA / root->mBox.SurfaceArea() << endl;
1033        cout << "interiorNodesVolume = " << bvhStats.mInteriorVol / root->mBox.GetVolume() << endl;
1034        cout << "leafNodesVolume = " << bvhStats.mLeafVol / root->mBox.GetVolume() << endl;
1035
1036        cout << "geometry per leaf: " << bvhStats.mGeometryRatio << endl;
1037        cout << "triangles per leaf: " << bvhStats.mTriangleRatio << endl;
1038        cout << "===========================================" << endl << endl;
1039}
1040
1041
1042int Bvh::CountTriangles(BvhNode *node) const
1043{
1044        int numTriangles = 0;
1045
1046        for (int i = node->mFirst; i <= node->mLast; ++ i)
1047        {
1048                numTriangles += mGeometry[i]->CountNumTriangles(0);
1049        }
1050
1051        return numTriangles;
1052}
1053
1054
1055float Bvh::GetArea(BvhNode *node) const
1056{
1057        return node->mArea;
1058}
1059
1060
1061void Bvh::UpdateNumLeaves(BvhNode *node) const
1062{
1063        if (node->IsLeaf())
1064        {
1065                node->mNumLeaves = 1;
1066        }
1067        else
1068        {
1069                BvhNode *f = static_cast<BvhInterior *>(node)->GetFront();
1070                BvhNode *b = static_cast<BvhInterior *>(node)->GetBack();
1071
1072                UpdateNumLeaves(f);
1073                UpdateNumLeaves(b);
1074
1075                node->mNumLeaves = f->mNumLeaves + b->mNumLeaves;
1076        }
1077}
1078
1079
1080void Bvh::CollectVirtualLeaves(BvhNode *node, BvhNodeContainer &leaves)
1081{
1082        stack<BvhNode *> tStack;
1083        tStack.push(node);
1084
1085        while (!tStack.empty())
1086        {
1087                BvhNode *node = tStack.top();
1088                tStack.pop();
1089
1090                if (node->mIsVirtualLeaf)
1091                {
1092                        leaves.push_back(node);
1093                }
1094                else if (!node->IsLeaf())
1095                {
1096                        BvhInterior *interior = static_cast<BvhInterior *>(node);
1097
1098                        tStack.push(interior->mFront);
1099                        tStack.push(interior->mBack);
1100                }
1101        }
1102}
1103
1104
1105void Bvh::SetVirtualLeaves(int numTriangles)
1106{
1107        // first invalidate old virtual leaves
1108        BvhNodeContainer leaves;
1109        CollectVirtualLeaves(mRoot, leaves);
1110
1111        BvhNodeContainer::const_iterator bit, bit_end = leaves.end();
1112
1113        for (bit = leaves.begin(); bit != bit_end; ++ bit)
1114        {
1115                (*bit)->mIsVirtualLeaf = false;
1116        }
1117
1118        mNumVirtualNodes = 0;
1119        // assign new virtual leaves based on specified #triangles per leaf
1120        std::stack<BvhNode *> nodeStack;
1121        nodeStack.push(mStaticRoot);
1122        nodeStack.push(mDynamicRoot);
1123
1124        while (!nodeStack.empty())
1125        {
1126                BvhNode *node = nodeStack.top();
1127                nodeStack.pop();
1128
1129                ++ mNumVirtualNodes;
1130
1131                if (node->IsLeaf())
1132                {
1133                        BvhLeaf *leaf = static_cast<BvhLeaf *>(node);
1134                        leaf->mIsVirtualLeaf = true;
1135                }
1136                else
1137                {
1138                        BvhInterior *interior = static_cast<BvhInterior *>(node);
1139
1140                        BvhNode *f = interior->mFront;
1141                        BvhNode *b = interior->mBack;
1142
1143                        if (node->mIsMaxDepthForVirtualLeaf ||
1144                                (CountTriangles(node) <= numTriangles))
1145                        {
1146                                //cout << " l " << CountTriangles(node) << " " << node->mIsMaxDepthForVirtualLeaf << endl;
1147                                node->mIsVirtualLeaf = true;
1148                        }
1149                        else
1150                        {
1151                                nodeStack.push(interior->mBack);
1152                                nodeStack.push(interior->mFront);
1153                        }
1154                }
1155        }
1156
1157        /// Reset the node states
1158        ResetNodeClassifications();
1159}
1160
1161
1162void Bvh::ComputeMaxDepthForVirtualLeaves()
1163{
1164        // We initialize the maximal depth for virtual leaves
1165        // of this bvh, i.e., the nodes that are used as
1166        // leaves of the hierarchy during traversal.
1167
1168        // Initially they are set either
1169        // a) to the real leaves of the hierarchy or
1170        // b) the point where the subdivision on object level ends
1171        // and the subsequent nodes are just used to provide tighter bounds
1172        // (see article for the notations)
1173
1174        std::stack<BvhNode *> nodeStack;
1175
1176        nodeStack.push(mStaticRoot);
1177        nodeStack.push(mDynamicRoot);
1178
1179        while (!nodeStack.empty())
1180        {
1181                BvhNode *node = nodeStack.top();
1182                nodeStack.pop();
1183
1184                if (node->IsLeaf())
1185                {
1186                        node->mIsMaxDepthForVirtualLeaf = true;
1187                }
1188                else
1189                {
1190                        BvhInterior *interior = static_cast<BvhInterior *>(node);
1191
1192                        BvhNode *f = interior->mFront;
1193                        BvhNode *b = interior->mBack;
1194
1195                        if ((f->mFirst == b->mFirst) && (f->mLast == b->mLast))
1196                        {
1197                                // point reached where beyond there would be no further reduction
1198                                // as both subtrees contain the same objects => stop here
1199                                // The tree beyond the current node is used to describe
1200                                // tighter bounds on the geometry contained  in it
1201                                node->mIsMaxDepthForVirtualLeaf = true;
1202                        }
1203                        else
1204                        {
1205                                nodeStack.push(f);
1206                                nodeStack.push(b);
1207                        }
1208                }
1209        }
1210}
1211
1212
1213// this function must be called once after hierarchy creation
1214void Bvh::PostProcess()
1215{
1216        CreateRoot();
1217
1218        ComputeMaxDepthForVirtualLeaves();
1219        // set virtual leaves for specified number of triangles
1220        SetVirtualLeaves(INITIAL_TRIANGLES_PER_VIRTUAL_LEAVES);
1221        /// for each node compute the number of leaves under this node
1222        UpdateNumLeaves(mRoot);
1223        // compute new ids
1224        ComputeIds();
1225        // specify bounds for occlusion tests
1226        RecomputeBounds();
1227
1228        mBox = mRoot->GetBox();
1229
1230        // compute and print stats for whole (static + dynamic) bvh
1231        ComputeBvhStats(mRoot, mBvhStats);
1232
1233        BvhStats staticBvhStats;
1234        ComputeBvhStats(mStaticRoot, staticBvhStats);
1235        cout << "\n============ Static BVH statistics =============" << endl;
1236
1237        PrintBvhStats(staticBvhStats, mStaticRoot);
1238
1239        // also output dynamic stats
1240        if (mDynamicGeometrySize)
1241        {
1242                BvhStats dynBvhStats;
1243                ComputeBvhStats(mDynamicRoot, dynBvhStats);
1244       
1245                cout << "\n=========== Dynamic BVH statistics: =========" << endl;
1246                PrintBvhStats(dynBvhStats, mDynamicRoot);
1247        }
1248}
1249
1250
1251void Bvh::RenderBoundingBoxImmediate(const AxisAlignedBox3 &box)
1252{
1253        const Vector3 l = box.Min();
1254        const Vector3 u = box.Max();
1255
1256        ///////////
1257        //-- render AABB as triangle strips
1258
1259        glBegin(GL_TRIANGLE_STRIP);
1260
1261        // render first half of AABB
1262        glVertex3f(l.x, l.y, u.z);
1263        glVertex3f(u.x, l.y, u.z);
1264        glVertex3f(l.x, u.y, u.z);
1265        glVertex3f(u.x, u.y, u.z);
1266        glVertex3f(l.x, u.y, l.z);
1267        glVertex3f(u.x, u.y, l.z);
1268        glVertex3f(l.x, l.y, l.z);
1269        glVertex3f(u.x, l.y, l.z);
1270
1271        glPrimitiveRestartNV();
1272
1273        // render second half of AABB
1274        glVertex3f(l.x, u.y, u.z);
1275        glVertex3f(l.x, u.y, l.z);
1276        glVertex3f(l.x, l.y, u.z);
1277        glVertex3f(l.x, l.y, l.z);
1278        glVertex3f(u.x, l.y, u.z);
1279        glVertex3f(u.x, l.y, l.z);
1280        glVertex3f(u.x, u.y, u.z);
1281        glVertex3f(u.x, u.y, l.z);
1282
1283        glEnd();
1284}
1285
1286
1287static void RenderBoxForViz(const AxisAlignedBox3 &box)
1288{
1289        glBegin(GL_LINE_LOOP);
1290        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
1291        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
1292        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
1293        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
1294        glEnd();
1295
1296        glBegin(GL_LINE_LOOP);
1297        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
1298        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
1299        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
1300        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
1301        glEnd();
1302
1303        glBegin(GL_LINE_LOOP);
1304        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
1305        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
1306        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
1307        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
1308        glEnd();
1309
1310        glBegin(GL_LINE_LOOP);
1311        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
1312        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
1313        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
1314        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
1315        glEnd();
1316
1317        glBegin(GL_LINE_LOOP);
1318        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
1319        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
1320        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
1321        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
1322        glEnd();
1323
1324        glBegin(GL_LINE_LOOP);
1325        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
1326        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
1327        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
1328        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
1329
1330        glEnd();
1331}
1332
1333
1334static Technique GetVizTechnique()
1335{
1336        Technique tech;
1337        tech.Init();
1338
1339        //tech.SetLightingEnabled(false);
1340        //tech.SetDepthWriteEnabled(false);
1341
1342        tech.SetEmmisive(RgbaColor(1.0f, 1.0f, 1.0f, 1.0f));
1343        tech.SetDiffuse(RgbaColor(1.0f, 1.0f, 1.0f, 1.0f));
1344        tech.SetAmbient(RgbaColor(1.0f, 1.0f, 1.0f, 1.0f));
1345
1346        return tech;
1347}
1348
1349
1350void Bvh::RenderBoundsForViz(BvhNode *node,
1351                                                         RenderState *state,
1352                                                         bool useTightBounds)
1353{
1354        Technique *oldTech = state->GetState();
1355        // we set a simple material
1356        static Technique boxMat = GetVizTechnique();
1357        boxMat.Render(state);
1358
1359        if (!useTightBounds)
1360        {
1361#if 1
1362                RenderBoxForViz(node->GetBox());
1363#else
1364                glPolygonMode(GL_FRONT, GL_LINE);
1365                RenderBoundingBoxImmediate(node->GetBox());
1366                glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1367#endif
1368        }
1369        else
1370        {
1371                for (int i = 0; i < node->mNumTestNodes; ++ i)
1372                {
1373                        RenderBoxForViz(mTestNodes[node->mTestNodesIdx + i]->GetBox());
1374                }
1375        }
1376
1377        if (oldTech) oldTech->Render(state);
1378}
1379
1380
1381
1382
1383bool Bvh::IntersectsNearPlane(BvhNode *node) const
1384{
1385        // note: we have problems with large scale object penetrating the near plane
1386        // (e.g., objects in the distance which are always handled to be visible)
1387        // especially annoying is this problem when using the frustum
1388        // fitting on the visible objects for shadow mapping
1389        // but don't see how to solve this issue without using costly calculations
1390       
1391        // we stored the near plane distance => we can use it also here
1392        float distanceToNearPlane = node->GetDistance();
1393        //float distanceToNearPlane = node->GetBox().GetMinDistance(sNearPlane);
1394       
1395        return (distanceToNearPlane < sNear);
1396}
1397
1398
1399void Bvh::CreateRoot()
1400{
1401        // create new root
1402        mRoot = new BvhInterior(NULL);
1403
1404        // the separation is a purely logical one
1405        // the bounding boxes of the child nodes are
1406        // identical to those of the root node
1407
1408        mRoot->mBox = mStaticRoot->mBox;
1409        mRoot->mBox.Include(mDynamicRoot->mBox);
1410
1411        mRoot->mArea = mRoot->mBox.SurfaceArea();
1412
1413        mRoot->mFirst = 0;
1414        mRoot->mLast = (int)mGeometrySize - 1;
1415
1416        //cout<<"f: " << mRoot->mFirst<< " l: " <<mRoot->mLast << endl;
1417        // add static root on left subtree
1418        mRoot->mFront = mStaticRoot;
1419        mStaticRoot->mParent = mRoot;
1420
1421        // add dynamic root on left subtree
1422        mRoot->mBack = mDynamicRoot;
1423        mDynamicRoot->mParent = mRoot;
1424}
1425 
1426
1427
1428
1429////////////////////////
1430//-- dynamic hierarchy stuff
1431
1432
1433void Bvh::UpdateBoundingBoxes(BvhNode *node)
1434{
1435        if (node->IsLeaf())
1436        {
1437                int numEntities;
1438                SceneEntity **entities = GetGeometry(node, numEntities);
1439
1440                node->mBox = SceneEntity::ComputeBoundingBox(entities, numEntities);
1441                //cout << "box: " << node->mBox << endl;
1442        }
1443        else
1444        {
1445                BvhNode *f = static_cast<BvhInterior *>(node)->GetFront();
1446                BvhNode *b = static_cast<BvhInterior *>(node)->GetBack();
1447
1448                UpdateBoundingBoxes(f);
1449                UpdateBoundingBoxes(b);
1450
1451                node->mBox = f->mBox;
1452                node->mBox.Include(b->mBox);
1453        }
1454}
1455
1456
1457void Bvh::CreateDynamicBranch()
1458{
1459        // the bvh has two main branches
1460        // a static branch (the old root), and a dynamic branch
1461        // we create a 'dynamic' leaf which basically is a container
1462        // for all dynamic objects underneath
1463
1464        // the bounding boxes of the dynamic tree must be updated
1465        // once each frame in order to be able to incorporate
1466        // the movements of the objects within
1467
1468       
1469        cout << "\n==============================" << endl;
1470        cout << "creating dynamic bvh branch"  << endl;
1471
1472        DEL_PTR(mDynamicRoot);
1473        -- mNumNodes;
1474
1475        BvhConstructor bvhConstructor(mGeometry, (int)mStaticGeometrySize, (int)mGeometrySize - 1);
1476
1477        int numNodes;
1478        mDynamicRoot = bvhConstructor.Construct(numNodes);
1479
1480        mNumNodes += numNodes;
1481}
1482
1483
1484
1485
1486}
Note: See TracBrowser for help on using the repository browser.