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

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