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

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