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

Revision 2947, 22.9 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::UpdateMinDistance(BvhNode *node) const
392{
393        node->mDistance = node->GetBox().GetMinDistance(sNearPlane);
394}
395
396
397float Bvh::CalcMaxDistance(BvhNode *node) const
398{
399        return node->GetBox().GetMaxDistance(sNearPlane);
400}
401
402
403void Bvh::RenderBounds(BvhNode *node, RenderState *state, bool useTightBounds)
404{
405        // if not using tight bounds, rendering boxes in immediate mode
406        // is preferable to vertex arrays (less setup time)
407        if (!useTightBounds)
408        {
409                RenderBoundingBoxImmediate(node->GetBox());
410        }
411        else
412        {
413                static BvhNodeContainer dummy(1);
414                dummy[0] = node;
415                RenderBounds(dummy, state, useTightBounds);
416        }
417}
418
419
420int Bvh::RenderBounds(const BvhNodeContainer &nodes,
421                                          RenderState *state,
422                                          bool useTightBounds)
423{
424        // if not using tight bounds, rendering boxes in immediate mode
425        // is preferable to vertex arrays (less setup time)
426
427        int renderedBoxes;
428
429        if (!useTightBounds)
430        {
431                BvhNodeContainer::const_iterator nit, nit_end = nodes.end();
432                       
433                for (nit = nodes.begin(); nit != nit_end; ++ nit)
434                {
435                        RenderBoundingBoxImmediate((*nit)->GetBox());
436                }
437
438                renderedBoxes = (int)nodes.size();
439        }
440        else
441        {
442                renderedBoxes = PrepareBoundsWithDrawArrays(nodes);
443                RenderBoundsWithDrawArrays(renderedBoxes, state);
444        }
445
446        return renderedBoxes;
447}
448
449
450int Bvh::PrepareBoundsWithDrawArrays(const BvhNodeContainer &nodes)
451{
452        //////
453        //-- for the first time we come here ...
454
455        if (!mIndices)
456        {       // create list of indices
457                CreateIndices();
458        }
459
460        if (mVboId == -1)
461        {       
462                // prepare the vbo
463                PrepareVertices();
464        }
465
466        ///////////////
467
468        int numNodes = 0;
469
470        BvhNodeContainer::const_iterator nit, nit_end = nodes.end();
471
472        for (nit = nodes.begin(); nit != nit_end; ++ nit)
473        {
474                BvhNode *node = *nit;
475
476        const int numIndices = node->mNumTestNodes * sNumIndicesPerBox;
477               
478                // copy indices
479                memcpy(mIndices + numNodes * sNumIndicesPerBox,
480                           mTestIndices + node->mIndicesPtr,
481                           numIndices * sizeof(unsigned int));
482
483                numNodes += node->mNumTestNodes;
484        }
485
486        return numNodes;
487}
488
489
490void Bvh::RenderBoundsWithDrawArrays(int numNodes, RenderState *state)
491{
492        //////
493        //-- Rendering the vbo
494
495        if (state->GetCurrentVboId() != mVboId)
496        {
497                glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
498                // set the vertex pointer to the vertex buffer
499                glVertexPointer(3, GL_FLOAT, 0, (char *)NULL); 
500
501                state->SetCurrentVboId(mVboId);
502        }
503
504        // we do use the last or the first index (they are generate and only used to connect strips)
505        int numElements = numNodes * sNumIndicesPerBox - 1;
506        // don't render first degenerate index
507        glDrawElements(GL_TRIANGLE_STRIP, numElements, GL_UNSIGNED_INT, mIndices + 1);
508}
509
510
511void Bvh::CreateIndices()
512{
513        // collect bvh nodes
514        BvhNodeContainer nodes;
515        CollectNodes(mRoot, nodes);
516
517        cout << "creating new indices" << endl;
518
519        int numMaxIndices = 0;
520
521        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
522
523        for (lit = nodes.begin(); lit != lit_end; ++ lit)
524        {
525                int offset = (*lit)->mNumTestNodes * sNumIndicesPerBox;
526#ifdef ALIGN_INDICES
527                // align with 32
528                offset = (offset / 32) * 32 + 32;
529#endif
530                numMaxIndices += offset;
531        }
532
533
534        cout << "creating global indices buffer" << endl;
535
536        if (mIndices) delete [] mIndices;
537        if (mTestIndices) delete [] mTestIndices;
538
539        // global buffer: create it once so we don't have
540        // to allocate memory from the chunks of the node
541        mIndices = new unsigned int[numMaxIndices];
542
543        // create new index buffer for the individual nodes
544        mTestIndices = new unsigned int[numMaxIndices];
545       
546        mCurrentIndicesPtr = 0;
547
548        for (lit = nodes.begin(); lit != lit_end; ++ lit)
549        {
550                BvhNode *node = *lit;
551               
552                // resize array
553                node->mIndicesPtr = mCurrentIndicesPtr;
554
555                int numIndices = 0;
556
557                // the bounding box of the test nodes are rendered instead of the root node
558                // => store their indices
559                for (int i = 0; i < node->mNumTestNodes; ++ i, numIndices += sNumIndicesPerBox)
560                {
561                        BvhNode *testNode = mTestNodes[node->mTestNodesIdx + i];
562
563                        // add indices to root node
564                        for (int j = 0; j < sNumIndicesPerBox; ++ j)
565                        {
566                                mTestIndices[mCurrentIndicesPtr + numIndices + j] = sIndices[j] + testNode->GetId() * 8;
567                        }
568                }
569
570                // align with 32
571#ifdef ALIGN_INDICES
572                const int offset = (numIndices / 32) * 32 + 32;
573#else
574                const int offset = numIndices;
575#endif
576                mCurrentIndicesPtr += offset;
577        }
578}
579
580
581void Bvh::ComputeIds()
582{
583        // collect all nodes
584        BvhNodeContainer nodes;
585        CollectNodes(mRoot, nodes);
586
587        // assign ids to all nodes of the "regular" hierarchy
588        int i = 0;
589        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
590
591        for (lit = nodes.begin(); lit != lit_end; ++ lit, ++ i)
592        {
593                (*lit)->SetId(i);
594        }
595}
596
597
598void Bvh::PrepareVertices()
599{
600        // collect all nodes
601        BvhNodeContainer nodes;
602
603        nodes.reserve(GetNumNodes());
604        CollectNodes(mRoot, nodes);
605
606        const unsigned int bufferSize = 8 * (int)nodes.size();
607        mVertices = new Vector3[bufferSize];
608       
609        int i = 0;
610       
611        // store bounding box vertices
612        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
613
614        for (lit = nodes.begin(); lit != lit_end; ++ lit, i += 8)
615        {
616                BvhNode *node = *lit;
617
618                for (int j = 0; j < 8; ++ j)
619                        ((Vector3 *)mVertices)[node->GetId() * 8 + j] = node->GetBox().GetVertex(j);
620        }
621
622        glGenBuffersARB(1, &mVboId);
623        glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
624        glVertexPointer(3, GL_FLOAT, 0, (char *)NULL);
625       
626        glBufferDataARB(GL_ARRAY_BUFFER_ARB,
627                            bufferSize * sizeof(Vector3),
628                            mVertices,
629                                        GL_STATIC_DRAW_ARB);
630
631        glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
632
633        // data handled by graphics driver from now on
634        DEL_PTR(mVertices);
635
636        cout << "***** created vbos for tighter bounds *********" << endl;
637}
638
639
640void Bvh::SetMaxDepthForTestingChildren(int maxDepth)
641{
642        if (maxDepth != mMaxDepthForTestingChildren)
643        {
644                mMaxDepthForTestingChildren = maxDepth;
645                RecomputeBounds();
646        }
647}
648
649
650void Bvh::SetAreaRatioThresholdForTestingChildren(float ratio)
651{
652        if (ratio != mAreaRatioThreshold)
653        {
654                mAreaRatioThreshold = ratio;
655                RecomputeBounds();
656        }
657}
658
659
660void Bvh::RecomputeBounds()
661{
662        // collect all nodes
663        BvhNodeContainer nodes;
664        CollectNodes(mRoot, nodes);
665
666        cout << "recomputing bounds, children will be tested in depth " << mMaxDepthForTestingChildren << endl;
667
668        int success = 0;
669        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
670
671        for (lit = nodes.begin(); lit != lit_end; ++ lit)
672        {
673                BvhNode *node = *lit;
674
675                // recreate list of nodes that will be queried as a proxy
676                if (CreateNodeRenderList(node))
677                        ++ success;
678        }
679
680        float p = 100.0f * (float)success / nodes.size();
681        cout << "created tighter bounds for " << p << " percent of the nodes" << endl;
682
683        // recreate indices used for indirect mode rendering
684        if (mIndices) CreateIndices();
685}
686
687       
688bool Bvh::CreateNodeRenderList(BvhNode *node)
689{
690        BvhNodeContainer children;
691
692        // collect nodes that will be tested instead of the leaf node
693        // in order to get a tighter bounding box test
694        CollectNodes(node, children, mMaxDepthForTestingChildren);
695       
696
697        // using the tighter bounds is not feasable in case
698        // that the tighter bounds represent nearly the same projected area
699        // as the old bounding box. Find this out using either volume or area
700        // heuristics
701
702        float vol = 0;
703        float area = 0;
704
705        BvhNodeContainer::const_iterator cit;
706
707        for (cit = children.begin(); cit != children.end(); ++ cit)
708                area += (*cit)->GetBox().SurfaceArea();
709
710        const float areaRatio = area / node->GetBox().SurfaceArea();
711       
712        bool success;
713
714        if (areaRatio < mAreaRatioThreshold)
715                success = true;
716        else
717        {
718                // hack: only store node itself
719                children.clear();
720                children.push_back(node);
721
722                success = false;
723        }
724
725        // the new test nodes are added at the end of the vector
726        node->mTestNodesIdx = (int)mTestNodes.size();
727
728        // use the found nodes as nodes during the occlusion tests
729        for (cit = children.begin(); cit != children.end(); ++ cit)
730        {
731                BvhNode *child = *cit;
732                mTestNodes.push_back(child);
733        }
734
735        node->mNumTestNodes = (int)children.size();
736
737        return success;
738}
739
740
741void Bvh::ResetNodeClassifications()
742{
743        BvhNodeContainer nodes;
744
745        nodes.reserve(GetNumNodes());
746        CollectNodes(mRoot, nodes);
747
748        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
749
750        for (lit = nodes.begin(); lit != lit_end; ++ lit)
751        {
752                (*lit)->ResetVisibility();
753        }
754}
755
756
757void Bvh::ComputeBvhStats()
758{
759        std::stack<BvhNode *> nodeStack;
760        nodeStack.push(mRoot);
761
762        int numVirtualLeaves = 0;
763
764        while (!nodeStack.empty())
765        {
766                BvhNode *node = nodeStack.top();
767                nodeStack.pop();
768
769                if (node->IsVirtualLeaf())
770                {
771                        ++ numVirtualLeaves;
772
773                        BvhLeaf *leaf = static_cast<BvhLeaf *>(node);
774
775                        mBvhStats.mTriangles += CountTriangles(leaf);
776                        mBvhStats.mLeafSA += leaf->mBox.SurfaceArea();
777                        mBvhStats.mLeafVol += leaf->mBox.GetVolume();
778                }
779                else
780                {
781                        mBvhStats.mInteriorSA += node->mBox.SurfaceArea();
782                        mBvhStats.mInteriorVol += node->mBox.GetVolume();
783
784                        BvhInterior *interior = static_cast<BvhInterior *>(node);
785                       
786                        nodeStack.push(interior->mBack);
787                        nodeStack.push(interior->mFront);
788                }
789        }
790
791        mBvhStats.mGeometryRatio = mGeometrySize / (float)numVirtualLeaves;
792        mBvhStats.mTriangleRatio = mBvhStats.mTriangles / (float)numVirtualLeaves;
793}
794
795
796void Bvh::PrintBvhStats() const
797{
798        cout << "\n******** bvh stats: ***********" << endl;
799        cout << "interiorNodesSA = " << mBvhStats.mInteriorSA / mRoot->mBox.SurfaceArea() << endl;
800        cout << "leafNodesSA = " << mBvhStats.mLeafSA / mRoot->mBox.SurfaceArea() << endl;
801        cout << "interiorNodesVolume = " << mBvhStats.mInteriorVol / mRoot->mBox.GetVolume() << endl;
802        cout << "leafNodesVolume = " << mBvhStats.mLeafVol / mRoot->mBox.GetVolume() << endl;
803
804        cout << "geometry per leaf: " <<  mBvhStats.mGeometryRatio << endl;
805        cout << "triangles per leaf: " <<  mBvhStats.mTriangleRatio << endl;
806        cout << "**************" << endl << endl;
807}
808
809
810int Bvh::CountTriangles(BvhNode *node) const
811{
812        int numTriangles = 0;
813
814        for (int i = node->mFirst; i <= node->mLast; ++ i)
815        {
816                numTriangles += mGeometry[i]->CountNumTriangles(0);
817        }
818
819        return numTriangles;
820}
821
822
823float Bvh::GetArea(BvhNode *node) const
824{
825        return node->mArea;
826}
827
828
829void Bvh::UpdateNumLeaves(BvhNode *node) const
830{
831        if (node->IsLeaf())
832        {
833                node->mNumLeaves = 1;
834        }
835        else
836        {
837                BvhNode *f = static_cast<BvhInterior *>(node)->GetFront();
838                BvhNode *b = static_cast<BvhInterior *>(node)->GetBack();
839
840                UpdateNumLeaves(f);
841                UpdateNumLeaves(b);
842
843                node->mNumLeaves = f->mNumLeaves + b->mNumLeaves;
844        }
845}
846
847
848void Bvh::CollectVirtualLeaves(BvhNode *node, BvhNodeContainer &leaves)
849{
850        stack<BvhNode *> tStack;
851        tStack.push(node);
852
853        while (!tStack.empty())
854        {
855                BvhNode *node = tStack.top();
856                tStack.pop();
857
858                if (node->mIsVirtualLeaf)
859                {
860                        leaves.push_back(node);
861                }
862                else if (!node->IsLeaf())
863                {
864                        BvhInterior *interior = static_cast<BvhInterior *>(node);
865
866                        tStack.push(interior->mFront);
867                        tStack.push(interior->mBack);
868                }
869        }
870}
871
872
873void Bvh::SetVirtualLeaves(int numTriangles)
874{
875        // first invalidate old leaves
876        BvhNodeContainer leaves;
877
878        CollectVirtualLeaves(mRoot, leaves);
879
880        BvhNodeContainer::const_iterator bit, bit_end = leaves.end();
881
882        for (bit = leaves.begin(); bit != bit_end; ++ bit)
883        {
884                (*bit)->mIsVirtualLeaf = false;
885        }
886
887        mNumVirtualNodes = 0;
888
889        // assign new virtual leaves based on specified number of triangles per leaf
890        std::stack<BvhNode *> nodeStack;
891        nodeStack.push(mRoot);
892
893        while (!nodeStack.empty())
894        {
895                BvhNode *node = nodeStack.top();
896                nodeStack.pop();
897
898                ++ mNumVirtualNodes;
899
900                if (node->IsLeaf())
901                {
902                        BvhLeaf *leaf = static_cast<BvhLeaf *>(node);
903                        leaf->mIsVirtualLeaf = true;
904                }
905                else
906                {
907                        BvhInterior *interior = static_cast<BvhInterior *>(node);
908
909                        BvhNode *f = interior->mFront;
910                        BvhNode *b = interior->mBack;
911
912                        if (node->mIsMaxDepthForVirtualLeaf || (CountTriangles(node) <= numTriangles))
913                        {
914                                 node->mIsVirtualLeaf = true;
915                        }
916                        else
917                        {
918                                nodeStack.push(interior->mBack);
919                                nodeStack.push(interior->mFront);
920                        }
921                }
922        }
923
924        ResetNodeClassifications();
925}
926
927
928void Bvh::PostProcess()
929{
930        std::stack<BvhNode *> nodeStack;
931        nodeStack.push(mRoot);
932
933        while (!nodeStack.empty())
934        {
935                BvhNode *node = nodeStack.top();
936                nodeStack.pop();
937
938                if (node->IsLeaf())
939                {
940                        node->mIsMaxDepthForVirtualLeaf = true;
941                }
942                else
943                {
944                        BvhInterior *interior = static_cast<BvhInterior *>(node);
945
946                        BvhNode *f = interior->mFront;
947                        BvhNode *b = interior->mBack;
948
949                        // point reached where we cannot subdivide further on object level
950                        if ((f->mFirst == b->mFirst) && (f->mLast == b->mLast))
951                        {
952                                node->mIsMaxDepthForVirtualLeaf = true;
953                        }
954                        else
955                        {
956                                nodeStack.push(f);
957                                nodeStack.push(b);
958                        }
959                }
960        }
961}
962
963
964void Bvh::RenderBoundingBoxImmediate(const AxisAlignedBox3 &box)
965{
966        const Vector3 l = box.Min();
967        const Vector3 u = box.Max();
968
969        glBegin(GL_TRIANGLE_STRIP);
970        {
971                ///////////
972                //-- render AABB as triangle strips
973
974                glVertex3f(l.x, l.y, u.z);
975                glVertex3f(u.x, l.y, u.z);
976                glVertex3f(l.x, u.y, u.z);
977                glVertex3f(u.x, u.y, u.z);
978                glVertex3f(l.x, u.y, l.z);
979                glVertex3f(u.x, u.y, l.z);
980                glVertex3f(l.x, l.y, l.z);
981                glVertex3f(u.x, l.y, l.z);
982
983                glPrimitiveRestartNV();
984
985                //-- render second half of AABB
986                glVertex3f(l.x, u.y, u.z);
987                glVertex3f(l.x, u.y, l.z);
988                glVertex3f(l.x, l.y, u.z);
989                glVertex3f(l.x, l.y, l.z);
990                glVertex3f(u.x, l.y, u.z);
991                glVertex3f(u.x, l.y, l.z);
992                glVertex3f(u.x, u.y, u.z);
993                glVertex3f(u.x, u.y, l.z);
994        }
995        glEnd();
996}
997
998
999
1000
1001static void RenderBoxForViz(const AxisAlignedBox3 &box)
1002{
1003        glBegin(GL_LINE_LOOP);
1004        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
1005        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
1006        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
1007        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
1008        glEnd();
1009
1010        glBegin(GL_LINE_LOOP);
1011        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
1012        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
1013        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
1014        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
1015        glEnd();
1016
1017        glBegin(GL_LINE_LOOP);
1018        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
1019        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
1020        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
1021        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
1022        glEnd();
1023
1024        glBegin(GL_LINE_LOOP);
1025        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
1026        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
1027        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
1028        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
1029        glEnd();
1030
1031        glBegin(GL_LINE_LOOP);
1032        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
1033        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
1034        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
1035        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
1036        glEnd();
1037
1038        glBegin(GL_LINE_LOOP);
1039        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
1040        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
1041        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
1042        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
1043
1044        glEnd();
1045}
1046
1047
1048void Bvh::RenderBoundsForViz(BvhNode *node, RenderState *state, bool useTightBounds)
1049{
1050        glDisable(GL_TEXTURE_2D);
1051        glDisable(GL_LIGHTING);
1052        glColor3f(1, 1, 1);
1053
1054        // hack: for deferred shading we have to define a material
1055        static Material boxMat;
1056        boxMat.SetEmmisive(RgbaColor(1.0f, 1.0f, 1.0f, 1.0f));
1057
1058        boxMat.Render(state);
1059
1060        if (!useTightBounds)
1061        {
1062                RenderBoxForViz(node->GetBox());
1063        }
1064        else
1065        {
1066                for (int i = 0; i < node->mNumTestNodes; ++ i)
1067                {
1068                        RenderBoxForViz(mTestNodes[node->mTestNodesIdx + i]->GetBox());
1069                }
1070        }
1071
1072        glEnable(GL_LIGHTING);
1073        glEnable(GL_TEXTURE_2D);
1074}
1075
1076
1077
1078}
Note: See TracBrowser for help on using the repository browser.