source: GTP/trunk/App/Demos/Vis/CHC_revisited/Bvh.cpp @ 2761

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