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

Revision 3064, 28.5 KB checked in by mattausch, 16 years ago (diff)

working on dynamic bvh hierarchy: denug version

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