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

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