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

Revision 3071, 31.9 KB checked in by mattausch, 16 years ago (diff)

worked on dynamic objects

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