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

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