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

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