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

Revision 2895, 22.5 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 Camera::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),
79mLastRenderedFrame(-999),
80mFirst(-1),
81mLast(-1),
82mNumTestNodes(1),
83mTestNodesIdx(-1),
84mIndicesPtr(-1),
85mId(0),
86mIsMaxDepthForVirtualLeaf(false),
87mIsVirtualLeaf(false)
88{
89        for (int i = 0; i < NUM_STATES; ++ i)
90        {
91                mPlaneMask[i] = 0;
92                mPreferredPlane[i]= 0;
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        }
108
109        mLastRenderedFrame = -999;
110}
111
112
113void BvhNode::VisibilityInfo::Reset()
114{
115        mIsVisible = false;
116        mAssumedVisibleFrameId = 0;
117        mLastVisitedFrame = -1;
118        mTimesInvisible = 0;
119        mIsFrustumCulled = false;
120        mIsNew = true;
121        mLastQueriedFrame = -1;
122}
123
124
125BvhInterior::~BvhInterior()
126{
127        DEL_PTR(mBack);
128        DEL_PTR(mFront);
129}
130
131
132BvhLeaf::~BvhLeaf()
133{
134}
135
136
137/***********************************************************/
138/*                class Bvh implementation                 */
139/***********************************************************/
140
141
142Bvh::Bvh()
143{
144        Init();
145}
146
147
148Bvh::Bvh(const SceneEntityContainer &entities)
149{
150        Init();
151
152        mGeometrySize = entities.size();
153        mGeometry = new SceneEntity*[mGeometrySize];
154
155        SceneEntityContainer::const_iterator it, it_end = entities.end();
156
157        int i = 0;
158        for (it = entities.begin(); it != it_end; ++ it, ++ i)
159        {
160                mGeometry[i] = (*it);
161        }
162}
163
164
165Bvh::~Bvh()
166{
167        if (mVertices) delete [] mVertices;
168        if (mIndices) delete [] mIndices;
169        if (mTestIndices) delete [] mTestIndices;
170        if (mGeometry) delete [] mGeometry;
171
172        if (mRoot) delete mRoot;
173
174        // delete vbo
175        glDeleteBuffersARB(1, &mVboId);
176}
177
178
179void Bvh::Init()
180{
181        mCamera = NULL;
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
366void Bvh::InitFrame()
367{
368        // = 0011 1111 which means that at the beginning, all six planes have to frustum culled
369        mRoot->mPlaneMask[BvhNode::sCurrentState] = 0x3f;
370
371        mCamera->CalcFrustum(sFrustum);
372        sFrustum.CalcNPVertexIndices(sClipPlaneAABBVertexIndices);
373
374        // store near plane
375        sNearPlane = Plane3(mCamera->GetDirection(), mCamera->GetPosition());
376}
377
378
379void Bvh::CalcDistance(BvhNode *node) const
380{
381        node->mDistance = node->GetBox().GetMinVisibleDistance(sNearPlane);
382}
383
384
385void Bvh::RenderBounds(BvhNode *node, RenderState *state, bool useTightBounds)
386{
387        // if not using tight bounds, rendering boxes in immediate mode
388        // is preferable to vertex arrays (less setup time)
389        if (!useTightBounds)
390        {
391                RenderBoundingBoxImmediate(node->GetBox());
392        }
393        else
394        {
395                static BvhNodeContainer dummy(1);
396                dummy[0] = node;
397                RenderBounds(dummy, state, useTightBounds);
398        }
399}
400
401
402int Bvh::RenderBounds(const BvhNodeContainer &nodes,
403                                          RenderState *state,
404                                          bool useTightBounds)
405{
406        // if not using tight bounds, rendering boxes in immediate mode
407        // is preferable to vertex arrays (less setup time)
408
409        int renderedBoxes;
410
411        if (!useTightBounds)
412        {
413                BvhNodeContainer::const_iterator nit, nit_end = nodes.end();
414                       
415                for (nit = nodes.begin(); nit != nit_end; ++ nit)
416                {
417                        RenderBoundingBoxImmediate((*nit)->GetBox());
418                }
419
420                renderedBoxes = (int)nodes.size();
421        }
422        else
423        {
424                renderedBoxes = PrepareBoundsWithDrawArrays(nodes);
425                RenderBoundsWithDrawArrays(renderedBoxes, state);
426        }
427
428        return renderedBoxes;
429}
430
431
432int Bvh::PrepareBoundsWithDrawArrays(const BvhNodeContainer &nodes)
433{
434        //////
435        //-- for the first time we come here ...
436
437        if (!mIndices)
438        {       // create list of indices
439                CreateIndices();
440        }
441
442        if (mVboId == -1)
443        {       
444                // prepare the vbo
445                PrepareVertices();
446        }
447
448        ///////////////
449
450        int numNodes = 0;
451
452        BvhNodeContainer::const_iterator nit, nit_end = nodes.end();
453
454        for (nit = nodes.begin(); nit != nit_end; ++ nit)
455        {
456                BvhNode *node = *nit;
457
458        const int numIndices = node->mNumTestNodes * sNumIndicesPerBox;
459               
460                // copy indices
461                memcpy(mIndices + numNodes * sNumIndicesPerBox,
462                           mTestIndices + node->mIndicesPtr,
463                           numIndices * sizeof(unsigned int));
464
465                numNodes += node->mNumTestNodes;
466        }
467
468        return numNodes;
469}
470
471
472void Bvh::RenderBoundsWithDrawArrays(int numNodes, RenderState *state)
473{
474        //////
475        //-- Rendering the vbo
476
477        if (state->GetCurrentVboId() != mVboId)
478        {
479                glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
480                // set the vertex pointer to the vertex buffer
481                glVertexPointer(3, GL_FLOAT, 0, (char *)NULL); 
482
483                state->SetCurrentVboId(mVboId);
484        }
485
486        // we do use the last or the first index (they are generate and only used to connect strips)
487        int numElements = numNodes * sNumIndicesPerBox - 1;
488        // don't render first degenerate index
489        glDrawElements(GL_TRIANGLE_STRIP, numElements, GL_UNSIGNED_INT, mIndices + 1);
490}
491
492
493void Bvh::CreateIndices()
494{
495        // collect bvh nodes
496        BvhNodeContainer nodes;
497        CollectNodes(mRoot, nodes);
498
499        cout << "creating new indices" << endl;
500
501        int numMaxIndices = 0;
502
503        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
504
505        for (lit = nodes.begin(); lit != lit_end; ++ lit)
506        {
507                int offset = (*lit)->mNumTestNodes * sNumIndicesPerBox;
508#ifdef ALIGN_INDICES
509                // align with 32
510                offset = (offset / 32) * 32 + 32;
511#endif
512                numMaxIndices += offset;
513        }
514
515
516        cout << "creating global indices buffer" << endl;
517
518        if (mIndices) delete [] mIndices;
519        if (mTestIndices) delete [] mTestIndices;
520
521        // global buffer: create it once so we don't have
522        // to allocate memory from the chunks of the node
523        mIndices = new unsigned int[numMaxIndices];
524
525        // create new index buffer for the individual nodes
526        mTestIndices = new unsigned int[numMaxIndices];
527       
528        mCurrentIndicesPtr = 0;
529
530        for (lit = nodes.begin(); lit != lit_end; ++ lit)
531        {
532                BvhNode *node = *lit;
533               
534                // resize array
535                node->mIndicesPtr = mCurrentIndicesPtr;
536
537                int numIndices = 0;
538
539                // the bounding box of the test nodes are rendered instead of the root node
540                // => store their indices
541                for (int i = 0; i < node->mNumTestNodes; ++ i, numIndices += sNumIndicesPerBox)
542                {
543                        BvhNode *testNode = mTestNodes[node->mTestNodesIdx + i];
544
545                        // add indices to root node
546                        for (int j = 0; j < sNumIndicesPerBox; ++ j)
547                        {
548                                mTestIndices[mCurrentIndicesPtr + numIndices + j] = sIndices[j] + testNode->GetId() * 8;
549                        }
550                }
551
552                // align with 32
553#ifdef ALIGN_INDICES
554                const int offset = (numIndices / 32) * 32 + 32;
555#else
556                const int offset = numIndices;
557#endif
558                mCurrentIndicesPtr += offset;
559        }
560}
561
562
563void Bvh::ComputeIds()
564{
565        // collect all nodes
566        BvhNodeContainer nodes;
567        CollectNodes(mRoot, nodes);
568
569        // assign ids to all nodes of the "regular" hierarchy
570        int i = 0;
571        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
572
573        for (lit = nodes.begin(); lit != lit_end; ++ lit, ++ i)
574        {
575                (*lit)->SetId(i);
576        }
577}
578
579
580void Bvh::PrepareVertices()
581{
582        // collect all nodes
583        BvhNodeContainer nodes;
584
585        nodes.reserve(GetNumNodes());
586        CollectNodes(mRoot, nodes);
587
588        const unsigned int bufferSize = 8 * (int)nodes.size();
589        mVertices = new Vector3[bufferSize];
590       
591        int i = 0;
592       
593        // store bounding box vertices
594        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
595
596        for (lit = nodes.begin(); lit != lit_end; ++ lit, i += 8)
597        {
598                BvhNode *node = *lit;
599
600                for (int j = 0; j < 8; ++ j)
601                        ((Vector3 *)mVertices)[node->GetId() * 8 + j] = node->GetBox().GetVertex(j);
602        }
603
604        glGenBuffersARB(1, &mVboId);
605        glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
606        glVertexPointer(3, GL_FLOAT, 0, (char *)NULL);
607       
608        glBufferDataARB(GL_ARRAY_BUFFER_ARB,
609                            bufferSize * sizeof(Vector3),
610                            mVertices,
611                                        GL_STATIC_DRAW_ARB);
612
613        glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
614
615        // data handled by graphics driver from now on
616        DEL_PTR(mVertices);
617
618        cout << "***** created vbos for tighter bounds *********" << endl;
619}
620
621
622void Bvh::SetMaxDepthForTestingChildren(int maxDepth)
623{
624        if (maxDepth != mMaxDepthForTestingChildren)
625        {
626                mMaxDepthForTestingChildren = maxDepth;
627                RecomputeBounds();
628        }
629}
630
631
632void Bvh::SetAreaRatioThresholdForTestingChildren(float ratio)
633{
634        if (ratio != mAreaRatioThreshold)
635        {
636                mAreaRatioThreshold = ratio;
637                RecomputeBounds();
638        }
639}
640
641
642void Bvh::RecomputeBounds()
643{
644        // collect all nodes
645        BvhNodeContainer nodes;
646        CollectNodes(mRoot, nodes);
647
648        cout << "recomputing bounds, children will be tested in depth " << mMaxDepthForTestingChildren << endl;
649
650        int success = 0;
651        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
652
653        for (lit = nodes.begin(); lit != lit_end; ++ lit)
654        {
655                BvhNode *node = *lit;
656
657                // recreate list of nodes that will be queried as a proxy
658                if (CreateNodeRenderList(node))
659                        ++ success;
660        }
661
662        float p = 100.0f * (float)success / nodes.size();
663        cout << "created tighter bounds for " << p << " percent of the nodes" << endl;
664
665        // recreate indices used for indirect mode rendering
666        if (mIndices) 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 << "\n******** 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        cout << "**************" << endl << endl;
789}
790
791
792int Bvh::CountTriangles(BvhNode *node) const
793{
794        int numTriangles = 0;
795
796        for (int i = node->mFirst; i <= node->mLast; ++ i)
797        {
798                numTriangles += mGeometry[i]->CountNumTriangles(0);
799        }
800
801        return numTriangles;
802}
803
804
805float Bvh::GetArea(BvhNode *node) const
806{
807        return node->mArea;
808}
809
810
811void Bvh::UpdateNumLeaves(BvhNode *node) const
812{
813        if (node->IsLeaf())
814        {
815                node->mNumLeaves = 1;
816        }
817        else
818        {
819                BvhNode *f = static_cast<BvhInterior *>(node)->GetFront();
820                BvhNode *b = static_cast<BvhInterior *>(node)->GetBack();
821
822                UpdateNumLeaves(f);
823                UpdateNumLeaves(b);
824
825                node->mNumLeaves = f->mNumLeaves + b->mNumLeaves;
826        }
827}
828
829
830void Bvh::CollectVirtualLeaves(BvhNode *node, BvhNodeContainer &leaves)
831{
832        stack<BvhNode *> tStack;
833        tStack.push(node);
834
835        while (!tStack.empty())
836        {
837                BvhNode *node = tStack.top();
838                tStack.pop();
839
840                if (node->mIsVirtualLeaf)
841                {
842                        leaves.push_back(node);
843                }
844                else if (!node->IsLeaf())
845                {
846                        BvhInterior *interior = static_cast<BvhInterior *>(node);
847
848                        tStack.push(interior->mFront);
849                        tStack.push(interior->mBack);
850                }
851        }
852}
853
854
855void Bvh::SetVirtualLeaves(int numTriangles)
856{
857        // first invalidate old leaves
858        BvhNodeContainer leaves;
859
860        CollectVirtualLeaves(mRoot, leaves);
861
862        BvhNodeContainer::const_iterator bit, bit_end = leaves.end();
863
864        for (bit = leaves.begin(); bit != bit_end; ++ bit)
865        {
866                (*bit)->mIsVirtualLeaf = false;
867        }
868
869        mNumVirtualNodes = 0;
870
871        // assign new virtual leaves based on specified number of triangles per leaf
872        std::stack<BvhNode *> nodeStack;
873        nodeStack.push(mRoot);
874
875        while (!nodeStack.empty())
876        {
877                BvhNode *node = nodeStack.top();
878                nodeStack.pop();
879
880                ++ mNumVirtualNodes;
881
882                if (node->IsLeaf())
883                {
884                        BvhLeaf *leaf = static_cast<BvhLeaf *>(node);
885                        leaf->mIsVirtualLeaf = true;
886                }
887                else
888                {
889                        BvhInterior *interior = static_cast<BvhInterior *>(node);
890
891                        BvhNode *f = interior->mFront;
892                        BvhNode *b = interior->mBack;
893
894                        if (node->mIsMaxDepthForVirtualLeaf || (CountTriangles(node) <= numTriangles))
895                        {
896                                 node->mIsVirtualLeaf = true;
897                        }
898                        else
899                        {
900                                nodeStack.push(interior->mBack);
901                                nodeStack.push(interior->mFront);
902                        }
903                }
904        }
905
906        ResetNodeClassifications();
907}
908
909
910void Bvh::PostProcess()
911{
912        std::stack<BvhNode *> nodeStack;
913        nodeStack.push(mRoot);
914
915        while (!nodeStack.empty())
916        {
917                BvhNode *node = nodeStack.top();
918                nodeStack.pop();
919
920                if (node->IsLeaf())
921                {
922                        node->mIsMaxDepthForVirtualLeaf = true;
923                }
924                else
925                {
926                        BvhInterior *interior = static_cast<BvhInterior *>(node);
927
928                        BvhNode *f = interior->mFront;
929                        BvhNode *b = interior->mBack;
930
931                        // point reached where we cannot subdivide further on object level
932                        if ((f->mFirst == b->mFirst) && (f->mLast == b->mLast))
933                        {
934                                node->mIsMaxDepthForVirtualLeaf = true;
935                        }
936                        else
937                        {
938                                nodeStack.push(f);
939                                nodeStack.push(b);
940                        }
941                }
942        }
943}
944
945
946void Bvh::RenderBoundingBoxImmediate(const AxisAlignedBox3 &box)
947{
948        const Vector3 l = box.Min();
949        const Vector3 u = box.Max();
950
951        glBegin(GL_TRIANGLE_STRIP);
952        {
953                ///////////
954                //-- render AABB as triangle strips
955
956                glVertex3f(l.x, l.y, u.z);
957                glVertex3f(u.x, l.y, u.z);
958                glVertex3f(l.x, u.y, u.z);
959                glVertex3f(u.x, u.y, u.z);
960                glVertex3f(l.x, u.y, l.z);
961                glVertex3f(u.x, u.y, l.z);
962                glVertex3f(l.x, l.y, l.z);
963                glVertex3f(u.x, l.y, l.z);
964
965                glPrimitiveRestartNV();
966
967                //-- render second half of AABB
968                glVertex3f(l.x, u.y, u.z);
969                glVertex3f(l.x, u.y, l.z);
970                glVertex3f(l.x, l.y, u.z);
971                glVertex3f(l.x, l.y, l.z);
972                glVertex3f(u.x, l.y, u.z);
973                glVertex3f(u.x, l.y, l.z);
974                glVertex3f(u.x, u.y, u.z);
975                glVertex3f(u.x, u.y, l.z);
976        }
977        glEnd();
978}
979
980
981
982
983static void RenderBoxForViz(const AxisAlignedBox3 &box)
984{
985        glBegin(GL_LINE_LOOP);
986        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
987        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
988        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
989        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
990        glEnd();
991
992        glBegin(GL_LINE_LOOP);
993        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
994        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
995        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
996        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
997        glEnd();
998
999        glBegin(GL_LINE_LOOP);
1000        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
1001        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
1002        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
1003        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
1004        glEnd();
1005
1006        glBegin(GL_LINE_LOOP);
1007        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
1008        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
1009        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
1010        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
1011        glEnd();
1012
1013        glBegin(GL_LINE_LOOP);
1014        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
1015        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
1016        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
1017        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
1018        glEnd();
1019
1020        glBegin(GL_LINE_LOOP);
1021        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
1022        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
1023        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
1024        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
1025
1026        glEnd();
1027}
1028
1029
1030void Bvh::RenderBoundsForViz(BvhNode *node, RenderState *state, bool useTightBounds)
1031{
1032        glDisable(GL_TEXTURE_2D);
1033        glDisable(GL_LIGHTING);
1034        glColor3f(1, 1, 1);
1035
1036        // hack: for deferred shading we have to define a material
1037        static Material boxMat;
1038        boxMat.SetEmmisive(RgbaColor(1.0f, 1.0f, 1.0f, 1.0f));
1039
1040        boxMat.Render(state);
1041
1042        if (!useTightBounds)
1043        {
1044                RenderBoxForViz(node->GetBox());
1045        }
1046        else
1047        {
1048                for (int i = 0; i < node->mNumTestNodes; ++ i)
1049                {
1050                        RenderBoxForViz(mTestNodes[node->mTestNodesIdx + i]->GetBox());
1051                }
1052        }
1053
1054        glEnable(GL_LIGHTING);
1055        glEnable(GL_TEXTURE_2D);
1056}
1057
1058
1059
1060}
Note: See TracBrowser for help on using the repository browser.