source: trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellBsp.cpp @ 240

Revision 240, 16.4 KB checked in by mattausch, 19 years ago (diff)

added dome bsp tree stuff

Line 
1#include "Plane3.h"
2#include "ViewCellBsp.h"
3#include "Mesh.h"
4#include "common.h"
5#include "ViewCell.h"
6#include "Environment.h"
7#include "Polygon3.h"
8
9#include <stack>
10#include <time.h>
11#include <iomanip>
12
13#define INITIAL_COST 999999// unreachable high initial cost for heuristic evaluation
14
15int BspTree::sTermMaxPolygons = 10;
16int BspTree::sTermMaxDepth = 20;
17int BspTree::sSplitPlaneStrategy = NEXT_POLYGON;
18int BspTree::sMaxCandidates = 10;
19
20/****************************************************************/
21/*                  class BspNode implementation                */
22/****************************************************************/
23
24BspNode::BspNode(): mParent(NULL)
25{}
26
27BspNode::BspNode(BspInterior *parent): mParent(parent)
28{}
29
30
31bool BspNode::IsRoot() const
32{
33        return mParent == NULL;
34}
35
36BspInterior *BspNode::GetParent()
37{
38        return mParent;
39}
40
41void BspNode::SetParent(BspInterior *parent)
42{
43        mParent = parent;
44}
45
46/****************************************************************/
47/*              class BspInterior implementation                */
48/****************************************************************/
49
50
51BspInterior::BspInterior(Plane3 plane): mPlane(plane)
52{}
53
54bool BspInterior::IsLeaf() const
55{
56        return false;
57}
58
59BspNode *BspInterior::GetBack()
60{
61        return mBack;
62}
63
64BspNode *BspInterior::GetFront()
65{
66        return mFront;
67}
68
69Plane3 *BspInterior::GetPlane()
70{
71        return &mPlane;
72}
73
74void BspInterior::ReplaceChildLink(BspNode *oldChild, BspNode *newChild)
75{
76        if (mBack == oldChild)
77        {
78                mBack = newChild;
79        }
80    else
81        {
82                mFront = newChild;
83        }
84}
85
86void BspInterior::SetupChildLinks(BspNode *b, BspNode *f)
87{
88    mBack = b;
89    mFront = f;
90}
91
92void BspInterior::SplitPolygons(PolygonContainer *polys,
93                                                                PolygonContainer *frontPolys,
94                                                                PolygonContainer *backPolys,
95                                                                int &splits)
96{
97        while (!polys->empty())
98        {
99                Polygon3 *poly = polys->back();
100                polys->pop_back();
101
102                // test if split is neccessary
103                int result = poly->ClassifyPlane(mPlane);
104
105                Polygon3 *front_piece = NULL;
106                Polygon3 *back_piece = NULL;
107
108                switch (result)
109                {
110                        case Polygon3::COINCIDENT:
111                                break; // do nothing
112                        case Polygon3::FRONT_SIDE:
113                                frontPolys->push_back(poly);
114                                break;
115                        case Polygon3::BACK_SIDE:
116                                backPolys->push_back(poly);
117                                break;
118                        case Polygon3::SPLIT:
119                                front_piece = new Polygon3();
120                                back_piece = new Polygon3();
121
122                                //-- split polygon
123                                poly->Split(&mPlane, front_piece, back_piece, splits);
124
125                                frontPolys->push_back(front_piece);
126                                backPolys->push_back(back_piece);
127                               
128#ifdef _DEBUG
129                                Debug << "split " << poly << endl << front << endl << back << endl;
130#endif
131                                // don't need polygon anymore
132                                DEL_PTR(poly);
133
134                                break;
135                        default:
136                                Debug << "SHOULD NEVER COME HERE\n";
137                                break;
138                }
139        }
140}
141
142/****************************************************************/
143/*                  class BspLeaf implementation                */
144/****************************************************************/
145
146BspLeaf::BspLeaf(ViewCell *viewCell): mViewCell(viewCell)
147{
148}
149
150ViewCell *BspLeaf::GetViewCell()
151{
152        return mViewCell;
153}
154
155bool BspLeaf::IsLeaf() const
156{
157        return true;
158}
159
160
161/****************************************************************/
162/*                  class BspTree implementation                */
163/****************************************************************/
164
165BspTree::BspTree(): mTermMaxPolygons(0), mTermMaxDepth(0), mRoot(NULL)
166{
167        Randomize(); // initialise random generator for heuristics
168}
169 
170const BspTreeStatistics &BspTree::GetStatistics() const
171{
172        return mStat;
173}
174
175void BspTreeStatistics::Print(ostream &app) const
176{
177        app << "===== BspTree statistics ===============\n";
178
179        app << setprecision(4);
180
181        app << "#N_RAYS Number of rays )\n"
182                << rays <<endl;
183        app << "#N_DOMAINS  ( Number of query domains )\n"
184                << queryDomains <<endl;
185
186        app << "#N_NODES ( Number of nodes )\n" << nodes << "\n";
187
188        app << "#N_LEAVES ( Number of leaves )\n" << Leaves() << "\n";
189
190        app << "#N_SPLITS ( Number of splits)\n" << splits << "\n";
191
192        app << "#N_RAYREFS ( Number of rayRefs )\n" <<
193        rayRefs << "\n";
194
195        app << "#N_RAYRAYREFS  ( Number of rayRefs / ray )\n" <<
196        rayRefs/(double)rays << "\n";
197
198        app << "#N_LEAFRAYREFS  ( Number of rayRefs / leaf )\n" <<
199        rayRefs/(double)Leaves() << "\n";
200
201        app << "#N_MAXOBJECTREFS  ( Max number of rayRefs / leaf )\n" <<
202        maxObjectRefs << "\n";
203
204        app << "#N_NONEMPTYRAYREFS  ( Number of rayRefs in nonEmpty leaves / non empty leaf )\n" <<
205        rayRefsNonZeroQuery/(double)(Leaves() - zeroQueryNodes) << "\n";
206
207        app << "#N_LEAFDOMAINREFS  ( Number of query domain Refs / leaf )\n" <<
208        objectRefs/(double)Leaves() << "\n";
209
210        app << "#N_PEMPTYLEAVES  ( Percentage of leaves with zero query domains )\n"<<
211        zeroQueryNodes*100/(double)Leaves()<<endl;
212
213        app << "#N_PMAXDEPTHLEAVES ( Percentage of leaves at maxdepth )\n"<<
214        maxDepthNodes * 100 / (double)Leaves() << endl;
215
216        app << "#N_PMAXDEPTH ( Maximal reached depth )\n" << maxDepth <<endl;
217
218        app << "#N_ADDED_RAYREFS  (Number of dynamically added ray references )\n"<<
219        addedRayRefs<<endl;
220
221        app << "#N_REMOVED_RAYREFS  (Number of dynamically removed ray references )\n"<<
222        removedRayRefs<<endl;
223
224        //  app << setprecision(4);
225
226        //  app << "#N_CTIME  ( Construction time [s] )\n"
227        //      << Time() << " \n";
228
229        app << "===== END OF BspTree statistics ==========\n";
230}
231
232BspTree::~BspTree()
233{
234        std::stack<BspNode *> tStack;
235
236        tStack.push(mRoot);
237
238        while (!tStack.empty())
239        {
240                BspNode *node = tStack.top();
241
242            tStack.pop();
243       
244                if (!node->IsLeaf())
245                {
246                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
247
248                        // push the children on the stack (there are always two children)
249                        interior->GetBack()->mParent = NULL;
250                        interior->GetFront()->mParent = NULL;
251
252                        tStack.push(interior->GetBack());
253                        tStack.push(interior->GetFront());
254                }
255
256                DEL_PTR(node);
257        }
258}
259
260
261void BspTree::InsertViewCell(ViewCell *viewCell)
262{       
263        std::stack<BspTraversalData> tStack;
264       
265        PolygonContainer polys;
266        // copy polygon information to guide the split process
267        CopyMesh2Polygons(viewCell->GetMesh(), polys);
268
269        BspNode *firstNode = mRoot ? mRoot : new BspLeaf(); // traverse tree or create new one
270
271        tStack.push(BspTraversalData(firstNode, NULL, &polys, 0));
272
273        while (!tStack.empty())
274        {
275                // filter polygons donw the tree
276                BspTraversalData tData = tStack.top();
277
278            tStack.pop();
279                               
280        if (!tData.mNode->IsLeaf())
281                {
282                        BspInterior *interior = dynamic_cast<BspInterior *>(tData.mNode);
283
284                        //-- filter view cell polygons down the tree until a leaf is reached
285                        PolygonContainer *frontPolys = new PolygonContainer();
286                        PolygonContainer *backPolys = new PolygonContainer();
287
288                        int splits = 0;
289                        // split viecell polygons with respect to split plane
290                        interior->SplitPolygons(tData.mPolygons, frontPolys, backPolys, splits);
291                        mStat.splits += splits;
292
293                        // push the children on the stack
294                        if (frontPolys->size() > 0) // if polygons on this side of bsp tree
295                                tStack.push(BspTraversalData(interior->GetFront(), interior->GetParent(),
296                                                        frontPolys, tData.mDepth + 1));
297                        else
298                                delete frontPolys;
299
300                        if (backPolys->size() > 0) // if polygons on this side of bsp tree
301                                tStack.push(BspTraversalData(interior->GetBack(), interior->GetParent(),
302                                                        backPolys, tData.mDepth + 1));
303                        else
304                                delete backPolys;
305                }
306                else // reached leaf => subdivide current viewcell
307                {
308                        BspNode *root = Subdivide(tStack, tData, NULL);
309
310                        if (!mRoot) // take as root if there is none yet
311                                mRoot = root;                           
312                }
313        }
314}
315
316void BspTree::Construct(const ViewCellContainer &viewCells)
317{
318        // for this type of construction we split until no polygons is left
319        mTermMaxPolygons = 0;
320        mTermMaxDepth = sTermMaxDepth;
321
322        mStat.nodes = 1;
323
324        // insert all viewcells
325        ViewCellContainer::const_iterator it;
326
327        for (it = viewCells.begin(); it != viewCells.end(); ++ it)
328        {
329                InsertViewCell(*it);
330        }
331}
332
333void BspTree::CopyMesh2Polygons(Mesh *mesh, PolygonContainer &polys)
334{
335        FaceContainer::const_iterator fi;
336       
337        // copy the face data to polygons
338        for (fi = mesh->mFaces.begin(); fi != mesh->mFaces.end(); ++ fi)
339        {
340                Polygon3 *poly = new Polygon3((*fi), mesh);
341                polys.push_back(poly);
342        }
343}
344
345void BspTree::Copy2PolygonSoup(const ObjectContainer &objects, PolygonContainer &polys, int maxPolys)
346{
347        ObjectContainer::const_iterator it, it_end = objects.end();
348
349        int limit = (maxPolys > 0) ? min((int)objects.size(), maxPolys) : (int)objects.size();
350
351        for (int i = 0; i < limit; ++i)
352        {
353                Intersectable *object = objects[i];//*it;
354                Mesh *mesh = NULL;
355
356                // extract the meshes
357                switch (object->Type())
358                {
359                case Intersectable::MESH_INSTANCE:
360                        mesh = dynamic_cast<MeshInstance *>(object)->GetMesh();
361                        break;
362                case Intersectable::VIEWCELL:
363                        mesh = dynamic_cast<ViewCell *>(object)->GetMesh();
364                        break;
365                default:
366                        break;
367                }
368               
369                if (mesh) // copy the mesh data to polygons
370                {
371                        CopyMesh2Polygons(mesh, polys);
372                }
373        }
374
375        Debug << "Number of polygons: " << polys.size() << endl;
376}
377
378void BspTree::Construct(const ObjectContainer &objects)
379{
380        Debug << "Constructing tree using object container\n";
381
382        mTermMaxPolygons = sTermMaxPolygons;
383        mTermMaxDepth = sTermMaxDepth;
384
385        mStat.nodes = 1;
386
387        std::stack<BspTraversalData> tStack;
388        PolygonContainer *polys = new PolygonContainer();
389       
390        // copy mesh instance polygons into one big polygon soup
391        Copy2PolygonSoup(objects, *polys, 100);
392
393        BspTraversalData tData(new BspLeaf(), mRoot->GetParent(), polys, 0);
394
395        tStack.push(tData);
396
397        while (!tStack.empty())
398        {
399                tData = tStack.top();
400            tStack.pop();
401
402                // subdivide leaf node
403                BspNode *root = Subdivide(tStack, tData);
404
405                if (!mRoot)
406                        mRoot = root;
407        }
408}
409
410BspNode * BspTree::Subdivide(BspTraversalStack &tStack, BspTraversalData &tData, ViewCell *viewCell)
411{
412        PolygonContainer *backPolys = new PolygonContainer();
413        PolygonContainer *frontPolys = new PolygonContainer();
414
415        BspNode *node = SubdivideNode(dynamic_cast<BspLeaf *>(tData.mNode),
416                                                                  tData.mParent,
417                                                                  tData.mPolygons,
418                                                                  tData.mDepth,
419                                                                  viewCell,
420                                                                  frontPolys,
421                                                                  backPolys);
422
423        if (!node->IsLeaf()) // node was subdivided
424        {
425                BspInterior *interior = dynamic_cast<BspInterior *>(node);
426
427                // push the children on the stack (there are always two children)
428                tStack.push(BspTraversalData(interior->GetBack(), interior, backPolys, tData.mDepth + 1));
429                tStack.push(BspTraversalData(interior->GetFront(), interior, frontPolys, tData.mDepth + 1));
430        }
431        else // tree terminates here
432        {
433                EvaluateLeafStats(tData);
434                // don't need to store polygon information => delete polygons
435                Polygon3::DeletePolygons(tData.mPolygons);
436        }
437
438        return node;
439}
440
441Plane3 BspTree::SelectPlane(PolygonContainer *polygons)  const
442{
443        // simple strategy: just take next polygon
444        if (sSplitPlaneStrategy == NEXT_POLYGON)
445        {
446                return polygons->front()->GetSupportingPlane();
447        }
448       
449        return SelectPlaneHeuristics(polygons, sMaxCandidates);
450}
451
452Plane3 BspTree::SelectPlaneHeuristics(PolygonContainer *polygons, int maxTests) const
453{
454        int lowestCost = INITIAL_COST;
455        Plane3 *bestPlane = NULL;
456       
457        int limit = min((int)polygons->size(), maxTests);
458
459        for (int i = 0; i < limit; ++i)
460        {
461                int candidateIdx = Random((int)polygons->size());
462                Plane3 candidatePlane = (*polygons)[candidateIdx]->GetSupportingPlane();
463               
464                // evaluate current candidate
465                int candidateCost = EvalSplitPlane(polygons, candidatePlane);
466                       
467                if (candidateCost < lowestCost)
468                {
469                        bestPlane = &candidatePlane;
470                        lowestCost = candidateCost;
471                        //Debug << "new plane cost " << lowestCost << endl;
472                }
473        }
474               
475        return *bestPlane;
476}
477
478int BspTree::EvalSplitPlane(PolygonContainer *polygons, const Plane3 &candidatePlane) const
479{
480        PolygonContainer::const_iterator it;
481
482        int sum = 0, sum2 = 0;
483
484        for (it = polygons->begin(); it < polygons->end(); ++ it)
485        {
486                int classification = (*it)->ClassifyPlane(candidatePlane);
487               
488                if ((sSplitPlaneStrategy == BALANCED_TREE) || (sSplitPlaneStrategy == COMBINED))
489                {
490                        sum += EvalForBalancedTree(classification);
491                }
492               
493                if ((sSplitPlaneStrategy == LEAST_SPLITS) || (sSplitPlaneStrategy == COMBINED))
494                {
495                        sum2 += EvalForLeastSplits(classification);
496                }
497        }
498
499        // return linear combination of both sums
500        return abs(sum) + abs(sum2);
501}
502
503int BspTree::EvalForBalancedTree(const int classification)
504{
505        if (classification == Polygon3::FRONT_SIDE)
506                return 1;
507        else if (classification == Polygon3::BACK_SIDE)
508                return -1;
509
510        return 0;
511}
512
513int BspTree::EvalForLeastSplits(const int classification)
514{
515        if (classification == Polygon3::SPLIT)
516                return 1;
517
518        return 0;
519}
520
521BspNode *BspTree::SubdivideNode(BspLeaf *leaf,
522                                                                BspInterior *parent,
523                                                                PolygonContainer *polys,
524                                                                const int depth,
525                                                                ViewCell *viewCell,
526                                                                PolygonContainer *frontPolys,
527                                                                PolygonContainer *backPolys)
528{
529        // terminate traversal
530        if ((polys->size() <= mTermMaxPolygons) || (depth >= mTermMaxDepth))
531        {
532                return leaf;
533        }
534
535         mStat.nodes += 2;
536
537        // add the new nodes to the tree + select subdivision plane
538        BspInterior *node = new BspInterior(SelectPlane(polys));
539
540#ifdef _DEBUG
541        Debug << node << endl;
542#endif
543        // split polygon according to current plane
544        int splits = 0;
545        int polySize = polys->size();
546       
547        node->SplitPolygons(polys, frontPolys, backPolys, splits);
548       
549        mStat.splits += splits;
550
551        // two new leaves
552        BspLeaf *back = new BspLeaf();
553        BspLeaf *front = new BspLeaf(viewCell);
554
555        // replace a link from node's parent
556        if (parent)
557        {
558                parent->ReplaceChildLink(leaf, node);
559        }
560
561        // and setup child links
562        node->SetupChildLinks(back, front);
563
564        DEL_PTR(leaf); // leaf not member of tree anymore
565
566        return node;
567}
568
569void BspTree::ParseEnvironment()
570{
571        environment->GetIntValue("BspTree.Termination.maxDepth", sTermMaxDepth);
572        environment->GetIntValue("BspTree.Termination.maxPolygons", sTermMaxPolygons);
573        environment->GetIntValue("BspTree.maxCandidates", sMaxCandidates);
574
575        //-- extract strategy to choose the next split plane
576        char splitPlaneStrategyStr[60];
577
578        environment->GetStringValue("BspTree.splitPlaneStrategy", splitPlaneStrategyStr);
579       
580        sSplitPlaneStrategy = BspTree::NEXT_POLYGON;
581       
582        if (strcmp(splitPlaneStrategyStr, "nextPolygon") == 0)
583                sSplitPlaneStrategy = BspTree::NEXT_POLYGON;
584        else if (strcmp(splitPlaneStrategyStr, "leastSplits") == 0)
585                sSplitPlaneStrategy = BspTree::LEAST_SPLITS;
586        else if (strcmp(splitPlaneStrategyStr, "balancedTree") == 0)
587                sSplitPlaneStrategy = BspTree::BALANCED_TREE;
588        else
589        {
590                cerr << "Wrong BSP split plane strategy " << splitPlaneStrategyStr << endl;
591                exit(1);
592    }
593}
594
595void BspTree::CollectLeaves(vector<BspLeaf *> &leaves)
596{
597        stack<BspNode *> nodeStack;
598        nodeStack.push(mRoot);
599 
600        while (!nodeStack.empty())
601        {
602                BspNode *node = nodeStack.top();
603   
604                nodeStack.pop();
605   
606                if (node->IsLeaf())
607                {
608                        BspLeaf *leaf = (BspLeaf *)node;
609                       
610                        leaves.push_back(leaf);
611                } else
612                {
613                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
614                        nodeStack.push(interior->GetBack());
615                        nodeStack.push(interior->GetFront());
616                }
617        }
618}
619
620int BspTree::CollectLeafPvs()
621{
622        int totalPvsSize = 0;
623 
624        stack<BspNode *> nodeStack;
625 
626        nodeStack.push(mRoot);
627 
628        while (!nodeStack.empty())
629        {
630                BspNode *node = nodeStack.top();
631               
632                nodeStack.pop();
633               
634                if (node->IsLeaf())
635                {
636                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
637
638                        ViewCell *viewcell = leaf->GetViewCell();
639                       
640                        if (!viewcell->Mailed())
641                        {
642                                viewcell->Mail();
643                                       
644                                // add this node to pvs of all nodes it can see
645                                BspPvsMap::iterator ni;
646         
647        /*                      for (ni = object->mBspPvs.mEntries.begin(); ni != object->mKdPvs.mEntries.end(); ni++)
648                                {
649                                        BspNode *node = (*ni).first;
650           
651                                        // $$ JB TEMPORARY solution -> should add object PVS or explictly computed
652                                        // BSP tree PVS
653                                if (leaf->mBspPvs.AddNodeSample(node))
654                                                totalPvsSize++;
655                                }*/
656                        }
657                } else
658                {
659                        // traverse tree
660                        BspInterior *interior = (BspInterior *)node;
661     
662                        nodeStack.push(interior->GetFront());
663                        nodeStack.push(interior->GetBack());
664                }
665        }
666
667        return totalPvsSize;
668}
669
670void BspTree::EvaluateLeafStats(const BspTraversalData &data)
671{
672        // the node became a leaf -> evaluate stats for leafs
673        BspLeaf *leaf = dynamic_cast<BspLeaf *>(data.mNode);
674
675        if (data.mDepth >= mTermMaxDepth)
676        {
677                ++ mStat.maxDepthNodes;
678        }
679
680        // record maximal depth
681        if (data.mDepth > mStat.maxDepth)
682                mStat.maxDepth = data.mDepth;
683
684#ifdef _DEBUG
685        Debug << "BSP Traversal data. Depth: " << data.mDepth << " (max: " << mTermMaxDepth<< "), #polygons: " <<
686          data.mPolygons->size() << " (max: " << mTermMaxPolygons << ")" << endl;
687#endif
688}
689//} // GtpVisibilityPreprocessor
Note: See TracBrowser for help on using the repository browser.