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

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

debug version trying to find out how to speed up app

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