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

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