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

Revision 3072, 32.8 KB checked in by mattausch, 16 years ago (diff)

fucked up depth order for some reason!!

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