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

Revision 3061, 27.1 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        mMaxDepthForDynamicBranch = 10;
208}
209
210
211void Bvh::PullUpLastVisited(BvhNode *node, const int frameId) const
212{               
213        BvhNode *parent = node->GetParent();
214
215        while (parent && (parent->GetLastVisitedFrame() != frameId))
216        {
217                parent->SetLastVisitedFrame(frameId);
218                parent = parent->GetParent();
219        }
220}
221
222
223void Bvh::MakeParentsVisible(BvhNode *node)
224{
225        BvhNode *parent = node->GetParent();
226
227        while (parent && (!parent->IsVisible()))
228        {
229                parent->SetVisible(true);
230                parent = parent->GetParent();
231        }
232}
233
234
235void Bvh::CollectLeaves(BvhNode *node, BvhLeafContainer &leaves)
236{
237        stack<BvhNode *> tStack;
238        tStack.push(node);
239
240        while (!tStack.empty())
241        {
242                BvhNode *node = tStack.top();
243
244                tStack.pop();
245
246                if (!node->IsLeaf())
247                {
248                        BvhInterior *interior = static_cast<BvhInterior *>(node);
249
250                        tStack.push(interior->mFront);
251                        tStack.push(interior->mBack);
252                }
253                else
254                {
255                        leaves.push_back(static_cast<BvhLeaf *>(node));
256                }
257        }
258}
259
260
261void Bvh::CollectNodes(BvhNode *node, BvhNodeContainer &nodes)
262{
263        stack<BvhNode *> tStack;
264
265        tStack.push(node);
266
267        while (!tStack.empty())
268        {
269                BvhNode *node = tStack.top();
270                tStack.pop();
271
272                nodes.push_back(node);
273
274                if (!node->IsLeaf())
275                {
276                        BvhInterior *interior = static_cast<BvhInterior *>(node);
277
278                        tStack.push(interior->mFront);
279                        tStack.push(interior->mBack);
280                }
281        }
282}
283
284
285typedef pair<BvhNode *, int> tPair;
286
287void Bvh::CollectNodes(BvhNode *root, BvhNodeContainer &nodes, int depth)
288{
289        stack<tPair> tStack;
290        tStack.push(tPair(root, 0));
291
292        while (!tStack.empty())
293        {
294                BvhNode *node = tStack.top().first;
295                const int d = tStack.top().second;
296
297                tStack.pop();
298
299                // found depth => take this node
300                if ((d == depth) || (node->IsLeaf()))
301                {
302                        nodes.push_back(node);
303                }
304                else
305                {
306                        BvhInterior *interior = static_cast<BvhInterior *>(node);
307
308                        tStack.push(tPair(interior->mFront, d + 1));
309                        tStack.push(tPair(interior->mBack, d + 1));
310                }
311        }
312}
313
314
315SceneEntity **Bvh::GetGeometry(BvhNode *node, int &geometrySize) const
316{
317        geometrySize = node->CountPrimitives();
318        return mGeometry + node->mFirst;
319}
320
321
322bool Bvh::TestPlane(BvhNode *node, int i, bool &bIntersect)
323{
324        // do the test only if necessary
325        if (!(node->mPlaneMask[BvhNode::sCurrentState] & (1 << i)))
326                return true;
327                       
328        ////////
329        //-- test the n-vertex
330               
331        if ((node->mBox.GetDistance(sClipPlaneAABBVertexIndices[i * 2 + 0], sFrustum.mClipPlanes[i]) > 0.0f))
332        {
333                // outside
334                node->mPreferredPlane[BvhNode::sCurrentState] = i;
335                return false;
336        }
337
338        ////////////
339        //-- test the p-vertex
340
341        if (node->mBox.GetDistance(sClipPlaneAABBVertexIndices[i * 2 + 1], sFrustum.mClipPlanes[i]) <= 0.0f)
342        {
343                // completely inside: children don't need to check against this plane no more
344                node->mPlaneMask[BvhNode::sCurrentState] ^= 1 << i;
345        }
346        else
347        {
348                bIntersect = true;
349        }
350       
351        return true;
352}
353
354
355int     Bvh::IsWithinViewFrustum(BvhNode *node)
356{
357        bool bIntersect = false;
358
359        if (node->GetParent())
360                node->mPlaneMask[BvhNode::sCurrentState] = node->GetParent()->mPlaneMask[BvhNode::sCurrentState];
361
362        ////////
363        //-- apply frustum culling for the planes [mPreferredPlane - 5]
364
365        for (int i = node->mPreferredPlane[BvhNode::sCurrentState]; i < 6; ++ i)
366                if (!TestPlane(node, i, bIntersect)) return 0;
367       
368
369        //////////
370        //-- do the view frustum culling for the planes [0 - m_iPreferredPlane)
371
372        for (int i = 0; i < node->mPreferredPlane[BvhNode::sCurrentState]; ++ i)
373                if (!TestPlane(node, i, bIntersect)) return 0;
374       
375        return bIntersect ? -1 : 1;
376}
377
378
379static void CalcNPVertexIndices(const Frustum &frustum, int *indices)
380{
381        for (int i = 0; i < 6; ++ i)
382        {
383                // n-vertex
384                indices[i * 2 + 0] = AxisAlignedBox3::GetIndexNearestVertex(frustum.mClipPlanes[i].mNormal);
385                // p-vertex
386                indices[i * 2 + 1] = AxisAlignedBox3::GetIndexFarthestVertex(frustum.mClipPlanes[i].mNormal);   
387        }
388}
389
390
391void Bvh::InitFrame(Camera *cam)
392{
393        // = 0011 1111 which means that at the beginning, all six planes have to frustum culled
394        mRoot->mPlaneMask[BvhNode::sCurrentState] = 0x3f;
395
396        cam->CalcFrustum(sFrustum);
397        CalcNPVertexIndices(sFrustum, sClipPlaneAABBVertexIndices);
398
399        // store near plane
400        sNearPlane = Plane3(cam->GetDirection(), cam->GetPosition());
401
402        // rebuild dynamic part of the hierarchy
403        if (!mDynamicEntities.empty())
404        {
405                UpdateDynamicBranch();
406        }
407}
408
409
410void Bvh::UpdateDistance(BvhNode *node) const
411{
412        // use distance to center rather than the distance to the near plane because
413        // otherwise problems with big object penetrating the near plane
414        // (e.g., big objects in the distance which are then always visible)
415        // especially annoying is this problem when using the frustum
416        // fitting on the visible objects for shadow mapping
417
418        //node->mDistance = node->GetBox()GetMinDistance(sNearPlane);
419        node->mDistance = sNearPlane.Distance(node->GetBox().Center());
420}
421
422
423float Bvh::CalcMaxDistance(BvhNode *node) const
424{
425        return node->GetBox().GetMaxDistance(sNearPlane);
426
427        float maxDist = .0f;
428
429        int geometrySize;
430        SceneEntity **entities = GetGeometry(node, geometrySize);
431
432        for (int i = 0; i < geometrySize; ++ i)
433        {
434                SceneEntity *ent = entities[i];
435                float dist = ent->GetTransformedBoundingBox().GetMaxDistance(sNearPlane);
436
437                if (dist > maxDist) maxDist = dist;
438        }
439
440        return maxDist;
441}
442
443
444void Bvh::RenderBounds(BvhNode *node, RenderState *state, bool useTightBounds)
445{
446        // if not using tight bounds, rendering boxes in immediate mode
447        // is preferable to vertex arrays (less setup time)
448        if (!useTightBounds)
449        {
450                RenderBoundingBoxImmediate(node->GetBox());
451        }
452        else
453        {
454                // hack: use dummy wrapper in order to use function
455                static BvhNodeContainer dummy(1);
456                dummy[0] = node;
457                RenderBounds(dummy, state, useTightBounds);
458        }
459}
460
461
462int Bvh::RenderBounds(const BvhNodeContainer &nodes,
463                                          RenderState *state,
464                                          bool useTightBounds)
465{
466        // if not using tight bounds, rendering boxes in immediate mode
467        // is preferable to vertex arrays (less setup time)
468
469        int renderedBoxes;
470
471        if (!useTightBounds)
472        {
473                BvhNodeContainer::const_iterator nit, nit_end = nodes.end();
474                       
475                for (nit = nodes.begin(); nit != nit_end; ++ nit)
476                {
477                        RenderBoundingBoxImmediate((*nit)->GetBox());
478                }
479
480                renderedBoxes = (int)nodes.size();
481        }
482        else
483        {
484                renderedBoxes = PrepareBoundsWithDrawArrays(nodes);
485                RenderBoundsWithDrawArrays(renderedBoxes, state);
486        }
487
488        return renderedBoxes;
489}
490
491
492int Bvh::PrepareBoundsWithDrawArrays(const BvhNodeContainer &nodes)
493{
494        //////
495        //-- for the first time we come here ...
496
497        if (!mIndices)
498        {       // create list of indices
499                CreateIndices();
500        }
501
502        if (mVboId == -1)
503        {       
504                // prepare the vbo
505                PrepareVertices();
506        }
507
508        ///////////////
509
510        int numNodes = 0;
511
512        BvhNodeContainer::const_iterator nit, nit_end = nodes.end();
513
514        for (nit = nodes.begin(); nit != nit_end; ++ nit)
515        {
516                BvhNode *node = *nit;
517
518        const int numIndices = node->mNumTestNodes * sNumIndicesPerBox;
519               
520                // copy indices
521                memcpy(mIndices + numNodes * sNumIndicesPerBox,
522                           mTestIndices + node->mIndicesPtr,
523                           numIndices * sizeof(unsigned int));
524
525                numNodes += node->mNumTestNodes;
526        }
527
528        return numNodes;
529}
530
531
532void Bvh::RenderBoundsWithDrawArrays(int numNodes, RenderState *state)
533{
534        //////
535        //-- Rendering the vbo
536
537        if (state->GetCurrentVboId() != mVboId)
538        {
539                glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
540                // set the vertex pointer to the vertex buffer
541                glVertexPointer(3, GL_FLOAT, 0, (char *)NULL); 
542
543                state->SetCurrentVboId(mVboId);
544        }
545
546        // we do use the last or the first index (they are generate and only used to connect strips)
547        int numElements = numNodes * sNumIndicesPerBox - 1;
548        // don't render first degenerate index
549        glDrawElements(GL_TRIANGLE_STRIP, numElements, GL_UNSIGNED_INT, mIndices + 1);
550}
551
552
553void Bvh::CreateIndices()
554{
555        // collect bvh nodes
556        BvhNodeContainer nodes;
557        CollectNodes(mRoot, nodes);
558
559        cout << "creating new indices" << endl;
560
561        int numMaxIndices = 0;
562
563        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
564
565        for (lit = nodes.begin(); lit != lit_end; ++ lit)
566        {
567                int offset = (*lit)->mNumTestNodes * sNumIndicesPerBox;
568#ifdef ALIGN_INDICES
569                // align with 32
570                offset = (offset / 32) * 32 + 32;
571#endif
572                numMaxIndices += offset;
573        }
574
575
576        cout << "creating global indices buffer" << endl;
577
578        if (mIndices) delete [] mIndices;
579        if (mTestIndices) delete [] mTestIndices;
580
581        // global buffer: create it once so we don't have
582        // to allocate memory from the chunks of the node
583        mIndices = new unsigned int[numMaxIndices];
584
585        // create new index buffer for the individual nodes
586        mTestIndices = new unsigned int[numMaxIndices];
587       
588        mCurrentIndicesPtr = 0;
589
590        for (lit = nodes.begin(); lit != lit_end; ++ lit)
591        {
592                BvhNode *node = *lit;
593               
594                // resize array
595                node->mIndicesPtr = mCurrentIndicesPtr;
596
597                int numIndices = 0;
598
599                // the bounding box of the test nodes are rendered instead of the root node
600                // => store their indices
601                for (int i = 0; i < node->mNumTestNodes; ++ i, numIndices += sNumIndicesPerBox)
602                {
603                        BvhNode *testNode = mTestNodes[node->mTestNodesIdx + i];
604
605                        // add indices to root node
606                        for (int j = 0; j < sNumIndicesPerBox; ++ j)
607                        {
608                                mTestIndices[mCurrentIndicesPtr + numIndices + j] = sIndices[j] + testNode->GetId() * 8;
609                        }
610                }
611
612                // align with 32
613#ifdef ALIGN_INDICES
614                const int offset = (numIndices / 32) * 32 + 32;
615#else
616                const int offset = numIndices;
617#endif
618                mCurrentIndicesPtr += offset;
619        }
620}
621
622
623void Bvh::ComputeIds()
624{
625        // collect all nodes
626        BvhNodeContainer nodes;
627        CollectNodes(mRoot, nodes);
628
629        // assign ids to all nodes of the "regular" hierarchy
630        int i = 0;
631        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
632
633        for (lit = nodes.begin(); lit != lit_end; ++ lit, ++ i)
634        {
635                (*lit)->SetId(i);
636        }
637}
638
639
640void Bvh::PrepareVertices()
641{
642        // collect all nodes
643        BvhNodeContainer nodes;
644
645        nodes.reserve(GetNumNodes());
646        CollectNodes(mRoot, nodes);
647
648        const unsigned int bufferSize = 8 * (int)nodes.size();
649        mVertices = new Vector3[bufferSize];
650       
651        int i = 0;
652       
653        // store bounding box vertices
654        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
655
656        for (lit = nodes.begin(); lit != lit_end; ++ lit, i += 8)
657        {
658                BvhNode *node = *lit;
659
660                for (int j = 0; j < 8; ++ j)
661                        ((Vector3 *)mVertices)[node->GetId() * 8 + j] = node->GetBox().GetVertex(j);
662        }
663
664        glGenBuffersARB(1, &mVboId);
665        glBindBufferARB(GL_ARRAY_BUFFER_ARB, mVboId);
666        glVertexPointer(3, GL_FLOAT, 0, (char *)NULL);
667       
668        glBufferDataARB(GL_ARRAY_BUFFER_ARB,
669                            bufferSize * sizeof(Vector3),
670                            mVertices,
671                                        GL_STATIC_DRAW_ARB);
672
673        glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
674
675        // data handled by graphics driver from now on
676        DEL_PTR(mVertices);
677
678        cout << "***** created vbos for tighter bounds *********" << endl;
679}
680
681
682void Bvh::SetMaxDepthForTestingChildren(int maxDepth)
683{
684        if (maxDepth != mMaxDepthForTestingChildren)
685        {
686                mMaxDepthForTestingChildren = maxDepth;
687                RecomputeBounds();
688        }
689}
690
691
692void Bvh::SetAreaRatioThresholdForTestingChildren(float ratio)
693{
694        if (ratio != mAreaRatioThreshold)
695        {
696                mAreaRatioThreshold = ratio;
697                RecomputeBounds();
698        }
699}
700
701
702void Bvh::RecomputeBounds()
703{
704        // collect all nodes
705        BvhNodeContainer nodes;
706        CollectNodes(mRoot, nodes);
707
708        cout << "recomputing bounds, children will be tested in depth " << mMaxDepthForTestingChildren << endl;
709
710        int success = 0;
711        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
712
713        for (lit = nodes.begin(); lit != lit_end; ++ lit)
714        {
715                BvhNode *node = *lit;
716
717                // recreate list of nodes that will be queried as a proxy
718                if (CreateNodeRenderList(node))
719                        ++ success;
720        }
721
722        float p = 100.0f * (float)success / nodes.size();
723        cout << "created tighter bounds for " << p << " percent of the nodes" << endl;
724
725        // recreate indices used for indirect mode rendering
726        if (mIndices) CreateIndices();
727}
728
729       
730bool Bvh::CreateNodeRenderList(BvhNode *node)
731{
732        BvhNodeContainer children;
733
734        // collect nodes that will be tested instead of the leaf node
735        // in order to get a tighter bounding box test
736        CollectNodes(node, children, mMaxDepthForTestingChildren);
737       
738
739        // using the tighter bounds is not feasable in case
740        // that the tighter bounds represent nearly the same projected area
741        // as the old bounding box. Find this out using either volume or area
742        // heuristics
743
744        float vol = 0;
745        float area = 0;
746
747        BvhNodeContainer::const_iterator cit;
748
749        for (cit = children.begin(); cit != children.end(); ++ cit)
750                area += (*cit)->GetBox().SurfaceArea();
751
752        const float areaRatio = area / node->GetBox().SurfaceArea();
753       
754        bool success;
755
756        if (areaRatio < mAreaRatioThreshold)
757                success = true;
758        else
759        {
760                // hack: only store node itself
761                children.clear();
762                children.push_back(node);
763
764                success = false;
765        }
766
767        // the new test nodes are added at the end of the vector
768        node->mTestNodesIdx = (int)mTestNodes.size();
769
770        // use the found nodes as nodes during the occlusion tests
771        for (cit = children.begin(); cit != children.end(); ++ cit)
772        {
773                BvhNode *child = *cit;
774                mTestNodes.push_back(child);
775        }
776
777        node->mNumTestNodes = (int)children.size();
778
779        return success;
780}
781
782
783void Bvh::ResetNodeClassifications()
784{
785        BvhNodeContainer nodes;
786
787        nodes.reserve(GetNumNodes());
788        CollectNodes(mRoot, nodes);
789
790        BvhNodeContainer::const_iterator lit, lit_end = nodes.end();
791
792        for (lit = nodes.begin(); lit != lit_end; ++ lit)
793        {
794                (*lit)->ResetVisibility();
795        }
796}
797
798
799void Bvh::ComputeBvhStats()
800{
801        std::stack<BvhNode *> nodeStack;
802        nodeStack.push(mRoot);
803
804        int numVirtualLeaves = 0;
805
806        while (!nodeStack.empty())
807        {
808                BvhNode *node = nodeStack.top();
809                nodeStack.pop();
810
811                if (node->IsVirtualLeaf())
812                {
813                        ++ numVirtualLeaves;
814
815                        BvhLeaf *leaf = static_cast<BvhLeaf *>(node);
816
817                        mBvhStats.mTriangles += CountTriangles(leaf);
818                        mBvhStats.mLeafSA += leaf->mBox.SurfaceArea();
819                        mBvhStats.mLeafVol += leaf->mBox.GetVolume();
820                }
821                else
822                {
823                        mBvhStats.mInteriorSA += node->mBox.SurfaceArea();
824                        mBvhStats.mInteriorVol += node->mBox.GetVolume();
825
826                        BvhInterior *interior = static_cast<BvhInterior *>(node);
827                       
828                        nodeStack.push(interior->mBack);
829                        nodeStack.push(interior->mFront);
830                }
831        }
832
833        mBvhStats.mGeometryRatio = mGeometrySize / (float)numVirtualLeaves;
834        mBvhStats.mTriangleRatio = mBvhStats.mTriangles / (float)numVirtualLeaves;
835}
836
837
838void Bvh::PrintBvhStats() const
839{
840        cout << "\n******** bvh stats: ***********" << endl;
841        cout << "interiorNodesSA = " << mBvhStats.mInteriorSA / mRoot->mBox.SurfaceArea() << endl;
842        cout << "leafNodesSA = " << mBvhStats.mLeafSA / mRoot->mBox.SurfaceArea() << endl;
843        cout << "interiorNodesVolume = " << mBvhStats.mInteriorVol / mRoot->mBox.GetVolume() << endl;
844        cout << "leafNodesVolume = " << mBvhStats.mLeafVol / mRoot->mBox.GetVolume() << endl;
845
846        cout << "geometry per leaf: " <<  mBvhStats.mGeometryRatio << endl;
847        cout << "triangles per leaf: " <<  mBvhStats.mTriangleRatio << endl;
848        cout << "**************" << endl << endl;
849}
850
851
852int Bvh::CountTriangles(BvhNode *node) const
853{
854        int numTriangles = 0;
855
856        for (int i = node->mFirst; i <= node->mLast; ++ i)
857        {
858                numTriangles += mGeometry[i]->CountNumTriangles(0);
859        }
860
861        return numTriangles;
862}
863
864
865float Bvh::GetArea(BvhNode *node) const
866{
867        return node->mArea;
868}
869
870
871void Bvh::UpdateNumLeaves(BvhNode *node) const
872{
873        if (node->IsLeaf())
874        {
875                node->mNumLeaves = 1;
876        }
877        else
878        {
879                BvhNode *f = static_cast<BvhInterior *>(node)->GetFront();
880                BvhNode *b = static_cast<BvhInterior *>(node)->GetBack();
881
882                UpdateNumLeaves(f);
883                UpdateNumLeaves(b);
884
885                node->mNumLeaves = f->mNumLeaves + b->mNumLeaves;
886        }
887}
888
889
890void Bvh::CollectVirtualLeaves(BvhNode *node, BvhNodeContainer &leaves)
891{
892        stack<BvhNode *> tStack;
893        tStack.push(node);
894
895        while (!tStack.empty())
896        {
897                BvhNode *node = tStack.top();
898                tStack.pop();
899
900                if (node->mIsVirtualLeaf)
901                {
902                        leaves.push_back(node);
903                }
904                else if (!node->IsLeaf())
905                {
906                        BvhInterior *interior = static_cast<BvhInterior *>(node);
907
908                        tStack.push(interior->mFront);
909                        tStack.push(interior->mBack);
910                }
911        }
912}
913
914
915void Bvh::SetVirtualLeaves(int numTriangles)
916{
917        // first invalidate old leaves
918        BvhNodeContainer leaves;
919
920        CollectVirtualLeaves(mRoot, leaves);
921
922        BvhNodeContainer::const_iterator bit, bit_end = leaves.end();
923
924        for (bit = leaves.begin(); bit != bit_end; ++ bit)
925        {
926                (*bit)->mIsVirtualLeaf = false;
927        }
928
929        mNumVirtualNodes = 0;
930
931        // assign new virtual leaves based on specified number of triangles per leaf
932        std::stack<BvhNode *> nodeStack;
933        nodeStack.push(mRoot);
934
935        while (!nodeStack.empty())
936        {
937                BvhNode *node = nodeStack.top();
938                nodeStack.pop();
939
940                ++ mNumVirtualNodes;
941
942                if (node->IsLeaf())
943                {
944                        BvhLeaf *leaf = static_cast<BvhLeaf *>(node);
945                        leaf->mIsVirtualLeaf = true;
946                }
947                else
948                {
949                        BvhInterior *interior = static_cast<BvhInterior *>(node);
950
951                        BvhNode *f = interior->mFront;
952                        BvhNode *b = interior->mBack;
953
954                        if (node->mIsMaxDepthForVirtualLeaf || (CountTriangles(node) <= numTriangles))
955                        {
956                                 node->mIsVirtualLeaf = true;
957                        }
958                        else
959                        {
960                                nodeStack.push(interior->mBack);
961                                nodeStack.push(interior->mFront);
962                        }
963                }
964        }
965
966        ResetNodeClassifications();
967}
968
969
970void Bvh::PostProcess()
971{
972        std::stack<BvhNode *> nodeStack;
973        nodeStack.push(mRoot);
974
975        while (!nodeStack.empty())
976        {
977                BvhNode *node = nodeStack.top();
978                nodeStack.pop();
979
980                if (node->IsLeaf())
981                {
982                        node->mIsMaxDepthForVirtualLeaf = true;
983                }
984                else
985                {
986                        BvhInterior *interior = static_cast<BvhInterior *>(node);
987
988                        BvhNode *f = interior->mFront;
989                        BvhNode *b = interior->mBack;
990
991                        // point reached where we cannot subdivide further on object level
992                        if ((f->mFirst == b->mFirst) && (f->mLast == b->mLast))
993                        {
994                                node->mIsMaxDepthForVirtualLeaf = true;
995                        }
996                        else
997                        {
998                                nodeStack.push(f);
999                                nodeStack.push(b);
1000                        }
1001                }
1002        }
1003}
1004
1005
1006void Bvh::RenderBoundingBoxImmediate(const AxisAlignedBox3 &box)
1007{
1008        const Vector3 l = box.Min();
1009        const Vector3 u = box.Max();
1010
1011        glBegin(GL_TRIANGLE_STRIP);
1012        {
1013                ///////////
1014                //-- render AABB as triangle strips
1015
1016                glVertex3f(l.x, l.y, u.z);
1017                glVertex3f(u.x, l.y, u.z);
1018                glVertex3f(l.x, u.y, u.z);
1019                glVertex3f(u.x, u.y, u.z);
1020                glVertex3f(l.x, u.y, l.z);
1021                glVertex3f(u.x, u.y, l.z);
1022                glVertex3f(l.x, l.y, l.z);
1023                glVertex3f(u.x, l.y, l.z);
1024
1025                glPrimitiveRestartNV();
1026
1027                //-- render second half of AABB
1028                glVertex3f(l.x, u.y, u.z);
1029                glVertex3f(l.x, u.y, l.z);
1030                glVertex3f(l.x, l.y, u.z);
1031                glVertex3f(l.x, l.y, l.z);
1032                glVertex3f(u.x, l.y, u.z);
1033                glVertex3f(u.x, l.y, l.z);
1034                glVertex3f(u.x, u.y, u.z);
1035                glVertex3f(u.x, u.y, l.z);
1036        }
1037        glEnd();
1038}
1039
1040
1041
1042
1043static void RenderBoxForViz(const AxisAlignedBox3 &box)
1044{
1045        glBegin(GL_LINE_LOOP);
1046        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
1047        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
1048        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
1049        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
1050        glEnd();
1051
1052        glBegin(GL_LINE_LOOP);
1053        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
1054        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
1055        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
1056        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
1057        glEnd();
1058
1059        glBegin(GL_LINE_LOOP);
1060        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
1061        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
1062        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
1063        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
1064        glEnd();
1065
1066        glBegin(GL_LINE_LOOP);
1067        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
1068        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
1069        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
1070        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
1071        glEnd();
1072
1073        glBegin(GL_LINE_LOOP);
1074        glVertex3d(box.Min().x, box.Min().y, box.Min().z);
1075        glVertex3d(box.Max().x, box.Min().y, box.Min().z);
1076        glVertex3d(box.Max().x, box.Min().y, box.Max().z);
1077        glVertex3d(box.Min().x, box.Min().y, box.Max().z);
1078        glEnd();
1079
1080        glBegin(GL_LINE_LOOP);
1081        glVertex3d(box.Min().x, box.Max().y, box.Min().z);
1082        glVertex3d(box.Max().x, box.Max().y, box.Min().z);
1083        glVertex3d(box.Max().x, box.Max().y, box.Max().z);
1084        glVertex3d(box.Min().x, box.Max().y, box.Max().z);
1085
1086        glEnd();
1087}
1088
1089
1090void Bvh::RenderBoundsForViz(BvhNode *node, RenderState *state, bool useTightBounds)
1091{
1092        glDisable(GL_TEXTURE_2D);
1093        glDisable(GL_LIGHTING);
1094        glColor3f(1, 1, 1);
1095
1096        // hack: for deferred shading we have to define a material
1097        static Technique boxMat;
1098        boxMat.SetEmmisive(RgbaColor(1.0f, 1.0f, 1.0f, 1.0f));
1099
1100        boxMat.Render(state);
1101
1102        if (!useTightBounds)
1103        {
1104                RenderBoxForViz(node->GetBox());
1105        }
1106        else
1107        {
1108                for (int i = 0; i < node->mNumTestNodes; ++ i)
1109                {
1110                        RenderBoxForViz(mTestNodes[node->mTestNodesIdx + i]->GetBox());
1111                }
1112        }
1113
1114        glEnable(GL_LIGHTING);
1115        glEnable(GL_TEXTURE_2D);
1116}
1117
1118
1119
1120////////////////////////
1121// construction of the dynamic hierarchy
1122
1123int Bvh::SortTriangles(BvhLeaf *leaf,
1124                                           int axis,
1125                                           float position,
1126                                           SceneEntityContainer &entities)
1127{
1128        int i = leaf->mFirst;
1129        int j = leaf->mLast;
1130
1131    while (1)
1132        {
1133                while (entities[i]->GetCenter()[axis] < position)
1134                        ++ i;
1135       
1136                while (position < entities[j]->GetCenter()[axis])
1137                        -- j;
1138
1139                if (i < j)
1140                {
1141                        swap(entities[i], entities[j]);
1142                       
1143                        ++ i;
1144                        -- j;
1145                }
1146                else
1147                {
1148                        break;
1149                }
1150        }
1151
1152        return j;
1153}
1154
1155
1156int Bvh::SortTrianglesSpatialMedian(BvhLeaf *leaf,
1157                                                                        int axis,
1158                                                                        SceneEntityContainer &entities)
1159{
1160        // spatial median
1161        float m = leaf->mBox.Center()[axis];
1162        return SortTriangles(leaf, axis, m, entities);
1163}
1164
1165
1166BvhNode *Bvh::SubdivideLeaf(BvhLeaf *leaf,
1167                                                        int parentAxis,
1168                                                        SceneEntityContainer &entities)
1169{
1170        if (TerminationCriteriaMet(leaf))
1171                return leaf;
1172       
1173        //int axis = leaf->mBox.MajorAxis();
1174        int axis = (parentAxis + 1) % 3;
1175
1176        // position of the split in the partailly sorted array of triangles
1177        // corresponding to this leaf
1178        int split = -1;
1179        const int scale = 20;
1180
1181        float pos = -1.0f;
1182
1183        // Spatial median subdivision
1184        split = SortTrianglesSpatialMedian(leaf, axis, entities);
1185        pos = leaf->mBox.Center()[axis];
1186       
1187        if (split == leaf->mLast)
1188        {
1189                // no split could be achieved => just halve number of objects
1190                split = (leaf->mLast - leaf->mFirst) / 2;
1191                cerr << "no reduction " << leaf->CountPrimitives() << " " << leaf->mFirst << " " << leaf->mLast << endl;
1192        }
1193
1194        // create two more nodes
1195        mNumNodes += 2;
1196        BvhInterior *parent = new BvhInterior(leaf->GetParent());
1197        BvhLeaf *front = new BvhLeaf(parent);
1198       
1199        parent->mAxis = axis;
1200        parent->mBox = leaf->mBox;
1201        parent->mDepth = leaf->mDepth;
1202
1203        parent->mBack = leaf;
1204        parent->mFront = front;
1205        //parent->mPosition = pos;
1206       
1207        // now assign the triangles to the subnodes
1208        front->mFirst = split + 1;
1209        front->mLast = leaf->mLast;
1210        front->mDepth = leaf->mDepth + 1;
1211        leaf->mLast = split;
1212        leaf->mDepth = front->mDepth;
1213        leaf->mParent = parent;
1214       
1215        // reset box
1216        leaf->mBox.Initialize();
1217
1218        // recursively continue subdivision
1219        parent->mBack = SubdivideLeaf(static_cast<BvhLeaf *>(parent->mBack), axis, entities);
1220        parent->mFront = SubdivideLeaf(static_cast<BvhLeaf *>(parent->mFront), axis, entities);
1221       
1222        return parent;
1223}
1224
1225
1226bool Bvh::TerminationCriteriaMet(BvhLeaf *leaf) const
1227{
1228        const bool criteriaMet =
1229                (leaf->mDepth > mMaxDepthForDynamicBranch) ||
1230                (leaf->CountPrimitives() == 1);
1231
1232        return criteriaMet;
1233}
1234
1235
1236void Bvh::UpdateDynamicBranch()
1237{
1238        BvhNode *dynamicRoot = static_cast<BvhInterior *>(mRoot)->mBack;
1239
1240        cout << "updating dynamic branch" << endl;
1241
1242        // delete old branch
1243        if (!dynamicRoot->IsLeaf())
1244        {
1245                cout << "deleting old branch" << endl;
1246
1247                DEL_PTR(dynamicRoot);
1248
1249                dynamicRoot = new BvhLeaf(mRoot);
1250                dynamicRoot->mBox = mRoot->mBox;
1251        }
1252
1253        dynamicRoot = SubdivideLeaf(static_cast<BvhLeaf *>(dynamicRoot), 0, mDynamicEntities);
1254}
1255
1256}
Note: See TracBrowser for help on using the repository browser.