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

Revision 2963, 23.4 KB checked in by mattausch, 16 years ago (diff)

debug version trying to find out how to speed up app

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