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

Revision 3068, 29.2 KB checked in by mattausch, 16 years ago (diff)

working on dynamic stuff again

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