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

Revision 295, 25.3 KB checked in by mattausch, 19 years ago (diff)

put out debug output. added new subdivision strategies

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#include "Ray.h"
9#include "AxisAlignedBox3.h"
10#include <stack>
11#include <time.h>
12#include <iomanip>
13#include "Exporter.h"
14
15int BspTree::sTermMaxPolygons = 10;
16int BspTree::sTermMaxDepth = 20;
17int BspTree::sMaxCandidates = 10;
18int BspTree::sSplitPlaneStrategy = NEXT_POLYGON;
19int BspTree::sConstructionMethod = VIEW_CELLS;
20
21/** Evaluates split plane classification with respect to the plane's
22        contribution for a balanced tree.
23*/
24float BspTree::sLeastSplitsTable[] = {0, 0, 1, 0};
25/** Evaluates split plane classification with respect to the plane's
26        contribution for a minimum number splits in the tree.
27*/
28float BspTree::sBalancedTreeTable[] = {-1, 1, 0, 0};
29
30//int counter = 0;
31
32/****************************************************************/
33/*                  class BspNode implementation                */
34/****************************************************************/
35
36BspNode::BspNode(): mParent(NULL), mPolygons(NULL)//,mViewCellIdx(0)
37{}
38
39BspNode::BspNode(BspInterior *parent): mParent(parent), mPolygons(NULL)//,mViewCellIdx(0)
40{}
41
42BspNode::~BspNode()
43{
44        if (mPolygons)
45        {
46                CLEAR_CONTAINER(*mPolygons);
47                DEL_PTR(mPolygons);
48        }
49}
50
51bool BspNode::IsRoot() const
52{
53        return mParent == NULL;
54}
55
56BspInterior *BspNode::GetParent()
57{
58        return mParent;
59}
60
61void BspNode::SetParent(BspInterior *parent)
62{
63        mParent = parent;
64}
65
66PolygonContainer *BspNode::GetPolygons()
67{
68        if (!mPolygons)
69                mPolygons = new PolygonContainer();
70
71        return mPolygons;
72}
73
74void BspNode::ProcessPolygons(PolygonContainer *polys, bool storePolys)
75{
76        if (storePolys)
77        {
78                while (!polys->empty())
79                {
80                        GetPolygons()->push_back(polys->back());
81                        polys->pop_back();
82                }
83        }
84        else CLEAR_CONTAINER(*polys);
85}
86
87
88/****************************************************************/
89/*              class BspInterior implementation                */
90/****************************************************************/
91
92
93BspInterior::BspInterior(const Plane3 &plane):
94mPlane(plane), mFront(NULL), mBack(NULL)
95{}
96
97bool BspInterior::IsLeaf() const
98{
99        return false;
100}
101
102BspNode *BspInterior::GetBack()
103{
104        return mBack;
105}
106
107BspNode *BspInterior::GetFront()
108{
109        return mFront;
110}
111
112Plane3 *BspInterior::GetPlane()
113{
114        return &mPlane;
115}
116
117void BspInterior::ReplaceChildLink(BspNode *oldChild, BspNode *newChild)
118{
119        if (mBack == oldChild)
120                mBack = newChild;
121        else
122                mFront = newChild;
123}
124
125void BspInterior::SetupChildLinks(BspNode *b, BspNode *f)
126{
127    mBack = b;
128    mFront = f;
129}
130
131void BspInterior::ProcessPolygon(Polygon3 **poly, const bool storePolys)
132{
133        if (storePolys)
134                GetPolygons()->push_back(*poly);
135        else
136                DEL_PTR(*poly);
137}
138
139void BspInterior::SplitPolygons(PolygonContainer *polys,
140                                                                PolygonContainer *frontPolys,
141                                                                PolygonContainer *backPolys,
142                                                                PolygonContainer *coincident,
143                                                                int &splits,
144                                                                bool storePolys)
145{
146        Polygon3 *splitPoly = NULL;
147#ifdef _Debug
148        Debug << "splitting polygons of node " << this << " with plane " << mPlane << endl;
149#endif
150        while (!polys->empty())
151        {
152                Polygon3 *poly = polys->back();
153                polys->pop_back();
154
155                //Debug << "New polygon with plane: " << poly->GetSupportingPlane() << "\n";
156
157                // get polygon classification
158                int classification = poly->ClassifyPlane(mPlane);
159
160                Polygon3 *front_piece = NULL;
161                Polygon3 *back_piece = NULL;
162       
163                switch (classification)
164                {
165                        case Polygon3::COINCIDENT:
166                                //Debug << "coincident" << endl;       
167                                coincident->push_back(poly);
168                                break;                 
169                        case Polygon3::FRONT_SIDE:     
170                                //Debug << "front" << endl;
171                                frontPolys->push_back(poly);
172                                break;
173                        case Polygon3::BACK_SIDE:
174                                //Debug << "back" << endl;
175                                backPolys->push_back(poly);
176                                break;
177                        case Polygon3::SPLIT:
178                                front_piece = new Polygon3(poly->mParent);
179                                back_piece = new Polygon3(poly->mParent);
180
181                                //-- split polygon into front and back part
182                                poly->Split(&mPlane, front_piece, back_piece);
183
184                                ++ splits; // increase number of splits
185                                // check if polygon still valid
186                                if (front_piece->mVertices.size() >= 3)
187                                        frontPolys->push_back(front_piece);
188                                else
189                                        DEL_PTR(front_piece);
190                                // check if polygon still valid
191                                if (back_piece->mVertices.size() >= 3)
192                                        backPolys->push_back(back_piece);
193                                else                           
194                                        DEL_PTR(back_piece);
195                               
196#ifdef _DEBUG
197                                Debug << "split " << *poly << endl << *front_piece << endl << *back_piece << endl;
198#endif
199                                ProcessPolygon(&poly, storePolys);
200                               
201                                break;
202                        default:
203                Debug << "SHOULD NEVER COME HERE\n";
204                                break;
205                }
206        }
207}
208
209/****************************************************************/
210/*                  class BspLeaf implementation                */
211/****************************************************************/
212BspLeaf::BspLeaf(): mViewCell(NULL)
213{
214}
215
216BspLeaf::BspLeaf(ViewCell *viewCell): mViewCell(viewCell)
217{
218}
219
220BspLeaf::BspLeaf(BspInterior *parent): BspNode(parent), mViewCell(NULL)
221{}
222
223BspLeaf::BspLeaf(BspInterior *parent, ViewCell *viewCell):
224BspNode(parent), mViewCell(viewCell)
225{
226}
227ViewCell *BspLeaf::GetViewCell()
228{
229        return mViewCell;
230}
231
232void BspLeaf::SetViewCell(ViewCell *viewCell)
233{
234        mViewCell = viewCell;
235}
236
237bool BspLeaf::IsLeaf() const
238{
239        return true;
240}
241
242/****************************************************************/
243/*                  class BspTree implementation                */
244/****************************************************************/
245
246BspTree::BspTree():
247mRoot(NULL),
248mVerticalAxis(Vector3(0, 0, 1)),
249//mStorePolys(true)
250mStorePolys(false)
251{
252        Randomize(); // initialise random generator for heuristics
253}
254 
255const BspTreeStatistics &BspTree::GetStatistics() const
256{
257        return mStat;
258}
259
260void BspTreeStatistics::Print(ostream &app) const
261{
262        app << "===== BspTree statistics ===============\n";
263
264        app << setprecision(4);
265
266        app << "#N_RAYS Number of rays )\n"
267                << rays << endl;
268        app << "#N_DOMAINS  ( Number of query domains )\n"
269                << queryDomains <<endl;
270
271        app << "#N_NODES ( Number of nodes )\n" << nodes << "\n";
272
273        app << "#N_INTERIORS ( Number of interior nodes )\n" << Interior() << "\n";
274
275        app << "#N_LEAVES ( Number of leaves )\n" << Leaves() << "\n";
276
277        app << "#N_SPLITS ( Number of splits )\n" << splits << "\n";
278
279        app << "#N_RAYREFS ( Number of rayRefs )\n" <<
280        rayRefs << "\n";
281
282        app << "#N_RAYRAYREFS  ( Number of rayRefs / ray )\n" <<
283        rayRefs/(double)rays << "\n";
284
285        app << "#N_LEAFRAYREFS  ( Number of rayRefs / leaf )\n" <<
286        rayRefs/(double)Leaves() << "\n";
287
288        app << "#N_MAXOBJECTREFS  ( Max number of rayRefs / leaf )\n" <<
289        maxObjectRefs << "\n";
290
291        app << "#N_NONEMPTYRAYREFS  ( Number of rayRefs in nonEmpty leaves / non empty leaf )\n" <<
292        rayRefsNonZeroQuery/(double)(Leaves() - zeroQueryNodes) << "\n";
293
294        app << "#N_LEAFDOMAINREFS  ( Number of query domain Refs / leaf )\n" <<
295        objectRefs/(double)Leaves() << "\n";
296
297        app << "#N_PEMPTYLEAVES  ( Percentage of leaves with zero query domains )\n"<<
298        zeroQueryNodes*100/(double)Leaves() << endl;
299
300        app << "#N_PMAXDEPTHLEAVES ( Percentage of leaves at maxdepth )\n"<<
301        maxDepthNodes * 100 / (double)Leaves() << endl;
302
303        app << "#N_PMAXDEPTH ( Maximal reached depth )\n" << maxDepth << endl;
304
305        app << "#N_PMINDEPTH ( Minimal reached depth )\n" << minDepth << endl;
306
307        app << "#AVGDEPTH ( average depth )\n" << AvgDepth() << endl;
308
309        app << "#N_ADDED_RAYREFS  ( Number of dynamically added ray references )\n"<<
310        addedRayRefs << endl;
311
312        app << "#N_REMOVED_RAYREFS  ( Number of dynamically removed ray references )\n" <<
313        removedRayRefs << endl;
314
315        app << "#N_INPUT_POLYGONS (number of input polygons )\n" <<
316                polys << endl;
317
318        app << "#N_ROUTPUT_INPUT_POLYGONS ( ratio polygons after subdivision / input polygons )\n" <<
319                 (polys + splits) / (double)polys << endl;
320       
321        app << "===== END OF BspTree statistics ==========\n";
322}
323
324BspTree::~BspTree()
325{
326        std::stack<BspNode *> tStack;
327
328        tStack.push(mRoot);
329
330        while (!tStack.empty())
331        {
332                BspNode *node = tStack.top();
333
334            tStack.pop();
335       
336                if (!node->IsLeaf())
337                {
338                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
339
340                        // push the children on the stack (there are always two children)
341                        tStack.push(interior->GetBack());
342                        tStack.push(interior->GetFront());
343                }
344
345                DEL_PTR(node);
346        }
347}
348
349void BspTree::InsertViewCell(ViewCell *viewCell)
350{
351        PolygonContainer *polys = new PolygonContainer();
352
353        // extract polygons that guide the split process
354        mStat.polys += AddMesh2Polygons(viewCell->GetMesh(), *polys);
355        mBox.Include(viewCell->GetBox()); // add to BSP aabb
356
357        InsertPolygons(polys);
358}
359
360void BspTree::InsertPolygons(PolygonContainer *polys, ViewCellContainer *viewCells)
361{       
362        std::stack<BspTraversalData> tStack;
363               
364        // traverse tree or create new one
365        BspNode *firstNode = mRoot ? mRoot : new BspLeaf();
366
367        tStack.push(BspTraversalData(firstNode, polys, 0, NULL));
368
369        while (!tStack.empty())
370        {
371                // filter polygons donw the tree
372                BspTraversalData tData = tStack.top();
373            tStack.pop();
374                       
375                if (!tData.mNode->IsLeaf())
376                {
377                        BspInterior *interior = dynamic_cast<BspInterior *>(tData.mNode);
378
379                        //-- filter view cell polygons down the tree until a leaf is reached
380                        if ((int)tData.mPolygons->size() > 0)
381                        {
382                                PolygonContainer *frontPolys = new PolygonContainer();
383                                PolygonContainer *backPolys = new PolygonContainer();
384                                PolygonContainer coincident;
385
386                                int splits = 0;
387               
388                                // split viecell polygons with respect to split plane
389                                interior->SplitPolygons(tData.mPolygons,
390                                                                                frontPolys,
391                                                                                backPolys,
392                                                                                &coincident,
393                                                                                splits,
394                                                                                mStorePolys);
395                               
396                                // get view cell associated with the split polygon
397                                ViewCell *viewCell = (coincident.size() > 0) ?
398                                        dynamic_cast<ViewCell *>(coincident.front()->mParent) : NULL;
399                                interior->ProcessPolygons(&coincident, mStorePolys);
400
401                                //Debug << "split node on level " << tData.mDepth << " bk: " << backPolys->size() << " frnt: " << frontPolys->size() << endl;
402                                mStat.splits += splits;
403
404                                // push the children on the stack
405                                tStack.push(BspTraversalData(interior->GetFront(), frontPolys, tData.mDepth + 1, NULL));
406                                tStack.push(BspTraversalData(interior->GetBack(), backPolys, tData.mDepth + 1, viewCell));
407                        }
408
409                        // cleanup
410                        DEL_PTR(tData.mPolygons);
411                }
412                else // reached leaf => subdivide current viewcell
413                {
414                        if (tData.mPolygons->size() > 0)
415                                Debug << "Subdividing further: polygon size: " << (int)tData.mPolygons->size() << ", view cell: " << tData.mViewCell << endl;
416
417                        BspNode *root = Subdivide(tStack, tData, viewCells);           
418
419                        if (!mRoot) // tree empty => new root
420                                mRoot = root;
421                }
422        }
423}
424
425int BspTree::AddMesh2Polygons(Mesh *mesh, PolygonContainer &polys, Intersectable *parent)
426{
427        FaceContainer::const_iterator fi;
428        int polysNum = 0;
429
430        // copy the face data to polygons
431        for (fi = mesh->mFaces.begin(); fi != mesh->mFaces.end(); ++ fi)
432        {
433                Polygon3 *poly = new Polygon3((*fi), mesh);
434                poly->mParent = parent; // set parent intersectable
435                polys.push_back(poly);
436
437                if (!poly->CheckValid())
438                        Debug << "Input polygon not valid: " << *poly << endl;
439
440                ++ polysNum;
441        }
442        return polysNum;
443}
444
445int BspTree::Copy2PolygonSoup(const ViewCellContainer &viewCells, PolygonContainer &polys, int maxObjects)
446{
447        int limit = (maxObjects > 0) ? Min((int)viewCells.size(), maxObjects) : (int)viewCells.size();
448 
449        for (int i = 0; i < limit; ++i)
450        {//if ((i == 12) ||(i==14))
451                if (viewCells[i]->GetMesh()) // copy the mesh data to polygons
452                {
453                        mBox.Include(viewCells[i]->GetBox()); // add to BSP tree aabb
454                        AddMesh2Polygons(viewCells[i]->GetMesh(), polys, viewCells[i]);
455                }
456        }
457
458        return (int)polys.size();
459}
460
461int BspTree::Copy2PolygonSoup(const ObjectContainer &objects, PolygonContainer &polys, int maxObjects)
462{
463        int limit = (maxObjects > 0) ? Min((int)objects.size(), maxObjects) : (int)objects.size();
464 
465        for (int i = 0; i < limit; ++i)
466        {
467                Intersectable *object = objects[i];//*it;
468                Mesh *mesh = NULL;
469
470                switch (object->Type()) // extract the meshes
471                {
472                case Intersectable::MESH_INSTANCE:
473                        mesh = dynamic_cast<MeshInstance *>(object)->GetMesh();
474                        break;
475                case Intersectable::VIEWCELL:
476                        mesh = dynamic_cast<ViewCell *>(object)->GetMesh();
477                        break;
478                        // TODO: handle transformed mesh instances
479                default:
480                        break;
481                }
482               
483        if (mesh) // copy the mesh data to polygons
484                {
485                        mBox.Include(object->GetBox()); // add to BSP tree aabb
486                        AddMesh2Polygons(mesh, polys);
487                }
488        }
489
490        return (int)polys.size();
491}
492
493void BspTree::Construct(const ViewCellContainer &viewCells)
494{
495        mStat.nodes = 1;
496        mBox.Initialize();      // initialise bsp tree bounding box
497
498        // copy view cell meshes into one big polygon soup
499        PolygonContainer *polys = new PolygonContainer();
500        mStat.polys = Copy2PolygonSoup(viewCells, *polys);
501
502        // construct tree from viewcell polygons
503        Construct(polys);
504        //Export("bsp.x3d");
505}
506
507
508void BspTree::Construct(const ObjectContainer &objects, ViewCellContainer *viewCells)
509{
510        mStat.nodes = 1;
511        mBox.Initialize();      // initialise bsp tree bounding box
512       
513        PolygonContainer *polys = new PolygonContainer();
514       
515        // copy mesh instance polygons into one big polygon soup
516        mStat.polys = Copy2PolygonSoup(objects, *polys);
517
518        // construct tree from polygon soup
519        Construct(polys, viewCells);
520}
521
522void BspTree::Construct(const RayContainer &rays, ViewCellContainer *viewCells)
523{
524        // TODO
525}
526
527void BspTree::Construct(PolygonContainer *polys, ViewCellContainer *viewCells)
528{
529        std::stack<BspTraversalData> tStack;
530       
531        BspTraversalData tData(new BspLeaf(), polys, 0, NULL);
532
533        tStack.push(tData);
534
535        long startTime = GetTime();
536        Debug << "**** Contructing tree using objects ****\n";
537        while (!tStack.empty())
538        {
539                tData = tStack.top();
540            tStack.pop();
541
542                // subdivide leaf node
543                BspNode *root = Subdivide(tStack, tData, viewCells);
544
545                // empty tree => new root corresponding to unbounded space
546                if (!mRoot)
547                        mRoot = root;
548        }
549
550        Debug << "**** Finished tree construction ****\n";
551        Debug << "BSP tree contruction time: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
552}
553
554
555BspNode *BspTree::Subdivide(BspTraversalStack &tStack, BspTraversalData &tData,
556                                                        ViewCellContainer *viewCells)
557{
558        //-- terminate traversal 
559        if ((tData.mPolygons->size() <= sTermMaxPolygons) || (tData.mDepth >= sTermMaxDepth))
560        {
561#ifdef _DEBUG
562                Debug << "subdivision terminated at depth " << tData.mDepth << ", #polys: " << (int)tData.mPolygons->size() << endl;
563#endif
564
565                EvaluateLeafStats(tData);
566
567                BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
568
569                //-- new viewcells are generated and added to each leaf
570                if (viewCells)
571                {
572                        ViewCell *viewCell = new ViewCell();
573                        leaf->SetViewCell(viewCell);
574                        viewCells->push_back(viewCell);
575                        // Debug << "creating new viewcell" << endl;
576                }
577                //-- add viewcell stored in split polygon
578                else if (tData.mViewCell)
579                {
580                        if (leaf->GetViewCell())
581                                Debug << "ERROR: leaf already has view cell " << endl;//leaf->mViewCellIdx << endl;
582
583                        //leaf->mViewCellIdx = counter; Debug << "insert view cell " << tData.mViewCell << endl;
584                        leaf->SetViewCell(dynamic_cast<ViewCell *>(tData.mViewCell));
585                }
586       
587                // remaining polygons are discarded or added to node
588                tData.mNode->ProcessPolygons(tData.mPolygons, mStorePolys);
589                DEL_PTR(tData.mPolygons);
590
591                return tData.mNode;
592        }
593
594        //-- continue subdivision
595        PolygonContainer *backPolys = new PolygonContainer();
596        PolygonContainer *frontPolys = new PolygonContainer();
597        PolygonContainer coincident;
598       
599        // create new interior node and two leaf nodes
600        BspInterior *interior = SubdivideNode(dynamic_cast<BspLeaf *>(tData.mNode),
601                                                                                  tData.mPolygons,
602                                                                                  frontPolys,
603                                                                                  backPolys,
604                                                                                  &coincident);
605
606        // view cell associated with the first split polygon
607        ViewCell *viewCell = (coincident.size() > 0) ?
608                                        dynamic_cast<ViewCell *>(coincident.front()->mParent) : NULL;
609        interior->ProcessPolygons(&coincident, mStorePolys);
610
611        // push the children on the stack
612        // split polygon is only needed in the back leaf
613        tStack.push(BspTraversalData(interior->GetFront(), frontPolys, tData.mDepth + 1, NULL));
614        tStack.push(BspTraversalData(interior->GetBack(), backPolys, tData.mDepth + 1, viewCell));
615
616        // cleanup
617        DEL_PTR(tData.mNode);
618        DEL_PTR(tData.mPolygons);
619
620        return interior;
621}
622
623
624BspInterior *BspTree::SubdivideNode(BspLeaf *leaf,
625                                                                        PolygonContainer *polys,
626                                                                        PolygonContainer *frontPolys,
627                                                                        PolygonContainer *backPolys,
628                                                                        PolygonContainer *coincident)
629{
630        mStat.nodes += 2;
631
632        // add the new nodes to the tree + select subdivision plane
633        BspInterior *interior = new BspInterior(SelectPlane(*polys));
634
635#ifdef _DEBUG
636        Debug << interior << endl;
637#endif
638
639        // split polygon according to current plane
640        int splits = 0;
641       
642        interior->SplitPolygons(polys, frontPolys, backPolys, coincident, splits, mStorePolys);
643       
644        mStat.splits += splits;
645
646        BspInterior *parent = leaf->GetParent();
647
648        // replace a link from node's parent
649        if (parent)
650        {
651                parent->ReplaceChildLink(leaf, interior);
652                interior->SetParent(parent);
653        }
654
655        // and setup child links
656        interior->SetupChildLinks(new BspLeaf(interior), new BspLeaf(interior));
657       
658        return interior;
659}
660
661Plane3 BspTree::SelectPlane(const PolygonContainer &polys)  const
662{
663        if (polys.size() == 0)
664        {
665                Debug << "Warning: No split candidate available\n";
666                return Plane3();
667        }
668
669        // simple strategy: just take next polygon
670        if (sSplitPlaneStrategy & NEXT_POLYGON)
671        {
672                return polys.front()->GetSupportingPlane();
673        }
674       
675        if (sSplitPlaneStrategy & AXIS_ALIGNED)
676        {
677                AxisAlignedBox3 box;
678                box.Initialize();
679       
680                Polygon3::IncludeInBox(polys, box);
681       
682                int axis = box.Size().DrivingAxis();
683                Vector3 norm(0,0,0); norm[axis] = 1;
684
685                Vector3 pt = (box.Min()[axis] + box.Max()[axis]) * 0.5f;
686
687                return Plane3(norm, pt);
688        }
689
690        /*if (sSplitPlaneStrategy & DRIVING_AXIS)
691        {
692                const float dot_thres = 0.999;
693                PolygonContainer::const_iterator it, it_end = polys->end();
694               
695                for (it = polys->begin(); it != it_end; ++ it)
696                {
697                        if (DotProd((*it)->GetSupportingPlane().mNormal, mVerticalAxis) > dot_thres)
698                                return (*it)->GetSupportingPlane();
699                }
700        }*/
701       
702        // use heuristics to find appropriate plane
703        return SelectPlaneHeuristics(polys, sMaxCandidates);
704}
705
706Plane3 BspTree::SelectPlaneHeuristics(const PolygonContainer &polys, int maxTests) const
707{
708        float lowestCost = MAX_FLOAT;
709        int bestPlaneIdx = 0;
710       
711        int limit = Min((int)polys.size(), maxTests);
712
713        for (int i = 0; i < limit; ++ i)
714        {
715                int candidateIdx = GetNextCandidateIdx((int)polys.size());
716                Plane3 candidatePlane = polys[candidateIdx]->GetSupportingPlane();
717               
718                // evaluate current candidate
719                float candidateCost = EvalSplitPlane(polys, candidatePlane);
720                       
721                if (candidateCost < lowestCost)
722                {
723                        bestPlaneIdx = candidateIdx;
724                        lowestCost = candidateCost;
725                }
726        }
727        //Debug << "Plane lowest cost: " << lowestCost << endl;
728       
729        return polys[bestPlaneIdx]->GetSupportingPlane();
730}
731
732int BspTree::GetNextCandidateIdx(const int max) const
733{
734        return Random(max); // TODO: avoid testing same plane 2 times
735}
736
737float BspTree::EvalSplitPlane(const PolygonContainer &polys, const Plane3 &candidatePlane) const
738{
739        float sumBalanced = 0, sumLeastSplits, drivingAxis = 0;
740       
741        if (sSplitPlaneStrategy & DRIVING_AXIS)
742        {
743        drivingAxis = (candidatePlane.mNormal.DrivingAxis() == mBox.Size().DrivingAxis()) ?
744                        99.0f : 0.0f; // always prefer driving axis => very high value
745        }
746        if ((sSplitPlaneStrategy & BALANCED_TREE) || (sSplitPlaneStrategy & LEAST_SPLITS))
747        {
748                PolygonContainer::const_iterator it, it_end = polys.end();
749               
750                for (it = polys.begin(); it != it_end; ++ it)
751                {
752                        int classification = (*it)->ClassifyPlane(candidatePlane);
753
754                        if (sSplitPlaneStrategy & BALANCED_TREE)
755                                sumBalanced += sBalancedTreeTable[classification];
756       
757                        if (sSplitPlaneStrategy & LEAST_SPLITS)
758                                sumLeastSplits += sLeastSplitsTable[classification];
759                }
760        }
761
762        // return linear combination of the sums
763        return fabs(sumBalanced) + sumLeastSplits + drivingAxis;
764}
765
766void BspTree::ParseEnvironment()
767{
768        environment->GetIntValue("BspTree.Termination.maxDepth", sTermMaxDepth);
769        environment->GetIntValue("BspTree.Termination.maxPolygons", sTermMaxPolygons);
770        environment->GetIntValue("BspTree.maxCandidates", sMaxCandidates);
771        environment->GetIntValue("BspTree.splitPlaneStrategy", sSplitPlaneStrategy);
772
773        Debug << "BSP max depth: " << sTermMaxDepth << endl;
774        Debug << "BSP max polys: " << sTermMaxPolygons << endl;
775        Debug << "BSP max candidates: " << sMaxCandidates << endl;
776
777        //-- parse BSP tree construction method
778        char constructionMethodStr[60];
779       
780        environment->GetStringValue("BspTree.constructionMethod", constructionMethodStr);
781
782        sConstructionMethod = BspTree::VIEW_CELLS;
783       
784        if (strcmp(constructionMethodStr, "viewCells") == 0)
785                sConstructionMethod = BspTree::VIEW_CELLS;
786        else if (strcmp(constructionMethodStr, "sceneGeometry") == 0)
787                sConstructionMethod = BspTree::SCENE_GEOMETRY;
788        else if (strcmp(constructionMethodStr, "rays") == 0)
789                sConstructionMethod = BspTree::RAYS;
790        else
791        {
792                cerr << "Wrong bsp construction method " << constructionMethodStr << endl;
793                exit(1);
794    }
795
796        Debug << "Construction method: " << constructionMethodStr << endl;
797}
798
799void BspTree::CollectLeaves(vector<BspLeaf *> &leaves)
800{
801        stack<BspNode *> nodeStack;
802        nodeStack.push(mRoot);
803 
804        while (!nodeStack.empty())
805        {
806                BspNode *node = nodeStack.top();
807   
808                nodeStack.pop();
809   
810                if (node->IsLeaf())
811                {
812                        BspLeaf *leaf = (BspLeaf *)node;
813                       
814                        leaves.push_back(leaf);
815                } else
816                {
817                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
818                        nodeStack.push(interior->GetBack());
819                        nodeStack.push(interior->GetFront());
820                }
821        }
822}
823
824int BspTree::CollectLeafPvs()
825{
826        int totalPvsSize = 0;
827 
828        stack<BspNode *> nodeStack;
829 
830        nodeStack.push(mRoot);
831 
832        while (!nodeStack.empty())
833        {
834                BspNode *node = nodeStack.top();
835               
836                nodeStack.pop();
837               
838                if (node->IsLeaf())
839                {
840                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
841
842                        ViewCell *viewcell = leaf->GetViewCell();
843                       
844                        if (!viewcell->Mailed())
845                        {
846                                viewcell->Mail(); // what does mail mean?
847                                       
848                                // add this node to pvs of all nodes it can see
849                                BspPvsMap::iterator ni;
850         
851        /*                      for (ni = object->mBspPvs.mEntries.begin(); ni != object->mKdPvs.mEntries.end(); ni++)
852                                {
853                                        BspNode *node = (*ni).first;
854           
855                                        // $$ JB TEMPORARY solution -> should add object PVS or explictly computed
856                                        // BSP tree PVS
857                                if (leaf->mBspPvs.AddNodeSample(node))
858                                                totalPvsSize++;
859                                }*/
860                        }
861                } else
862                {
863                        // traverse tree
864                        BspInterior *interior = (BspInterior *)node;
865     
866                        nodeStack.push(interior->GetFront());
867                        nodeStack.push(interior->GetBack());
868                }
869        }
870
871        return totalPvsSize;
872}
873
874AxisAlignedBox3 BspTree::GetBoundingBox() const
875{
876        return mBox;
877}
878
879BspNode *BspTree::GetRoot() const
880{
881        return mRoot;
882}
883
884bool BspTree::StorePolys() const
885{
886        return mStorePolys;
887}
888
889void BspTree::EvaluateLeafStats(const BspTraversalData &data)
890{
891        // the node became a leaf -> evaluate stats for leafs
892        BspLeaf *leaf = dynamic_cast<BspLeaf *>(data.mNode);
893
894        if (data.mDepth >= sTermMaxDepth)
895        {
896                ++ mStat.maxDepthNodes;
897        }
898
899        // store maximal and minimal depth
900        if (data.mDepth > mStat.maxDepth)
901                mStat.maxDepth = data.mDepth;
902        if (data.mDepth < mStat.minDepth)
903                mStat.minDepth = data.mDepth;
904
905        // accumulate depth to compute average
906        mStat.accumDepth += data.mDepth;
907
908        if (leaf->mViewCell)
909                ++ mStat.viewCellLeaves;
910
911#ifdef _DEBUG
912        Debug << "BSP Traversal data. Depth: " << data.mDepth << " (max: " << mTermMaxDepth << "), #polygons: " <<
913          data.mPolygons->size() << " (max: " << sTermMaxPolygons << ")" << endl;
914#endif
915}
916
917int BspTree::CastRay(Ray &ray)
918{
919        int hits = 0;
920 
921        stack<BspRayTraversalData> tStack;
922 
923        float maxt = 1e6;
924        float mint = 0;
925
926        Intersectable::NewMail();
927
928        // test with tree bounding box
929        if (!mBox.GetMinMaxT(ray, &mint, &maxt))
930                return 0;
931
932        if (mint < 0)
933                mint = 0;
934 
935        maxt += Limits::Threshold;
936 
937        Vector3 entp = ray.Extrap(mint);
938        Vector3 extp = ray.Extrap(maxt);
939 
940        BspNode *node = mRoot;
941        BspNode *farChild;
942       
943        while (1)
944        {
945                if (!node->IsLeaf())
946                {
947                        BspInterior *in = (BspInterior *) node;
948                       
949                        Plane3 *splitPlane = in->GetPlane();
950
951                        float t = 0;
952                        bool coplanar = false;
953               
954                        int entSide = splitPlane->Side(entp);
955                        int extSide = splitPlane->Side(extp);
956
957                        Vector3 intersection;
958
959                        if (entSide < 0)
960                        {
961                                node = in->GetBack();
962
963                                if(extSide <= 0)
964                                        continue;
965                                       
966                                farChild = in->GetFront(); // plane splits ray
967
968                        } else if (entSide > 0)
969                        {
970                                node = in->GetFront();
971
972                                if (extSide >= 0)
973                                        continue;
974
975                                farChild = in->GetBack();        // plane splits ray                   
976                        }
977                        else // ray and plane are coincident // WHAT TO DO IN THIS CASE ?
978                        {
979                                node = in->GetFront();
980                                continue;
981                        }
982
983                        //-- split
984
985                        // push data for far child
986                        tStack.push(BspRayTraversalData(farChild, extp, maxt));
987
988                        // find intersection with plane between ray origin and exit point
989                        extp = splitPlane->FindIntersection(ray.GetLoc(), extp, &maxt);
990
991                } else // compute intersections with objects in leaf
992                {
993                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
994                        //ray.leaves.push_back(leaf);
995      // TODO
996                        /*ObjectContainer::const_iterator mi;
997                        for (mi = leaf->mObjects.begin(); mi != leaf->mObjects.end(); ++mi)
998                        {
999                                Intersectable *object = *mi;
1000                                if (!object->Mailed())
1001                                {
1002                                        object->Mail();
1003                                        //ray.meshes.push_back(mesh);
1004                                        hits += object->CastRay(ray);
1005                                }
1006                        }*/
1007
1008                        if (hits && ray.GetType() == Ray::LOCAL_RAY)
1009                                if (ray.intersections[0].mT <= maxt)
1010                                        break;
1011     
1012                        // get the next node from the stack
1013                        if (tStack.empty())
1014                                break;
1015     
1016                        entp = extp;
1017                        mint = maxt;
1018                        BspRayTraversalData &s  = tStack.top();
1019
1020                        node = s.mNode;
1021                        extp = s.mExitPoint;
1022                        maxt = s.mMaxT;
1023
1024                        tStack.pop();
1025                }
1026        }
1027
1028        return hits;
1029}
1030
1031bool BspTree::Export(const string filename)
1032{
1033        Exporter *exporter = Exporter::GetExporter(filename);
1034
1035        if (exporter)
1036        {
1037                exporter->ExportBspTree(*this);
1038                return true;
1039        }       
1040
1041        return false;
1042}
1043//} // GtpVisibilityPreprocessor
Note: See TracBrowser for help on using the repository browser.