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

Revision 2795, 22.1 KB checked in by mattausch, 16 years ago (diff)
Line 
1#include <queue>
2#include <stack>
3#include <fstream>
4#include <iostream>
5#include <iomanip>
6
7#include "Bvh.h"
8#include "Camera.h"
9#include "Plane3.h"
10#include "glInterface.h"
11#include "Triangle3.h"
12#include "SceneEntity.h"
13#include "Geometry.h"
14#include "RenderState.h"
15#include "gzstream.h"
16
17
18namespace CHCDemoEngine
19{
20
21#define INVALID_TEST ((unsigned int)-1)
22
23using namespace std;
24
25
26
27/*
283 x---------x 2
29  |\         \
30  | \         \
31  |  \         \
32  |     4 x---------x 5
33  |   |         |
340 x   |     x 1 |
35   \  |         |
36    \ |         |
37     \|         |
38        7 x---------x 6             
39*/
40
41static unsigned int sIndices[] =       
42{7, // degenerated
43 7, 6, 4, 5, 3, 2, 0, 1,
44 1, 4, // degenerated
45 4, 3, 7, 0, 6, 1, 5, 2,
46 2 // degenerated
47};
48
49
50const static int sNumIndicesPerBox = 20;
51
52/*      Order of vertices
53        0 = (0, 0, 0)
54        1 = (1, 0, 0)
55        2 = (1, 1, 0)
56        3 = (0, 1, 0)
57        4 = (0, 1, 1)
58        5 = (1, 1, 1)
59        6 = (1, 0, 1)
60        7 = (0, 0, 1)
61*/
62
63static Plane3 sNearPlane;
64static Camera::Frustum sFrustum;
65
66/// these values are valid for all nodes
67static int sClipPlaneAABBVertexIndices[12];
68
69
70#define ALIGN_INDICES
71
72BvhNode::BvhNode(BvhNode *parent):
73mParent(parent),
74mAxis(-1),
75mDepth(0),
76mPlaneMask(0),
77mPreferredPlane(0),
78mLastRenderedFrame(-999),
79mFirst(-1),
80mLast(-1),
81mNumTestNodes(1),
82mTestNodesIdx(-1),
83mIndicesPtr(-1),
84mId(0),
85mIsMaxDepthForVirtualLeaf(false),
86mIsVirtualLeaf(false)
87{
88}
89
90
91BvhNode::~BvhNode()
92{
93}
94
95
96void BvhNode::ResetVisibility()
97{
98        mVisibility.Reset();
99        mLastRenderedFrame = -999;
100}
101
102
103void BvhNode::VisibilityInfo::Reset()
104{
105        mIsVisible = false;
106        mAssumedVisibleFrameId = 0;
107        mLastVisitedFrame = -1;
108        mTimesInvisible = 0;
109        mIsFrustumCulled = false;
110        mIsNew = true;
111}
112
113
114BvhInterior::~BvhInterior()
115{
116        DEL_PTR(mBack);
117        DEL_PTR(mFront);
118}
119
120
121BvhLeaf::~BvhLeaf()
122{
123}
124
125
126/***********************************************************/
127/*                class Bvh implementation                 */
128/***********************************************************/
129
130
131Bvh::Bvh()
132{
133        Init();
134}
135
136
137Bvh::Bvh(const SceneEntityContainer &entities)
138{
139        Init();
140
141        mGeometrySize = entities.size();
142        mGeometry = new SceneEntity*[mGeometrySize];
143       
144        mBox.Initialize();
145
146        SceneEntityContainer::const_iterator it, it_end = entities.end();
147
148        int i = 0;
149        for (it = entities.begin(); it != it_end; ++ it, ++ i)
150        {
151                mGeometry[i] = (*it);
152                mBox.Include((*it)->GetBoundingBox());
153        }
154
155        cout << "scene box: " << mBox << endl;
156}
157
158
159Bvh::~Bvh()
160{
161        if (mVertices) delete [] mVertices;
162        if (mIndices) delete [] mIndices;
163        if (mTestIndices) delete [] mTestIndices;
164        if (mGeometry) delete [] mGeometry;
165
166        if (mRoot) delete mRoot;
167
168        // delete vbo
169        glDeleteBuffersARB(1, &mVboId);
170}
171
172
173void Bvh::Init()
174{
175        mCamera = NULL;
176        mRoot = NULL;
177        mVertices = NULL;
178        mIndices = NULL;
179        mTestIndices = NULL;
180        mCurrentIndicesPtr = 0;
181        mNumNodes = 0;
182       
183        mMaxDepthForTestingChildren = 3;
184        //mMaxDepthForTestingChildren = 4;
185        mAreaRatioThreshold = 2.0f;
186        //mAreaRatioThreshold = 1.4f;
187
188        mVboId = -1;
189}
190
191
192void Bvh::PullUpLastVisited(BvhNode *node, const int frameId) const
193{               
194        BvhNode *parent = node->GetParent();
195
196        while (parent && (parent->GetLastVisitedFrame() != frameId))
197        {
198                parent->SetLastVisitedFrame(frameId);
199                parent = parent->GetParent();
200        }
201}
202
203
204void Bvh::MakeParentsVisible(BvhNode *node)
205{
206        BvhNode *parent = node->GetParent();
207
208        while (parent && (!parent->IsVisible()))
209        {
210                parent->SetVisible(true);
211                parent = parent->GetParent();
212        }
213}
214
215
216void Bvh::CollectLeaves(BvhNode *node, BvhLeafContainer &leaves)
217{
218        stack<BvhNode *> tStack;
219        tStack.push(node);
220
221        while (!tStack.empty())
222        {
223                BvhNode *node = tStack.top();
224
225                tStack.pop();
226
227                if (!node->IsLeaf())
228                {
229                        BvhInterior *interior = static_cast<BvhInterior *>(node);
230
231                        tStack.push(interior->mFront);
232                        tStack.push(interior->mBack);
233                }
234                else
235                {
236                        leaves.push_back(static_cast<BvhLeaf *>(node));
237                }
238        }
239}
240
241
242void Bvh::CollectNodes(BvhNode *node, BvhNodeContainer &nodes)
243{
244        stack<BvhNode *> tStack;
245
246        tStack.push(node);
247
248        while (!tStack.empty())
249        {
250                BvhNode *node = tStack.top();
251                tStack.pop();
252
253                nodes.push_back(node);
254
255                if (!node->IsLeaf())
256                {
257                        BvhInterior *interior = static_cast<BvhInterior *>(node);
258
259                        tStack.push(interior->mFront);
260                        tStack.push(interior->mBack);
261                }
262        }
263}
264
265
266typedef pair<BvhNode *, int> tPair;
267
268void Bvh::CollectNodes(BvhNode *root, BvhNodeContainer &nodes, int depth)
269{
270        stack<tPair> tStack;
271        tStack.push(tPair(root, 0));
272
273        while (!tStack.empty())
274        {
275                BvhNode *node = tStack.top().first;
276                const int d = tStack.top().second;
277
278                tStack.pop();
279
280                // found depth => take this node
281                if ((d == depth) || (node->IsLeaf()))
282                {
283                        nodes.push_back(node);
284                }
285                else
286                {
287                        BvhInterior *interior = static_cast<BvhInterior *>(node);
288
289                        tStack.push(tPair(interior->mFront, d + 1));
290                        tStack.push(tPair(interior->mBack, d + 1));
291                }
292        }
293}
294
295
296SceneEntity **Bvh::GetGeometry(BvhNode *node, int &geometrySize)
297{
298        geometrySize = node->CountPrimitives();
299        return mGeometry + node->mFirst;
300}
301
302
303bool Bvh::TestPlane(BvhNode *node, int i, bool &bIntersect)
304{
305        // do the test only if necessary
306        if (!(node->mPlaneMask & (1 << i)))
307                return true;
308                       
309        ////////
310        //-- test the n-vertex
311               
312        if ((node->mBox.GetDistance(sClipPlaneAABBVertexIndices[i * 2 + 0], sFrustum.mClipPlanes[i]) > 0.0f))
313        {
314                // outside
315                node->mPreferredPlane = i;
316                return false;
317        }
318
319        ////////////
320        //-- test the p-vertex
321
322        if (node->mBox.GetDistance(sClipPlaneAABBVertexIndices[i * 2 + 1], sFrustum.mClipPlanes[i]) <= 0.0f)
323        {
324                // completely inside: children don't need to check against this plane no more
325                node->mPlaneMask^= 1 << i;
326        }
327        else
328        {
329                bIntersect = true;
330        }
331       
332        return true;
333}
334
335
336int     Bvh::IsWithinViewFrustum(BvhNode *node)
337{
338        bool bIntersect = false;
339
340        if (node->GetParent())
341                node->mPlaneMask = node->GetParent()->mPlaneMask;
342
343
344        //for (int i = 0; i < 6; ++ i)
345        //      if (!TestPlane(node, i, bIntersect)) return 0;
346       
347
348        ////////
349        //-- apply frustum culling for the planes [mPreferredPlane - 5]
350
351        for (int i = node->mPreferredPlane; i < 6; ++ i)
352                if (!TestPlane(node, i, bIntersect)) return 0;
353       
354        //////////
355        //-- do the view frustum culling for the planes [0 - m_iPreferredPlane)
356
357        for (int i = 0; i < node->mPreferredPlane; ++ i)
358                if (!TestPlane(node, i, bIntersect)) return 0;
359       
360        return bIntersect ? -1 : 1;
361}
362
363
364void Bvh::InitFrame()
365{
366        // = 0011 1111 which means that at the beginning, all six planes have to frustum culled
367        mRoot->mPlaneMask = 0x3f;
368
369        mCamera->CalcFrustum(sFrustum);
370        sFrustum.CalcNPVertexIndices(sClipPlaneAABBVertexIndices);
371
372        // store near plane
373        sNearPlane = Plane3(mCamera->GetDirection(), mCamera->GetPosition());
374}
375
376
377void Bvh::CalcDistance(BvhNode *node) const
378{
379        node->mDistance = node->GetBox().GetMinVisibleDistance(sNearPlane);
380}
381
382
383void Bvh::RenderBounds(BvhNode *node, RenderState *state, bool useTightBounds)
384{
385        // if not using tight bounds, rendering boxes in immediate mode
386        // is preferable to vertex arrays (less setup time)
387        if (!useTightBounds)
388        {
389                RenderBoundingBoxImmediate(node->GetBox());
390        }
391        else
392        {
393                static BvhNodeContainer dummy(1);
394                dummy[0] = node;
395                RenderBounds(dummy, state, useTightBounds);
396        }
397}
398
399
400int Bvh::RenderBounds(const BvhNodeContainer &nodes,
401                                          RenderState *state,
402                                          bool useTightBounds)
403{
404        // if not using tight bounds, rendering boxes in immediate mode
405        // is preferable to vertex arrays (less setup time)
406
407        int renderedBoxes;
408
409        if (!useTightBounds)
410        {
411                BvhNodeContainer::const_iterator nit, nit_end = nodes.end();
412                       
413                for (nit = nodes.begin(); nit != nit_end; ++ nit)
414                {
415                        RenderBoundingBoxImmediate((*nit)->GetBox());
416                }
417
418                renderedBoxes = (int)nodes.size();
419        }
420        else
421        {
422                renderedBoxes = PrepareBoundsWithDrawArrays(nodes);
423                RenderBoundsWithDrawArrays(renderedBoxes, state);
424        }
425
426        return renderedBoxes;
427}
428
429
430int Bvh::PrepareBoundsWithDrawArrays(const BvhNodeContainer &nodes)
431{
432        //////
433        //-- for the first time we come here ...
434
435        if (!mIndices)
436        {       // create list of indices
437                CreateIndices();
438        }
439
440        if (mVboId == -1)
441        {       
442                // prepare the vbo
443                PrepareVertices();
444        }
445
446        ///////////////
447
448        int numNodes = 0;
449
450        BvhNodeContainer::const_iterator nit, nit_end = nodes.end();
451
452        for (nit = nodes.begin(); nit != nit_end; ++ nit)
453        {
454                BvhNode *node = *nit;
455
456        const int numIndices = node->mNumTestNodes * sNumIndicesPerBox;
457               
458                // copy indices
459                memcpy(mIndices + numNodes * sNumIndicesPerBox,
460                           mTestIndices + node->mIndicesPtr,
461                           numIndices * sizeof(unsigned int));
462
463                numNodes += node->mNumTestNodes;
464        }
465
466        return numNodes;
467}
468
469
470void Bvh::RenderBoundsWithDrawArrays(int numNodes, RenderState *state)
471{
472        //////
473        //-- Rendering the vbo
474
475        if (state->GetCurrentVboId() != mVboId)
476        {
477                glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
478                // set the vertex pointer to the vertex buffer
479                glVertexPointer(3, GL_FLOAT, 0, (char *)NULL); 
480
481                state->SetCurrentVboId(mVboId);
482        }
483
484        // we do use the last or the first index (they are generate and only used to connect strips)
485        int numElements = numNodes * sNumIndicesPerBox - 1;
486        // don't render first degenerate index
487        glDrawElements(GL_TRIANGLE_STRIP, numElements, GL_UNSIGNED_INT, mIndices + 1);
488}
489
490
491void Bvh::CreateIndices()
492{
493        // collect bvh nodes
494        BvhNodeContainer nodes;
495        CollectNodes(mRoot, nodes);
496
497        cout << "creating new indices" << endl;
498
499        int numMaxIndices = 0;
500
501        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
502
503        for (lit = nodes.begin(); lit != lit_end; ++ lit)
504        {
505                int offset = (*lit)->mNumTestNodes * sNumIndicesPerBox;
506#ifdef ALIGN_INDICES
507                // align with 32
508                offset = (offset / 32) * 32 + 32;
509#endif
510                numMaxIndices += offset;
511        }
512
513
514        cout << "creating global indices buffer" << endl;
515
516        if (mIndices) delete [] mIndices;
517        if (mTestIndices) delete [] mTestIndices;
518
519        // global buffer: create it once so we don't have
520        // to allocate memory from the chunks of the node
521        mIndices = new unsigned int[numMaxIndices];
522
523        // create new index buffer for the individual nodes
524        mTestIndices = new unsigned int[numMaxIndices];
525       
526        mCurrentIndicesPtr = 0;
527
528        for (lit = nodes.begin(); lit != lit_end; ++ lit)
529        {
530                BvhNode *node = *lit;
531               
532                // resize array
533                node->mIndicesPtr = mCurrentIndicesPtr;
534
535                int numIndices = 0;
536
537                // the bounding box of the test nodes are rendered instead of the root node
538                // => store their indices
539                for (int i = 0; i < node->mNumTestNodes; ++ i, numIndices += sNumIndicesPerBox)
540                {
541                        BvhNode *testNode = mTestNodes[node->mTestNodesIdx + i];
542
543                        // add indices to root node
544                        for (int j = 0; j < sNumIndicesPerBox; ++ j)
545                        {
546                                mTestIndices[mCurrentIndicesPtr + numIndices + j] = sIndices[j] + testNode->GetId() * 8;
547                        }
548                }
549
550                // align with 32
551#ifdef ALIGN_INDICES
552                const int offset = (numIndices / 32) * 32 + 32;
553#else
554                const int offset = numIndices;
555#endif
556                mCurrentIndicesPtr += offset;
557        }
558}
559
560
561void Bvh::ComputeIds()
562{
563        // collect all nodes
564        BvhNodeContainer nodes;
565        CollectNodes(mRoot, nodes);
566
567        // assign ids to all nodes of the "regular" hierarchy
568        int i = 0;
569        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
570
571        for (lit = nodes.begin(); lit != lit_end; ++ lit, ++ i)
572        {
573                (*lit)->SetId(i);
574        }
575}
576
577
578void Bvh::PrepareVertices()
579{
580        // collect all nodes
581        BvhNodeContainer nodes;
582
583        nodes.reserve(GetNumNodes());
584        CollectNodes(mRoot, nodes);
585
586        const unsigned int bufferSize = 8 * (int)nodes.size();
587        mVertices = new Vector3[bufferSize];
588       
589        int i = 0;
590       
591        // store bounding box vertices
592        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
593
594        for (lit = nodes.begin(); lit != lit_end; ++ lit, i += 8)
595        {
596                BvhNode *node = *lit;
597
598                for (int j = 0; j < 8; ++ j)
599                        ((Vector3 *)mVertices)[node->GetId() * 8 + j] = node->GetBox().GetVertex(j);
600        }
601
602        glGenBuffersARB(1, &mVboId);
603        glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
604        glVertexPointer(3, GL_FLOAT, 0, (char *)NULL);
605       
606        glBufferDataARB(GL_ARRAY_BUFFER_ARB,
607                            bufferSize * sizeof(Vector3),
608                            mVertices,
609                                        GL_STATIC_DRAW_ARB);
610
611        //glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
612
613        // data handled by graphics driver from now on
614        DEL_PTR(mVertices);
615
616        cout << "***** created vbos for tighter bounds *********" << endl;
617}
618
619
620void Bvh::SetMaxDepthForTestingChildren(int maxDepth)
621{
622        if (maxDepth != mMaxDepthForTestingChildren)
623        {
624                mMaxDepthForTestingChildren = maxDepth;
625                RecomputeBounds();
626        }
627}
628
629
630void Bvh::SetAreaRatioThresholdForTestingChildren(float ratio)
631{
632        if (ratio != mAreaRatioThreshold)
633        {
634                mAreaRatioThreshold = ratio;
635                RecomputeBounds();
636        }
637}
638
639
640void Bvh::RecomputeBounds()
641{
642        // clear old list
643        mTestNodes.clear();
644
645        // collect all nodes
646        BvhNodeContainer nodes;
647        CollectNodes(mRoot, nodes);
648
649        cout << "recomputing bounds, children will be tested in depth " << mMaxDepthForTestingChildren << endl;
650
651        int success = 0;
652        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
653
654        for (lit = nodes.begin(); lit != lit_end; ++ lit)
655        {
656                BvhNode *node = *lit;
657
658                // recreate list of nodes that will be queried as a proxy
659                if (CreateNodeRenderList(node))
660                        ++ success;
661        }
662
663        float p = 100.0f * (float)success / nodes.size();
664        cout << "created tighter bounds for " << p << " percent of the nodes" << endl;
665
666        // recreate indices used for indirect mode rendering
667        if (mIndices)
668                CreateIndices();
669}
670
671       
672bool Bvh::CreateNodeRenderList(BvhNode *node)
673{
674        BvhNodeContainer children;
675
676        // collect nodes that will be tested instead of the leaf node
677        // in order to get a tighter bounding box test
678        CollectNodes(node, children, mMaxDepthForTestingChildren);
679       
680
681        // using the tighter bounds is not feasable in case
682        // that the tighter bounds represent nearly the same projected area
683        // as the old bounding box. Find this out using either volume or area
684        // heuristics
685
686        float vol = 0;
687        float area = 0;
688
689        BvhNodeContainer::const_iterator cit;
690
691        for (cit = children.begin(); cit != children.end(); ++ cit)
692                area += (*cit)->GetBox().SurfaceArea();
693
694        const float areaRatio = area / node->GetBox().SurfaceArea();
695       
696        bool success;
697
698        if (areaRatio < mAreaRatioThreshold)
699                success = true;
700        else
701        {
702                // hack: only store node itself
703                children.clear();
704                children.push_back(node);
705
706                success = false;
707        }
708
709        // the new test nodes are added at the end of the vector
710        node->mTestNodesIdx = (int)mTestNodes.size();
711
712        // use the found nodes as nodes during the occlusion tests
713        for (cit = children.begin(); cit != children.end(); ++ cit)
714        {
715                BvhNode *child = *cit;
716                mTestNodes.push_back(child);
717        }
718
719        node->mNumTestNodes = (int)children.size();
720
721        return success;
722}
723
724
725void Bvh::ResetNodeClassifications()
726{
727        BvhNodeContainer nodes;
728
729        nodes.reserve(GetNumNodes());
730        CollectNodes(mRoot, nodes);
731
732        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
733
734        for (lit = nodes.begin(); lit != lit_end; ++ lit)
735        {
736                (*lit)->ResetVisibility();
737        }
738}
739
740
741void Bvh::ComputeBvhStats()
742{
743        std::stack<BvhNode *> nodeStack;
744        nodeStack.push(mRoot);
745
746        int numVirtualLeaves = 0;
747
748        while (!nodeStack.empty())
749        {
750                BvhNode *node = nodeStack.top();
751                nodeStack.pop();
752
753                if (node->IsVirtualLeaf())
754                {
755                        ++ numVirtualLeaves;
756
757                        BvhLeaf *leaf = static_cast<BvhLeaf *>(node);
758
759                        mBvhStats.mTriangles += CountTriangles(leaf);
760                        mBvhStats.mLeafSA += leaf->mBox.SurfaceArea();
761                        mBvhStats.mLeafVol += leaf->mBox.GetVolume();
762                }
763                else
764                {
765                        mBvhStats.mInteriorSA += node->mBox.SurfaceArea();
766                        mBvhStats.mInteriorVol += node->mBox.GetVolume();
767
768                        BvhInterior *interior = static_cast<BvhInterior *>(node);
769                       
770                        nodeStack.push(interior->mBack);
771                        nodeStack.push(interior->mFront);
772                }
773        }
774
775        mBvhStats.mGeometryRatio = mGeometrySize / (float)numVirtualLeaves;
776        mBvhStats.mTriangleRatio = mBvhStats.mTriangles / (float)numVirtualLeaves;
777}
778
779
780void Bvh::PrintBvhStats() const
781{
782        cout << "bvh stats:" << endl;
783        cout << "interiorNodesSA = " << mBvhStats.mInteriorSA / mRoot->mBox.SurfaceArea() << endl;
784        cout << "leafNodesSA = " << mBvhStats.mLeafSA / mRoot->mBox.SurfaceArea() << endl;
785        cout << "interiorNodesVolume = " << mBvhStats.mInteriorVol / mRoot->mBox.GetVolume() << endl;
786        cout << "leafNodesVolume = " << mBvhStats.mLeafVol / mRoot->mBox.GetVolume() << endl;
787
788        cout << "geometry per leaf: " <<  mBvhStats.mGeometryRatio << endl;
789        cout << "triangles per leaf: " <<  mBvhStats.mTriangleRatio << endl;
790}
791
792
793int Bvh::CountTriangles(BvhNode *node) const
794{
795        int numTriangles = 0;
796
797        for (int i = node->mFirst; i <= node->mLast; ++ i)
798        {
799                numTriangles += mGeometry[i]->GetGeometry()->GetNumTriangles();
800        }
801
802        return numTriangles;
803}
804
805
806float Bvh::GetArea(BvhNode *node) const
807{
808        return node->mArea;
809}
810
811
812void Bvh::UpdateNumLeaves(BvhNode *node) const
813{
814        if (node->IsLeaf())
815        {
816                node->mNumLeaves = 1;
817        }
818        else
819        {
820                BvhNode *f = static_cast<BvhInterior *>(node)->GetFront();
821                BvhNode *b = static_cast<BvhInterior *>(node)->GetBack();
822
823                UpdateNumLeaves(f);
824                UpdateNumLeaves(b);
825
826                node->mNumLeaves = f->mNumLeaves + b->mNumLeaves;
827        }
828}
829
830
831void Bvh::CollectVirtualLeaves(BvhNode *node, BvhNodeContainer &leaves)
832{
833        stack<BvhNode *> tStack;
834        tStack.push(node);
835
836        while (!tStack.empty())
837        {
838                BvhNode *node = tStack.top();
839                tStack.pop();
840
841                if (node->mIsVirtualLeaf)
842                {
843                        leaves.push_back(node);
844                }
845                else if (!node->IsLeaf())
846                {
847                        BvhInterior *interior = static_cast<BvhInterior *>(node);
848
849                        tStack.push(interior->mFront);
850                        tStack.push(interior->mBack);
851                }
852        }
853}
854
855
856void Bvh::SetVirtualLeaves(int numTriangles)
857{
858        // first invalidate old leaves
859        BvhNodeContainer leaves;
860
861        CollectVirtualLeaves(mRoot, leaves);
862
863        BvhNodeContainer::const_iterator bit, bit_end = leaves.end();
864
865        for (bit = leaves.begin(); bit != bit_end; ++ bit)
866        {
867                (*bit)->mIsVirtualLeaf = false;
868        }
869
870        mNumVirtualNodes = 0;
871
872        // assign new virtual leaves based on specified number of triangles per leaf
873        std::stack<BvhNode *> nodeStack;
874        nodeStack.push(mRoot);
875
876        while (!nodeStack.empty())
877        {
878                BvhNode *node = nodeStack.top();
879                nodeStack.pop();
880
881                ++ mNumVirtualNodes;
882
883                if (node->IsLeaf())
884                {
885                        BvhLeaf *leaf = static_cast<BvhLeaf *>(node);
886                        leaf->mIsVirtualLeaf = true;
887                }
888                else
889                {
890                        BvhInterior *interior = static_cast<BvhInterior *>(node);
891
892                        BvhNode *f = interior->mFront;
893                        BvhNode *b = interior->mBack;
894
895                        if (node->mIsMaxDepthForVirtualLeaf || (CountTriangles(node) <= numTriangles))
896                        {
897                                 node->mIsVirtualLeaf = true;
898                        }
899                        else
900                        {
901                                nodeStack.push(interior->mBack);
902                                nodeStack.push(interior->mFront);
903                        }
904                }
905        }
906}
907
908
909void Bvh::PostProcess()
910{
911        std::stack<BvhNode *> nodeStack;
912        nodeStack.push(mRoot);
913
914        while (!nodeStack.empty())
915        {
916                BvhNode *node = nodeStack.top();
917                nodeStack.pop();
918
919                if (node->IsLeaf())
920                {
921                        node->mIsMaxDepthForVirtualLeaf = true;
922                }
923                else
924                {
925                        BvhInterior *interior = static_cast<BvhInterior *>(node);
926
927                        BvhNode *f = interior->mFront;
928                        BvhNode *b = interior->mBack;
929
930                        // point reached where we cannot subdivide further on object level
931                        if ((f->mFirst == b->mFirst) && (f->mLast == b->mLast))
932                        {
933                                node->mIsMaxDepthForVirtualLeaf = true;
934                        }
935                        else
936                        {
937                                nodeStack.push(f);
938                                nodeStack.push(b);
939                        }
940                }
941        }
942}
943
944
945void Bvh::RenderBoundingBoxImmediate(const AxisAlignedBox3 &box)
946{
947        const Vector3 l = box.Min();
948        const Vector3 u = box.Max();
949
950        glBegin(GL_TRIANGLE_STRIP);
951        {
952                ///////////
953                //-- render AABB as triangle strips
954
955                glVertex3f(l.x, l.y, u.z);
956                glVertex3f(u.x, l.y, u.z);
957                glVertex3f(l.x, u.y, u.z);
958                glVertex3f(u.x, u.y, u.z);
959                glVertex3f(l.x, u.y, l.z);
960                glVertex3f(u.x, u.y, l.z);
961                glVertex3f(l.x, l.y, l.z);
962                glVertex3f(u.x, l.y, l.z);
963
964                glPrimitiveRestartNV();
965
966                //-- render second half of AABB
967                glVertex3f(l.x, u.y, u.z);
968                glVertex3f(l.x, u.y, l.z);
969                glVertex3f(l.x, l.y, u.z);
970                glVertex3f(l.x, l.y, l.z);
971                glVertex3f(u.x, l.y, u.z);
972                glVertex3f(u.x, l.y, l.z);
973                glVertex3f(u.x, u.y, u.z);
974                glVertex3f(u.x, u.y, l.z);
975        }
976        glEnd();
977}
978
979
980
981
982static void RenderBoxForViz(const AxisAlignedBox3 &box)
983{
984        glBegin(GL_LINE_LOOP);
985        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
986        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
987        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
988        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
989        glEnd();
990
991        glBegin(GL_LINE_LOOP);
992        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
993        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
994        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
995        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
996        glEnd();
997
998        glBegin(GL_LINE_LOOP);
999        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
1000        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
1001        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
1002        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
1003        glEnd();
1004
1005        glBegin(GL_LINE_LOOP);
1006        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
1007        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
1008        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
1009        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
1010        glEnd();
1011
1012        glBegin(GL_LINE_LOOP);
1013        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
1014        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
1015        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
1016        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
1017        glEnd();
1018
1019        glBegin(GL_LINE_LOOP);
1020        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
1021        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
1022        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
1023        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
1024
1025        glEnd();
1026}
1027
1028
1029void Bvh::RenderBoundsForViz(BvhNode *node, bool useTightBounds)
1030{
1031        glDisable(GL_TEXTURE_2D);
1032        glDisable(GL_LIGHTING);
1033        glColor3f(1, 1, 1);
1034       
1035        if (!useTightBounds)
1036        {
1037                RenderBoxForViz(node->GetBox());
1038        }
1039        else
1040        {
1041                for (int i = 0; i < node->mNumTestNodes; ++ i)
1042                {
1043                        RenderBoxForViz(mTestNodes[node->mTestNodesIdx + i]->GetBox());
1044                }
1045        }
1046
1047        glEnable(GL_LIGHTING);
1048        glEnable(GL_TEXTURE_2D);
1049}
1050
1051
1052
1053}
Note: See TracBrowser for help on using the repository browser.