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

Revision 3271, 32.9 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
[2746]357void Bvh::CollectNodes(BvhNode *node, BvhNodeContainer &nodes)
358{
359        stack<BvhNode *> tStack;
360
361        tStack.push(node);
362
363        while (!tStack.empty())
364        {
365                BvhNode *node = tStack.top();
366                tStack.pop();
367
368                nodes.push_back(node);
369
370                if (!node->IsLeaf())
371                {
372                        BvhInterior *interior = static_cast<BvhInterior *>(node);
373
374                        tStack.push(interior->mFront);
375                        tStack.push(interior->mBack);
376                }
377        }
378}
379
380
381typedef pair<BvhNode *, int> tPair;
382
[2755]383void Bvh::CollectNodes(BvhNode *root, BvhNodeContainer &nodes, int depth)
[2746]384{
385        stack<tPair> tStack;
386        tStack.push(tPair(root, 0));
387
388        while (!tStack.empty())
389        {
390                BvhNode *node = tStack.top().first;
391                const int d = tStack.top().second;
392
393                tStack.pop();
394
[3065]395                // found node in specified depth => take this node
[2755]396                if ((d == depth) || (node->IsLeaf()))
[2746]397                {
398                        nodes.push_back(node);
399                }
[2755]400                else
[2951]401                {
[2746]402                        BvhInterior *interior = static_cast<BvhInterior *>(node);
403
404                        tStack.push(tPair(interior->mFront, d + 1));
405                        tStack.push(tPair(interior->mBack, d + 1));
406                }
407        }
408}
409
410
[2951]411SceneEntity **Bvh::GetGeometry(BvhNode *node, int &geometrySize) const
[2746]412{
413        geometrySize = node->CountPrimitives();
414        return mGeometry + node->mFirst;
415}
416
417
[2762]418bool Bvh::TestPlane(BvhNode *node, int i, bool &bIntersect)
419{
420        // do the test only if necessary
[2895]421        if (!(node->mPlaneMask[BvhNode::sCurrentState] & (1 << i)))
[3065]422        {
[2763]423                return true;
[3065]424        }
425
426
[2763]427        ////////
428        //-- test the n-vertex
429               
430        if ((node->mBox.GetDistance(sClipPlaneAABBVertexIndices[i * 2 + 0], sFrustum.mClipPlanes[i]) > 0.0f))
431        {
432                // outside
[2895]433                node->mPreferredPlane[BvhNode::sCurrentState] = i;
[2763]434                return false;
[2762]435        }
436
[2763]437        ////////////
438        //-- test the p-vertex
439
440        if (node->mBox.GetDistance(sClipPlaneAABBVertexIndices[i * 2 + 1], sFrustum.mClipPlanes[i]) <= 0.0f)
441        {
442                // completely inside: children don't need to check against this plane no more
[2895]443                node->mPlaneMask[BvhNode::sCurrentState] ^= 1 << i;
[2763]444        }
445        else
446        {
447                bIntersect = true;
448        }
449       
[2762]450        return true;
451}
452
453
[2755]454int     Bvh::IsWithinViewFrustum(BvhNode *node)
[2746]455{
456        bool bIntersect = false;
457
458        if (node->GetParent())
[2895]459                node->mPlaneMask[BvhNode::sCurrentState] = node->GetParent()->mPlaneMask[BvhNode::sCurrentState];
[2746]460
461        ////////
[3065]462        //-- apply frustum culling for the planes with index mPreferredPlane to 6
[2763]463
[2895]464        for (int i = node->mPreferredPlane[BvhNode::sCurrentState]; i < 6; ++ i)
[2762]465                if (!TestPlane(node, i, bIntersect)) return 0;
[2763]466       
[2895]467
[2746]468        //////////
[3065]469        //-- apply frustum culling for the planes with index 0 to mPreferredPlane
[2746]470
[2895]471        for (int i = 0; i < node->mPreferredPlane[BvhNode::sCurrentState]; ++ i)
[2762]472                if (!TestPlane(node, i, bIntersect)) return 0;
[2763]473       
[2746]474        return bIntersect ? -1 : 1;
475}
476
477
[2911]478static void CalcNPVertexIndices(const Frustum &frustum, int *indices)
479{
480        for (int i = 0; i < 6; ++ i)
481        {
482                // n-vertex
483                indices[i * 2 + 0] = AxisAlignedBox3::GetIndexNearestVertex(frustum.mClipPlanes[i].mNormal);
484                // p-vertex
485                indices[i * 2 + 1] = AxisAlignedBox3::GetIndexFarthestVertex(frustum.mClipPlanes[i].mNormal);   
486        }
487}
488
489
[3074]490void Bvh::InitFrame(Camera *cam, RenderState *state)
[2746]491{
492        // = 0011 1111 which means that at the beginning, all six planes have to frustum culled
[2895]493        mRoot->mPlaneMask[BvhNode::sCurrentState] = 0x3f;
[2746]494
[2897]495        cam->CalcFrustum(sFrustum);
[2911]496        CalcNPVertexIndices(sFrustum, sClipPlaneAABBVertexIndices);
[2746]497
[2763]498        // store near plane
[2897]499        sNearPlane = Plane3(cam->GetDirection(), cam->GetPosition());
[3065]500        sNear = cam->GetNear();
[3053]501
[3072]502        // update dynamic part of the hierarchy
503        //if (!mDynamicEntities.empty())
504        if (mDynamicGeometrySize)
[3053]505        {
[3267]506                UpdateBoundingBoxes(mDynamicRoot);
[3074]507                UpdateDynamicBounds(state);
[3053]508        }
[2746]509}
510
511
[2954]512void Bvh::UpdateDistance(BvhNode *node) const
[2746]513{
[3065]514        // q: should we use distance to center rather than the distance to the near plane?
[3068]515        // distance to near plane can also be used for checking near plane intersection
516        //node->mDistance = sNearPlane.Distance(node->GetBox().Center());
517        node->mDistance = node->GetBox().GetMinDistance(sNearPlane);
[2746]518}
519
520
[2947]521float Bvh::CalcMaxDistance(BvhNode *node) const
522{
[3068]523#if 1
[2947]524        return node->GetBox().GetMaxDistance(sNearPlane);
[2951]525
[3068]526#else
527        // use bounding boxes of geometry to determine max dist
[2951]528        float maxDist = .0f;
529
530        int geometrySize;
531        SceneEntity **entities = GetGeometry(node, geometrySize);
532
533        for (int i = 0; i < geometrySize; ++ i)
534        {
535                SceneEntity *ent = entities[i];
[3070]536                float dist = ent->GetWorldBoundingBox().GetMaxDistance(sNearPlane);
[2951]537
538                if (dist > maxDist) maxDist = dist;
539        }
540
541        return maxDist;
[3068]542#endif
[2947]543}
544
545
[2786]546void Bvh::RenderBounds(BvhNode *node, RenderState *state, bool useTightBounds)
[2746]547{
[3065]548        // hack: use dummy contayiner as wrapper in order to use multibox function
549        static BvhNodeContainer dummy(1);
550        dummy[0] = node;
551        RenderBounds(dummy, state, useTightBounds);
[2746]552}
553
554
[2786]555int Bvh::RenderBounds(const BvhNodeContainer &nodes,
556                                          RenderState *state,
557                                          bool useTightBounds)
[2746]558{
[2786]559        int renderedBoxes;
560
561        if (!useTightBounds)
562        {
[3064]563                // if not using tight bounds, rendering boxes in immediate mode
564                // is preferable to vertex arrays (less setup time)
[2786]565                BvhNodeContainer::const_iterator nit, nit_end = nodes.end();
566                       
567                for (nit = nodes.begin(); nit != nit_end; ++ nit)
568                {
569                        RenderBoundingBoxImmediate((*nit)->GetBox());
570                }
[3065]571
[2786]572                renderedBoxes = (int)nodes.size();
573        }
574        else
[3065]575        {
[2786]576                renderedBoxes = PrepareBoundsWithDrawArrays(nodes);
577                RenderBoundsWithDrawArrays(renderedBoxes, state);
578        }
579
[2746]580        return renderedBoxes;
581}
582
583
[2786]584int Bvh::PrepareBoundsWithDrawArrays(const BvhNodeContainer &nodes)
[2746]585{
[3064]586        ///////////////////
587        //-- for the first time we come here => create vbo and indices
[3074]588
[2746]589        if (!mIndices)
[3064]590        {       
591                // create list of indices
[2746]592                CreateIndices();
593        }
594
[2773]595        if (mVboId == -1)
[2746]596        {       
597                // prepare the vbo
598                PrepareVertices();
599        }
[3074]600
[2746]601        ///////////////
602
603        int numNodes = 0;
[3074]604
[2746]605        BvhNodeContainer::const_iterator nit, nit_end = nodes.end();
606
607        for (nit = nodes.begin(); nit != nit_end; ++ nit)
608        {
609                BvhNode *node = *nit;
[3202]610        const int numIndices = node->mNumTestNodes * NUM_INDICES_PER_BOX;
[2746]611               
612                // copy indices
[3202]613                memcpy(mIndices + numNodes * NUM_INDICES_PER_BOX,
[2746]614                           mTestIndices + node->mIndicesPtr,
615                           numIndices * sizeof(unsigned int));
[2795]616
[2746]617                numNodes += node->mNumTestNodes;
618        }
[3074]619
[2746]620        return numNodes;
621}
622
623
[2786]624void Bvh::RenderBoundsWithDrawArrays(int numNodes, RenderState *state)
[2746]625{
[3064]626        /////////
627        //-- Render the vbo
[2773]628
629        if (state->GetCurrentVboId() != mVboId)
630        {
631                glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
[2746]632                // set the vertex pointer to the vertex buffer
[2773]633                glVertexPointer(3, GL_FLOAT, 0, (char *)NULL); 
[2746]634
[2773]635                state->SetCurrentVboId(mVboId);
636        }
[2746]637
[3202]638        // we don't use the last or the first index (they are generate and only used to connect strips)
639        int numElements = numNodes * NUM_INDICES_PER_BOX - 1;
[2746]640        // don't render first degenerate index
641        glDrawElements(GL_TRIANGLE_STRIP, numElements, GL_UNSIGNED_INT, mIndices + 1);
642}
643
644
645void Bvh::CreateIndices()
646{
647        // collect bvh nodes
648        BvhNodeContainer nodes;
[3202]649        // first collect dynamic nodes so we make sure that they are in the beginning
650        CollectNodes(mDynamicRoot, nodes);
651        // then collect static nodes
652        CollectNodes(mStaticRoot, nodes);
653        //CollectNodes(mRoot, nodes);
[3271]654        // also add root
655        nodes.push_back(mRoot);
[2746]656
[2755]657        cout << "creating new indices" << endl;
[2746]658
659        int numMaxIndices = 0;
660
661        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
662
663        for (lit = nodes.begin(); lit != lit_end; ++ lit)
664        {
[3202]665                int offset = (*lit)->mNumTestNodes * NUM_INDICES_PER_BOX;
[2795]666#ifdef ALIGN_INDICES
[3064]667                // align with 32 in order to speed up memcopy
[2746]668                offset = (offset / 32) * 32 + 32;
669#endif
670                numMaxIndices += offset;
671        }
672
[2755]673        cout << "creating global indices buffer" << endl;
[2746]674
[3202]675        if (mIndices)     delete [] mIndices;
[2746]676        if (mTestIndices) delete [] mTestIndices;
677
678        // global buffer: create it once so we don't have
[3202]679        // to allocate memory for each individual chunk of the node
[2746]680        mIndices = new unsigned int[numMaxIndices];
681        // create new index buffer for the individual nodes
682        mTestIndices = new unsigned int[numMaxIndices];
683       
684        mCurrentIndicesPtr = 0;
685
686        for (lit = nodes.begin(); lit != lit_end; ++ lit)
687        {
688                BvhNode *node = *lit;
689               
690                // resize array
691                node->mIndicesPtr = mCurrentIndicesPtr;
692                int numIndices = 0;
693
[3065]694                // the bounding boxes of the test nodes are rendered instead of the node itself
[2746]695                // => store their indices
[3202]696                for (int i = 0; i < node->mNumTestNodes; ++ i, numIndices += NUM_INDICES_PER_BOX)
[2746]697                {
[2755]698                        BvhNode *testNode = mTestNodes[node->mTestNodesIdx + i];
[2746]699
[3202]700                        // add vertex indices of boxes to root node
701                        for (int j = 0; j < NUM_INDICES_PER_BOX; ++ j)
[2746]702                        {
703                                mTestIndices[mCurrentIndicesPtr + numIndices + j] = sIndices[j] + testNode->GetId() * 8;
704                        }
705                }
706
707                // align with 32
[2795]708#ifdef ALIGN_INDICES
[2746]709                const int offset = (numIndices / 32) * 32 + 32;
710#else
711                const int offset = numIndices;
712#endif
713                mCurrentIndicesPtr += offset;
714        }
715}
716
717
718void Bvh::ComputeIds()
719{
[2756]720        // collect all nodes
[2755]721        BvhNodeContainer nodes;
[3074]722        //CollectNodes(mRoot, nodes);
723        // first collect dynamic nodes so we make sure that they are in the beginning
724        CollectNodes(mDynamicRoot, nodes);
725        // then collect static nodes
726        CollectNodes(mStaticRoot, nodes);
727        // also add root
728        nodes.push_back(mRoot);
[2746]729
[3074]730        // assign ids to all nodes of the hierarchy
[2746]731        int i = 0;
[2756]732        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
[2746]733
734        for (lit = nodes.begin(); lit != lit_end; ++ lit, ++ i)
735        {
736                (*lit)->SetId(i);
737        }
738}
739
[2756]740
[2746]741void Bvh::PrepareVertices()
742{
[2755]743        // collect all nodes
744        BvhNodeContainer nodes;
[2746]745
[3073]746        nodes.reserve(GetNumNodes());
[3074]747        // first collect dynamic nodes so we make sure that they are in the beginning
748        CollectNodes(mDynamicRoot, nodes);
749        // then collect static nodes
750        CollectNodes(mStaticRoot, nodes);
751        // also add root
752        nodes.push_back(mRoot);
[2746]753
754        const unsigned int bufferSize = 8 * (int)nodes.size();
[2755]755        mVertices = new Vector3[bufferSize];
[2746]756       
757        int i = 0;
758       
759        // store bounding box vertices
[2755]760        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
[2746]761
762        for (lit = nodes.begin(); lit != lit_end; ++ lit, i += 8)
763        {
[2755]764                BvhNode *node = *lit;
[3202]765                Vector3 v;
766
[2746]767                for (int j = 0; j < 8; ++ j)
[3202]768                {
769                        node->GetBox().GetVertex2(j, v);
770                        (static_cast<Vector3 *>(mVertices))[node->GetId() * 8 + j] = v;
771                }
[2746]772        }
773
[2773]774        glGenBuffersARB(1, &mVboId);
775        glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
776        glVertexPointer(3, GL_FLOAT, 0, (char *)NULL);
[2746]777       
[2773]778        glBufferDataARB(GL_ARRAY_BUFFER_ARB,
779                            bufferSize * sizeof(Vector3),
780                            mVertices,
[3074]781                                        //GL_STATIC_DRAW_ARB);
782                                        GL_DYNAMIC_DRAW_ARB);
[2746]783
[2800]784        glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
[2746]785
[2773]786        // data handled by graphics driver from now on
[3074]787        DEL_ARRAY_PTR(mVertices);
[2746]788
[3064]789        cout << "******** created vbos for tighter bounds *********" << endl;
[2746]790}
791
792
[3074]793void Bvh::UpdateDynamicBounds(RenderState *state)
794{
795        // vbos not created yet
796        if (mVboId == -1) return;
797
798        // collect all nodes
799        static BvhNodeContainer nodes;
800        nodes.clear();
[3259]801
[3074]802        CollectNodes(mDynamicRoot, nodes);
[3271]803        // also add root
804        nodes.push_back(mRoot);
[3074]805
806        const unsigned int bufferSize = 8 * (int)nodes.size();
807        if (!mVertices) mVertices = new Vector3[bufferSize];
808       
809        int i = 0;
810       
811        // store bounding box vertices
812        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
813
814        for (lit = nodes.begin(); lit != lit_end; ++ lit, i += 8)
815        {
816                BvhNode *node = *lit;
817
818                for (int j = 0; j < 8; ++ j)
[3271]819                {
[3074]820                        (static_cast<Vector3 *>(mVertices))[node->GetId() * 8 + j] = node->GetBox().GetVertex(j);
[3271]821                }
[3074]822        }
823       
824        if (state->GetCurrentVboId() != mVboId)
825        {
826                glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
827                // set the vertex pointer to the vertex buffer
828                glVertexPointer(3, GL_FLOAT, 0, (char *)NULL); 
829                state->SetCurrentVboId(mVboId);
830        }
831
832        glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0,
833                                           bufferSize * sizeof(Vector3),
834                                           mVertices);
835}
836
837
[2755]838void Bvh::SetMaxDepthForTestingChildren(int maxDepth)
[2746]839{
840        if (maxDepth != mMaxDepthForTestingChildren)
841        {
842                mMaxDepthForTestingChildren = maxDepth;
843                RecomputeBounds();
844        }
845}
846
847
[2755]848void Bvh::SetAreaRatioThresholdForTestingChildren(float ratio)
[2746]849{
850        if (ratio != mAreaRatioThreshold)
851        {
852                mAreaRatioThreshold = ratio;
853                RecomputeBounds();
854        }
855}
856
857
858void Bvh::RecomputeBounds()
859{
860        // collect all nodes
861        BvhNodeContainer nodes;
[3065]862        CollectNodes(mRoot, nodes);
[2746]863
[3269]864        cout << "\nrecomputing bounds, children will be tested in depth " << mMaxDepthForTestingChildren << endl;
[2746]865
866        int success = 0;
867        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
868
869        for (lit = nodes.begin(); lit != lit_end; ++ lit)
870        {
871                BvhNode *node = *lit;
872
[2795]873                // recreate list of nodes that will be queried as a proxy
[2755]874                if (CreateNodeRenderList(node))
875                        ++ success;
[2746]876        }
877
[2755]878        float p = 100.0f * (float)success / nodes.size();
879        cout << "created tighter bounds for " << p << " percent of the nodes" << endl;
[2746]880
[3267]881        // recreate indices used for indirect rendering mode
[2894]882        if (mIndices) CreateIndices();
[2746]883}
884
885       
886bool Bvh::CreateNodeRenderList(BvhNode *node)
887{
[2755]888        BvhNodeContainer children;
[2746]889
[2755]890        // collect nodes that will be tested instead of the leaf node
891        // in order to get a tighter bounding box test
892        CollectNodes(node, children, mMaxDepthForTestingChildren);
893       
[2746]894
895        // using the tighter bounds is not feasable in case
896        // that the tighter bounds represent nearly the same projected area
[3064]897        // as the old bounding box. Test this property using either
898        // volume or area heuristics
[2746]899
900        float vol = 0;
901        float area = 0;
902
[2755]903        BvhNodeContainer::const_iterator cit;
[2746]904
905        for (cit = children.begin(); cit != children.end(); ++ cit)
[2755]906                area += (*cit)->GetBox().SurfaceArea();
[2746]907
[2755]908        const float areaRatio = area / node->GetBox().SurfaceArea();
[2746]909       
910        bool success;
911
[2755]912        if (areaRatio < mAreaRatioThreshold)
[2746]913                success = true;
914        else
915        {
916                // hack: only store node itself
917                children.clear();
918                children.push_back(node);
919
920                success = false;
921        }
922
923        // the new test nodes are added at the end of the vector
[2755]924        node->mTestNodesIdx = (int)mTestNodes.size();
[2746]925
[3072]926        // use the collected nodes as proxy for the occlusion tests
[2746]927        for (cit = children.begin(); cit != children.end(); ++ cit)
928        {
[2755]929                BvhNode *child = *cit;
[2746]930                mTestNodes.push_back(child);
931        }
932
933        node->mNumTestNodes = (int)children.size();
934
935        return success;
936}
937
938
939void Bvh::ResetNodeClassifications()
940{
941        BvhNodeContainer nodes;
942
943        nodes.reserve(GetNumNodes());
944        CollectNodes(mRoot, nodes);
945
946        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
947
948        for (lit = nodes.begin(); lit != lit_end; ++ lit)
949        {
950                (*lit)->ResetVisibility();
951        }
952}
953
954
[3070]955void Bvh::ComputeBvhStats(BvhNode *root, BvhStats &bvhStats)
[2746]956{
[3070]957        bvhStats.Reset();
[2746]958        std::stack<BvhNode *> nodeStack;
[3070]959        nodeStack.push(root);
[2746]960
[2786]961        int numVirtualLeaves = 0;
[3070]962        int numGeometry = 0;
[3267]963
[2746]964        while (!nodeStack.empty())
965        {
966                BvhNode *node = nodeStack.top();
967                nodeStack.pop();
968
[2773]969                if (node->IsVirtualLeaf())
[2746]970                {
[2786]971                        ++ numVirtualLeaves;
[3070]972                        numGeometry += node->CountPrimitives();
[2786]973
[2746]974                        BvhLeaf *leaf = static_cast<BvhLeaf *>(node);
975
[3070]976                        bvhStats.mTriangles += CountTriangles(leaf);
977                        bvhStats.mLeafSA += leaf->mBox.SurfaceArea();
978                        bvhStats.mLeafVol += leaf->mBox.GetVolume();
[2746]979                }
980                else
981                {
[3070]982                        bvhStats.mInteriorSA += node->mBox.SurfaceArea();
983                        bvhStats.mInteriorVol += node->mBox.GetVolume();
[2746]984
985                        BvhInterior *interior = static_cast<BvhInterior *>(node);
986                       
987                        nodeStack.push(interior->mBack);
988                        nodeStack.push(interior->mFront);
989                }
990        }
991
[3070]992        bvhStats.mGeometryRatio = (float)numGeometry / numVirtualLeaves;
993        bvhStats.mTriangleRatio = (float)bvhStats.mTriangles / numVirtualLeaves;
994        bvhStats.mLeaves = numVirtualLeaves;
[2746]995}
996
997
[3266]998void Bvh::PrintBvhStats(const BvhStats &bvhStats, BvhNode *root) const
[2746]999{
[3266]1000        cout << "interiorNodesSA = " << bvhStats.mInteriorSA / root->mBox.SurfaceArea() << endl;
1001        cout << "leafNodesSA = " << bvhStats.mLeafSA / root->mBox.SurfaceArea() << endl;
1002        cout << "interiorNodesVolume = " << bvhStats.mInteriorVol / root->mBox.GetVolume() << endl;
1003        cout << "leafNodesVolume = " << bvhStats.mLeafVol / root->mBox.GetVolume() << endl;
[2746]1004
[3070]1005        cout << "geometry per leaf: " << bvhStats.mGeometryRatio << endl;
1006        cout << "triangles per leaf: " << bvhStats.mTriangleRatio << endl;
1007        cout << "===========================================" << endl << endl;
[2746]1008}
1009
1010
1011int Bvh::CountTriangles(BvhNode *node) const
1012{
1013        int numTriangles = 0;
1014
1015        for (int i = node->mFirst; i <= node->mLast; ++ i)
[2774]1016        {
[2848]1017                numTriangles += mGeometry[i]->CountNumTriangles(0);
[2774]1018        }
1019
[2746]1020        return numTriangles;
1021}
1022
1023
[2756]1024float Bvh::GetArea(BvhNode *node) const
[2746]1025{
1026        return node->mArea;
1027}
1028
[2760]1029
1030void Bvh::UpdateNumLeaves(BvhNode *node) const
1031{
1032        if (node->IsLeaf())
1033        {
1034                node->mNumLeaves = 1;
1035        }
1036        else
1037        {
1038                BvhNode *f = static_cast<BvhInterior *>(node)->GetFront();
1039                BvhNode *b = static_cast<BvhInterior *>(node)->GetBack();
1040
1041                UpdateNumLeaves(f);
1042                UpdateNumLeaves(b);
1043
1044                node->mNumLeaves = f->mNumLeaves + b->mNumLeaves;
1045        }
[2746]1046}
[2760]1047
1048
[2761]1049void Bvh::CollectVirtualLeaves(BvhNode *node, BvhNodeContainer &leaves)
1050{
1051        stack<BvhNode *> tStack;
1052        tStack.push(node);
1053
1054        while (!tStack.empty())
1055        {
1056                BvhNode *node = tStack.top();
1057                tStack.pop();
1058
1059                if (node->mIsVirtualLeaf)
1060                {
1061                        leaves.push_back(node);
1062                }
1063                else if (!node->IsLeaf())
1064                {
1065                        BvhInterior *interior = static_cast<BvhInterior *>(node);
1066
1067                        tStack.push(interior->mFront);
1068                        tStack.push(interior->mBack);
1069                }
1070        }
[2760]1071}
[2761]1072
1073
1074void Bvh::SetVirtualLeaves(int numTriangles)
1075{
[3064]1076        // first invalidate old virtual leaves
[2761]1077        BvhNodeContainer leaves;
[3065]1078        CollectVirtualLeaves(mRoot, leaves);
[2761]1079
1080        BvhNodeContainer::const_iterator bit, bit_end = leaves.end();
1081
1082        for (bit = leaves.begin(); bit != bit_end; ++ bit)
1083        {
1084                (*bit)->mIsVirtualLeaf = false;
1085        }
1086
[2764]1087        mNumVirtualNodes = 0;
[3064]1088        // assign new virtual leaves based on specified #triangles per leaf
[2761]1089        std::stack<BvhNode *> nodeStack;
[3267]1090        nodeStack.push(mStaticRoot);
1091        nodeStack.push(mDynamicRoot);
[2761]1092
1093        while (!nodeStack.empty())
1094        {
1095                BvhNode *node = nodeStack.top();
1096                nodeStack.pop();
1097
[2764]1098                ++ mNumVirtualNodes;
1099
[2761]1100                if (node->IsLeaf())
1101                {
1102                        BvhLeaf *leaf = static_cast<BvhLeaf *>(node);
1103                        leaf->mIsVirtualLeaf = true;
1104                }
1105                else
1106                {
1107                        BvhInterior *interior = static_cast<BvhInterior *>(node);
1108
1109                        BvhNode *f = interior->mFront;
1110                        BvhNode *b = interior->mBack;
1111
[3064]1112                        if (node->mIsMaxDepthForVirtualLeaf ||
1113                                (CountTriangles(node) <= numTriangles))
[2761]1114                        {
[3267]1115                                //cout << " l " << CountTriangles(node) << " " << node->mIsMaxDepthForVirtualLeaf << endl;
[3266]1116                                node->mIsVirtualLeaf = true;
[2761]1117                        }
1118                        else
1119                        {
1120                                nodeStack.push(interior->mBack);
1121                                nodeStack.push(interior->mFront);
1122                        }
1123                }
1124        }
[2800]1125
[3064]1126        /// Reset the node states
[2800]1127        ResetNodeClassifications();
[2761]1128}
1129
1130
[3072]1131void Bvh::ComputeMaxDepthForVirtualLeaves()
[2761]1132{
[3072]1133        // We initialize the maximal depth for virtual leaves
[3064]1134        // of this bvh, i.e., the nodes that are used as
1135        // leaves of the hierarchy during traversal.
1136
1137        // Initially they are set either
1138        // a) to the real leaves of the hierarchy or
1139        // b) the point where the subdivision on object level ends
1140        // and the subsequent nodes are just used to provide tighter bounds
1141        // (see article for the notations)
1142
[2761]1143        std::stack<BvhNode *> nodeStack;
1144
[3267]1145        nodeStack.push(mStaticRoot);
1146        nodeStack.push(mDynamicRoot);
1147
[2761]1148        while (!nodeStack.empty())
1149        {
1150                BvhNode *node = nodeStack.top();
1151                nodeStack.pop();
[3267]1152
[2761]1153                if (node->IsLeaf())
1154                {
1155                        node->mIsMaxDepthForVirtualLeaf = true;
1156                }
1157                else
1158                {
1159                        BvhInterior *interior = static_cast<BvhInterior *>(node);
1160
1161                        BvhNode *f = interior->mFront;
1162                        BvhNode *b = interior->mBack;
1163
1164                        if ((f->mFirst == b->mFirst) && (f->mLast == b->mLast))
1165                        {
[3064]1166                                // point reached where beyond there would be no further reduction
1167                                // as both subtrees contain the same objects => stop here
1168                                // The tree beyond the current node is used to describe
1169                                // tighter bounds on the geometry contained  in it
[2761]1170                                node->mIsMaxDepthForVirtualLeaf = true;
1171                        }
1172                        else
1173                        {
1174                                nodeStack.push(f);
1175                                nodeStack.push(b);
1176                        }
1177                }
1178        }
1179}
1180
1181
[3072]1182// this function must be called once after hierarchy creation
1183void Bvh::PostProcess()
1184{
1185        CreateRoot();
1186
1187        ComputeMaxDepthForVirtualLeaves();
1188        // set virtual leaves for specified number of triangles
1189        SetVirtualLeaves(INITIAL_TRIANGLES_PER_VIRTUAL_LEAVES);
1190        /// for each node compute the number of leaves under this node
1191        UpdateNumLeaves(mRoot);
[3074]1192        // compute new ids
1193        ComputeIds();
[3072]1194        // specify bounds for occlusion tests
1195        RecomputeBounds();
1196
[3074]1197        mBox = mRoot->GetBox();
1198
[3244]1199        // compute and print stats for whole (static + dynamic) bvh
[3072]1200        ComputeBvhStats(mRoot, mBvhStats);
1201
[3266]1202        BvhStats staticBvhStats;
[3267]1203        ComputeBvhStats(mStaticRoot, staticBvhStats);
[3266]1204        cout << "\n============ Static BVH statistics =============" << endl;
1205
1206        PrintBvhStats(staticBvhStats, mStaticRoot);
1207
[3244]1208        // also output dynamic stats
[3072]1209        if (mDynamicGeometrySize)
1210        {
[3266]1211                BvhStats dynBvhStats;
1212                ComputeBvhStats(mDynamicRoot, dynBvhStats);
1213       
[3072]1214                cout << "\n=========== Dynamic BVH statistics: =========" << endl;
[3266]1215                PrintBvhStats(dynBvhStats, mDynamicRoot);
[3072]1216        }
1217}
1218
1219
[2763]1220void Bvh::RenderBoundingBoxImmediate(const AxisAlignedBox3 &box)
1221{
1222        const Vector3 l = box.Min();
1223        const Vector3 u = box.Max();
1224
[3065]1225        ///////////
1226        //-- render AABB as triangle strips
1227
[2764]1228        glBegin(GL_TRIANGLE_STRIP);
[2763]1229
[3065]1230        // render first half of AABB
1231        glVertex3f(l.x, l.y, u.z);
1232        glVertex3f(u.x, l.y, u.z);
1233        glVertex3f(l.x, u.y, u.z);
1234        glVertex3f(u.x, u.y, u.z);
1235        glVertex3f(l.x, u.y, l.z);
1236        glVertex3f(u.x, u.y, l.z);
1237        glVertex3f(l.x, l.y, l.z);
1238        glVertex3f(u.x, l.y, l.z);
[2763]1239
[3065]1240        glPrimitiveRestartNV();
[2763]1241
[3065]1242        // render second half of AABB
1243        glVertex3f(l.x, u.y, u.z);
1244        glVertex3f(l.x, u.y, l.z);
1245        glVertex3f(l.x, l.y, u.z);
1246        glVertex3f(l.x, l.y, l.z);
1247        glVertex3f(u.x, l.y, u.z);
1248        glVertex3f(u.x, l.y, l.z);
1249        glVertex3f(u.x, u.y, u.z);
1250        glVertex3f(u.x, u.y, l.z);
1251
[2764]1252        glEnd();
[2761]1253}
[2763]1254
[2790]1255
1256static void RenderBoxForViz(const AxisAlignedBox3 &box)
1257{
1258        glBegin(GL_LINE_LOOP);
1259        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
1260        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
1261        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
1262        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
1263        glEnd();
1264
1265        glBegin(GL_LINE_LOOP);
1266        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
1267        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
1268        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
1269        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
1270        glEnd();
1271
1272        glBegin(GL_LINE_LOOP);
1273        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
1274        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
1275        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
1276        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
1277        glEnd();
1278
1279        glBegin(GL_LINE_LOOP);
1280        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
1281        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
1282        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
1283        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
1284        glEnd();
1285
1286        glBegin(GL_LINE_LOOP);
1287        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
1288        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
1289        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
1290        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
1291        glEnd();
1292
1293        glBegin(GL_LINE_LOOP);
1294        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
1295        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
1296        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
1297        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
1298
1299        glEnd();
1300}
1301
1302
[3066]1303static Technique GetVizTechnique()
1304{
1305        Technique tech;
1306        tech.Init();
1307
1308        //tech.SetLightingEnabled(false);
1309        //tech.SetDepthWriteEnabled(false);
1310
1311        tech.SetEmmisive(RgbaColor(1.0f, 1.0f, 1.0f, 1.0f));
1312        tech.SetDiffuse(RgbaColor(1.0f, 1.0f, 1.0f, 1.0f));
1313        tech.SetAmbient(RgbaColor(1.0f, 1.0f, 1.0f, 1.0f));
1314
1315        return tech;
1316}
1317
1318
[3064]1319void Bvh::RenderBoundsForViz(BvhNode *node,
1320                                                         RenderState *state,
1321                                                         bool useTightBounds)
[2790]1322{
[3066]1323        Technique *oldTech = state->GetState();
1324        // we set a simple material
1325        static Technique boxMat = GetVizTechnique();
[2825]1326        boxMat.Render(state);
1327
[2790]1328        if (!useTightBounds)
1329        {
[3245]1330#if 1
[3066]1331                RenderBoxForViz(node->GetBox());
[3245]1332#else
1333                glPolygonMode(GL_FRONT, GL_LINE);
[3065]1334                RenderBoundingBoxImmediate(node->GetBox());
[3245]1335                glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1336#endif
[2790]1337        }
1338        else
1339        {
[3203]1340                for (int i = 0; i < node->mNumTestNodes; ++ i)
[2790]1341                {
1342                        RenderBoxForViz(mTestNodes[node->mTestNodesIdx + i]->GetBox());
[3203]1343                }
[2790]1344        }
[3066]1345
1346        if (oldTech) oldTech->Render(state);
[2790]1347}
1348
1349
1350
[3053]1351
[3266]1352bool Bvh::IntersectsNearPlane(BvhNode *node) const
1353{
1354        // note: we have problems with large scale object penetrating the near plane
1355        // (e.g., objects in the distance which are always handled to be visible)
1356        // especially annoying is this problem when using the frustum
1357        // fitting on the visible objects for shadow mapping
1358        // but don't see how to solve this issue without using costly calculations
1359       
1360        // we stored the near plane distance => we can use it also here
1361        float distanceToNearPlane = node->GetDistance();
1362        //float distanceToNearPlane = node->GetBox().GetMinDistance(sNearPlane);
1363       
1364        return (distanceToNearPlane < sNear);
[3053]1365}
1366
1367
[3266]1368void Bvh::CreateRoot()
[3053]1369{
[3266]1370        // create new root
1371        mRoot = new BvhInterior(NULL);
[3053]1372
[3266]1373        // the separation is a purely logical one
1374        // the bounding boxes of the child nodes are
1375        // identical to those of the root node
[3053]1376
[3266]1377        mRoot->mBox = mStaticRoot->mBox;
1378        mRoot->mBox.Include(mDynamicRoot->mBox);
[3064]1379
[3266]1380        mRoot->mArea = mRoot->mBox.SurfaceArea();
[3053]1381
[3266]1382        mRoot->mFirst = 0;
1383        mRoot->mLast = (int)mGeometrySize - 1;
[3070]1384
[3266]1385        //cout<<"f: " << mRoot->mFirst<< " l: " <<mRoot->mLast << endl;
1386        // add static root on left subtree
1387        mRoot->mFront = mStaticRoot;
1388        mStaticRoot->mParent = mRoot;
[3053]1389
[3266]1390        // add dynamic root on left subtree
1391        mRoot->mBack = mDynamicRoot;
1392        mDynamicRoot->mParent = mRoot;
[3053]1393}
[3266]1394 
[3053]1395
1396
1397
[3266]1398////////////////////////
1399//-- dynamic hierarchy stuff
[3053]1400
1401
[3267]1402void Bvh::UpdateBoundingBoxes(BvhNode *node)
[3053]1403{
[3070]1404        if (node->IsLeaf())
1405        {
1406                int numEntities;
1407                SceneEntity **entities = GetGeometry(node, numEntities);
1408
[3262]1409                node->mBox = SceneEntity::ComputeBoundingBox(entities, numEntities);
[3070]1410                //cout << "box: " << node->mBox << endl;
1411        }
1412        else
1413        {
1414                BvhNode *f = static_cast<BvhInterior *>(node)->GetFront();
1415                BvhNode *b = static_cast<BvhInterior *>(node)->GetBack();
1416
[3267]1417                UpdateBoundingBoxes(f);
1418                UpdateBoundingBoxes(b);
[3070]1419
1420                node->mBox = f->mBox;
1421                node->mBox.Include(b->mBox);
1422        }
1423}
1424
1425
1426void Bvh::CreateDynamicBranch()
1427{
[3069]1428        // the bvh has two main branches
[3262]1429        // a static branch (the old root), and a dynamic branch
[3069]1430        // we create a 'dynamic' leaf which basically is a container
1431        // for all dynamic objects underneath
1432
1433        // the bounding boxes of the dynamic tree must be updated
1434        // once each frame in order to be able to incorporate
1435        // the movements of the objects within
1436
[3269]1437       
1438        cout << "\n==============================" << endl;
[3264]1439        cout << "creating dynamic bvh branch"  << endl;
1440
[3069]1441        DEL_PTR(mDynamicRoot);
[3264]1442        -- mNumNodes;
[3053]1443
[3264]1444        BvhConstructor bvhConstructor(mGeometry, (int)mStaticGeometrySize, (int)mGeometrySize - 1);
1445
1446        int numNodes;
1447        mDynamicRoot = bvhConstructor.Construct(numNodes);
1448
1449        mNumNodes += numNodes;
[3053]1450}
1451
[3267]1452
1453
1454
[2764]1455}
Note: See TracBrowser for help on using the repository browser.