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

Revision 294, 24.8 KB checked in by mattausch, 19 years ago (diff)

vertical splitr criterium

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