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

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