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

Revision 3214, 35.3 KB checked in by mattausch, 16 years ago (diff)

worked on lense flare

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