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

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