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

Revision 2954, 23.3 KB checked in by mattausch, 16 years ago (diff)

implemented sun color

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