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

Revision 312, 33.1 KB checked in by mattausch, 19 years ago (diff)

bsp split exporter added

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;
[310]19int BspTree::sConstructionMethod = FROM_INPUT_VIEW_CELLS;
[297]20int BspTree::sTermMaxPolysForAxisAligned = 50;
[302]21
22float BspTree::sCt_div_ci = 1.0f;
23float BspTree::sSplitBorder = 1.0f;
[303]24float BspTree::sMaxCostRatio = 0.9f;
[224]25
[297]26//-- factors for bsp tree split plane heuristics
27float BspTree::sLeastSplitsFactor = 1.0f;
28float BspTree::sBalancedPolysFactor = 2.0f;
29float BspTree::sBalancedViewCellsFactor = 2.0f;
30float BspTree::sVerticalSplitsFactor = 1.0f; // very important criterium for 2.5d scenes
[306]31float BspTree::sLargestPolyAreaFactor = 1.0f;
[296]32
[263]33/** Evaluates split plane classification with respect to the plane's
34        contribution for a balanced tree.
35*/
[294]36float BspTree::sLeastSplitsTable[] = {0, 0, 1, 0};
[263]37/** Evaluates split plane classification with respect to the plane's
38        contribution for a minimum number splits in the tree.
39*/
[297]40float BspTree::sBalancedPolysTable[] = {-1, 1, 0, 0};
[263]41
[289]42//int counter = 0;
[294]43
[195]44/****************************************************************/
[221]45/*                  class BspNode implementation                */
[195]46/****************************************************************/
[235]47
[286]48BspNode::BspNode(): mParent(NULL), mPolygons(NULL)//,mViewCellIdx(0)
[265]49{}
[235]50
[286]51BspNode::BspNode(BspInterior *parent): mParent(parent), mPolygons(NULL)//,mViewCellIdx(0)
[235]52{}
53
[264]54BspNode::~BspNode()
55{
56        if (mPolygons)
57        {
58                CLEAR_CONTAINER(*mPolygons);
59                DEL_PTR(mPolygons);
60        }
61}
[265]62
[221]63bool BspNode::IsRoot() const
[190]64{
65        return mParent == NULL;
66}
67
[224]68BspInterior *BspNode::GetParent()
69{
70        return mParent;
71}
[235]72
73void BspNode::SetParent(BspInterior *parent)
74{
75        mParent = parent;
76}
77
[260]78PolygonContainer *BspNode::GetPolygons()
79{
[264]80        if (!mPolygons)
81                mPolygons = new PolygonContainer();
82
83        return mPolygons;
[260]84}
85
[264]86void BspNode::ProcessPolygons(PolygonContainer *polys, bool storePolys)
[263]87{
[264]88        if (storePolys)
[263]89        {
[264]90                while (!polys->empty())
91                {
92                        GetPolygons()->push_back(polys->back());
93                        polys->pop_back();
94                }
[263]95        }
[264]96        else CLEAR_CONTAINER(*polys);
[263]97}
98
99
[195]100/****************************************************************/
[221]101/*              class BspInterior implementation                */
[195]102/****************************************************************/
[194]103
[222]104
[263]105BspInterior::BspInterior(const Plane3 &plane):
106mPlane(plane), mFront(NULL), mBack(NULL)
[222]107{}
108
[221]109bool BspInterior::IsLeaf() const
[190]110{
111        return false;
112}
113
[222]114BspNode *BspInterior::GetBack()
115{
116        return mBack;
117}
118
119BspNode *BspInterior::GetFront()
120{
121        return mFront;
122}
123
124Plane3 *BspInterior::GetPlane()
125{
126        return &mPlane;
127}
128
[221]129void BspInterior::ReplaceChildLink(BspNode *oldChild, BspNode *newChild)
[195]130{
131        if (mBack == oldChild)
132                mBack = newChild;
[264]133        else
[195]134                mFront = newChild;
[267]135}
[195]136
[267]137void BspInterior::SetupChildLinks(BspNode *b, BspNode *f)
138{
139    mBack = b;
140    mFront = f;
141}
142
[289]143void BspInterior::ProcessPolygon(Polygon3 **poly, const bool storePolys)
[263]144{
[267]145        if (storePolys)
[289]146                GetPolygons()->push_back(*poly);
[267]147        else
[289]148                DEL_PTR(*poly);
[263]149}
150
[289]151void BspInterior::SplitPolygons(PolygonContainer *polys,
152                                                                PolygonContainer *frontPolys,
153                                                                PolygonContainer *backPolys,
154                                                                PolygonContainer *coincident,
155                                                                int &splits,
156                                                                bool storePolys)
[267]157{
[286]158        Polygon3 *splitPoly = NULL;
[275]159#ifdef _Debug
[294]160        Debug << "splitting polygons of node " << this << " with plane " << mPlane << endl;
[275]161#endif
[267]162        while (!polys->empty())
163        {
164                Polygon3 *poly = polys->back();
165                polys->pop_back();
166
[289]167                //Debug << "New polygon with plane: " << poly->GetSupportingPlane() << "\n";
[268]168
[293]169                // get polygon classification
[267]170                int classification = poly->ClassifyPlane(mPlane);
171
172                Polygon3 *front_piece = NULL;
173                Polygon3 *back_piece = NULL;
[268]174       
[312]175                VertexContainer splitVertices;
176
[267]177                switch (classification)
178                {
179                        case Polygon3::COINCIDENT:
[286]180                                //Debug << "coincident" << endl;       
[289]181                                coincident->push_back(poly);
182                                break;                 
[275]183                        case Polygon3::FRONT_SIDE:     
[286]184                                //Debug << "front" << endl;
[267]185                                frontPolys->push_back(poly);
186                                break;
187                        case Polygon3::BACK_SIDE:
[286]188                                //Debug << "back" << endl;
[267]189                                backPolys->push_back(poly);
190                                break;
191                        case Polygon3::SPLIT:
[286]192                                front_piece = new Polygon3(poly->mParent);
193                                back_piece = new Polygon3(poly->mParent);
[294]194
[290]195                                //-- split polygon into front and back part
[312]196                                poly->Split(mPlane, *front_piece, *back_piece, splitVertices);
[290]197
198                                ++ splits; // increase number of splits
[297]199
200                                // check if polygons still valid
[299]201                                if (front_piece->Valid())
[289]202                                        frontPolys->push_back(front_piece);
[294]203                                else
204                                        DEL_PTR(front_piece);
[297]205                               
[299]206                                if (back_piece->Valid())
[289]207                                        backPolys->push_back(back_piece);
[294]208                                else                           
209                                        DEL_PTR(back_piece);
[290]210                               
[275]211#ifdef _DEBUG
[286]212                                Debug << "split " << *poly << endl << *front_piece << endl << *back_piece << endl;
[275]213#endif
[289]214                                ProcessPolygon(&poly, storePolys);
[267]215                               
216                                break;
217                        default:
218                Debug << "SHOULD NEVER COME HERE\n";
219                                break;
220                }
[233]221        }
222}
223
[195]224/****************************************************************/
[221]225/*                  class BspLeaf implementation                */
[195]226/****************************************************************/
[263]227BspLeaf::BspLeaf(): mViewCell(NULL)
228{
229}
[195]230
[264]231BspLeaf::BspLeaf(ViewCell *viewCell): mViewCell(viewCell)
[190]232{
233}
234
[263]235BspLeaf::BspLeaf(BspInterior *parent): BspNode(parent), mViewCell(NULL)
236{}
237
[264]238BspLeaf::BspLeaf(BspInterior *parent, ViewCell *viewCell):
239BspNode(parent), mViewCell(viewCell)
240{
241}
[222]242ViewCell *BspLeaf::GetViewCell()
243{
244        return mViewCell;
245}
246
[260]247void BspLeaf::SetViewCell(ViewCell *viewCell)
248{
249        mViewCell = viewCell;
250}
251
[221]252bool BspLeaf::IsLeaf() const
[190]253{
254        return true;
255}
256
[195]257/****************************************************************/
[235]258/*                  class BspTree implementation                */
[225]259/****************************************************************/
260
[297]261BspTree::BspTree(ViewCell *viewCell):
[260]262mRoot(NULL),
[297]263mViewCell(viewCell),
[305]264//mStoreSplitPolys(true)
265mStoreSplitPolys(false)
[235]266{
[238]267        Randomize(); // initialise random generator for heuristics
[267]268}
269 
[235]270const BspTreeStatistics &BspTree::GetStatistics() const
271{
[267]272        return mStat;
273}
274
[235]275void BspTreeStatistics::Print(ostream &app) const
276{
277        app << "===== BspTree statistics ===============\n";
[225]278
[238]279        app << setprecision(4);
280
[235]281        app << "#N_RAYS Number of rays )\n"
[263]282                << rays << endl;
[235]283        app << "#N_DOMAINS  ( Number of query domains )\n"
284                << queryDomains <<endl;
[225]285
[235]286        app << "#N_NODES ( Number of nodes )\n" << nodes << "\n";
[225]287
[267]288        app << "#N_INTERIORS ( Number of interior nodes )\n" << Interior() << "\n";
[265]289
[235]290        app << "#N_LEAVES ( Number of leaves )\n" << Leaves() << "\n";
[225]291
[265]292        app << "#N_SPLITS ( Number of splits )\n" << splits << "\n";
[225]293
[235]294        app << "#N_RAYREFS ( Number of rayRefs )\n" <<
295        rayRefs << "\n";
[225]296
[235]297        app << "#N_RAYRAYREFS  ( Number of rayRefs / ray )\n" <<
298        rayRefs/(double)rays << "\n";
[225]299
[235]300        app << "#N_LEAFRAYREFS  ( Number of rayRefs / leaf )\n" <<
301        rayRefs/(double)Leaves() << "\n";
[225]302
[235]303        app << "#N_MAXOBJECTREFS  ( Max number of rayRefs / leaf )\n" <<
304        maxObjectRefs << "\n";
[225]305
[235]306        app << "#N_NONEMPTYRAYREFS  ( Number of rayRefs in nonEmpty leaves / non empty leaf )\n" <<
307        rayRefsNonZeroQuery/(double)(Leaves() - zeroQueryNodes) << "\n";
[225]308
[235]309        app << "#N_LEAFDOMAINREFS  ( Number of query domain Refs / leaf )\n" <<
310        objectRefs/(double)Leaves() << "\n";
[225]311
[235]312        app << "#N_PEMPTYLEAVES  ( Percentage of leaves with zero query domains )\n"<<
[263]313        zeroQueryNodes*100/(double)Leaves() << endl;
[225]314
[235]315        app << "#N_PMAXDEPTHLEAVES ( Percentage of leaves at maxdepth )\n"<<
[237]316        maxDepthNodes * 100 / (double)Leaves() << endl;
[225]317
[265]318        app << "#N_PMAXDEPTH ( Maximal reached depth )\n" << maxDepth << endl;
[225]319
[265]320        app << "#N_PMINDEPTH ( Minimal reached depth )\n" << minDepth << endl;
[225]321
[267]322        app << "#AVGDEPTH ( average depth )\n" << AvgDepth() << endl;
[195]323
[265]324        app << "#N_ADDED_RAYREFS  ( Number of dynamically added ray references )\n"<<
325        addedRayRefs << endl;
[235]326
[265]327        app << "#N_REMOVED_RAYREFS  ( Number of dynamically removed ray references )\n" <<
328        removedRayRefs << endl;
[235]329
[265]330        app << "#N_INPUT_POLYGONS (number of input polygons )\n" <<
331                polys << endl;
332
333        app << "#N_ROUTPUT_INPUT_POLYGONS ( ratio polygons after subdivision / input polygons )\n" <<
334                 (polys + splits) / (double)polys << endl;
335       
[235]336        app << "===== END OF BspTree statistics ==========\n";
[267]337}
338
339BspTree::~BspTree()
340{
341        std::stack<BspNode *> tStack;
342
343        tStack.push(mRoot);
344
345        while (!tStack.empty())
346        {
347                BspNode *node = tStack.top();
348
349            tStack.pop();
350       
351                if (!node->IsLeaf())
352                {
353                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
354
355                        // push the children on the stack (there are always two children)
356                        tStack.push(interior->GetBack());
357                        tStack.push(interior->GetFront());
358                }
359
360                DEL_PTR(node);
361        }
362}
363
[289]364void BspTree::InsertViewCell(ViewCell *viewCell)
365{
[267]366        PolygonContainer *polys = new PolygonContainer();
367
368        // extract polygons that guide the split process
[312]369        mStat.polys += AddMeshToPolygons(viewCell->GetMesh(), *polys, viewCell);
[267]370        mBox.Include(viewCell->GetBox()); // add to BSP aabb
371
[289]372        InsertPolygons(polys);
373}
374
375void BspTree::InsertPolygons(PolygonContainer *polys, ViewCellContainer *viewCells)
376{       
377        std::stack<BspTraversalData> tStack;
378               
379        // traverse tree or create new one
[267]380        BspNode *firstNode = mRoot ? mRoot : new BspLeaf();
381
[297]382        tStack.push(BspTraversalData(firstNode, polys, 0, mViewCell));
[267]383
384        while (!tStack.empty())
385        {
386                // filter polygons donw the tree
387                BspTraversalData tData = tStack.top();
388            tStack.pop();
389                       
390                if (!tData.mNode->IsLeaf())
391                {
392                        BspInterior *interior = dynamic_cast<BspInterior *>(tData.mNode);
393
394                        //-- filter view cell polygons down the tree until a leaf is reached
395                        if ((int)tData.mPolygons->size() > 0)
396                        {
397                                PolygonContainer *frontPolys = new PolygonContainer();
398                                PolygonContainer *backPolys = new PolygonContainer();
[289]399                                PolygonContainer coincident;
[267]400
401                                int splits = 0;
402               
[312]403                                // split viewcell polygons with respect to split plane
[289]404                                interior->SplitPolygons(tData.mPolygons,
405                                                                                frontPolys,
406                                                                                backPolys,
407                                                                                &coincident,
408                                                                                splits,
[304]409                                                                                mStoreSplitPolys);
[276]410                               
[297]411                                // extract view cells associated with the split polygons
412                                ViewCell *frontViewCell = mViewCell;
413                                ViewCell *backViewCell = mViewCell;
414       
415                                if (!viewCells)
416                                {
417                                        ExtractViewCells(&backViewCell,
418                                                                         &frontViewCell,
419                                                                         coincident,
420                                                                         interior->mPlane,
421                                                                         frontPolys->empty(),
422                                                                         backPolys->empty());
423                                }
424
425                                // don't need coincident polygons anymore
[304]426                                interior->ProcessPolygons(&coincident, mStoreSplitPolys);
[289]427
[267]428                                mStat.splits += splits;
429
430                                // push the children on the stack
[297]431                                tStack.push(BspTraversalData(interior->GetFront(), frontPolys, tData.mDepth + 1, frontViewCell));
432                                tStack.push(BspTraversalData(interior->GetBack(), backPolys, tData.mDepth + 1, backViewCell));
[267]433                        }
[289]434
435                        // cleanup
436                        DEL_PTR(tData.mPolygons);
[267]437                }
438                else // reached leaf => subdivide current viewcell
439                {
[308]440                        //if (tData.mPolygons->size() > 0) Debug << "Subdividing further: polygon size: " << (int)tData.mPolygons->size() << ", view cell: " << tData.mViewCell << endl;
441                        BspNode *root = Subdivide(tStack, tData);               
[267]442
[308]443                        if (viewCells && root->IsLeaf())
444                        {       // generate new view cell for each leaf
445                                ViewCell *viewCell = new ViewCell();
446                                viewCells->push_back(viewCell);
447                               
448                                dynamic_cast<BspLeaf *>(root)->SetViewCell(viewCell);
[312]449                        }
450
[267]451                        if (!mRoot) // tree empty => new root
452                                mRoot = root;
453                }
454        }
[289]455}
[267]456
[312]457int BspTree::AddMeshToPolygons(Mesh *mesh, PolygonContainer &polys, MeshInstance *parent)
[267]458{
459        FaceContainer::const_iterator fi;
460        int polysNum = 0;
461
462        // copy the face data to polygons
463        for (fi = mesh->mFaces.begin(); fi != mesh->mFaces.end(); ++ fi)
464        {
465                Polygon3 *poly = new Polygon3((*fi), mesh);
[286]466                poly->mParent = parent; // set parent intersectable
[267]467                polys.push_back(poly);
[289]468
[306]469                //if (!poly->Valid())
470                //      Debug << "Input polygon not valid: " << *poly << endl << "Area: " << poly->GetArea() << endl;
[301]471               
[286]472                ++ polysNum;
[267]473        }
474        return polysNum;
475}
476
477int BspTree::Copy2PolygonSoup(const ViewCellContainer &viewCells, PolygonContainer &polys, int maxObjects)
478{
[260]479        int limit = (maxObjects > 0) ? Min((int)viewCells.size(), maxObjects) : (int)viewCells.size();
480 
[267]481        for (int i = 0; i < limit; ++i)
[275]482        {//if ((i == 12) ||(i==14))
[267]483                if (viewCells[i]->GetMesh()) // copy the mesh data to polygons
484                {
485                        mBox.Include(viewCells[i]->GetBox()); // add to BSP tree aabb
[312]486                        AddMeshToPolygons(viewCells[i]->GetMesh(), polys, viewCells[i]);
[267]487                }
488        }
489
490        return (int)polys.size();
491}
492
493int BspTree::Copy2PolygonSoup(const ObjectContainer &objects, PolygonContainer &polys, int maxObjects)
494{
[245]495        int limit = (maxObjects > 0) ? Min((int)objects.size(), maxObjects) : (int)objects.size();
[241]496 
[267]497        for (int i = 0; i < limit; ++i)
498        {
499                Intersectable *object = objects[i];//*it;
500                Mesh *mesh = NULL;
[260]501
[267]502                switch (object->Type()) // extract the meshes
503                {
504                case Intersectable::MESH_INSTANCE:
505                        mesh = dynamic_cast<MeshInstance *>(object)->GetMesh();
506                        break;
[308]507                case Intersectable::VIEW_CELL:
[267]508                        mesh = dynamic_cast<ViewCell *>(object)->GetMesh();
509                        break;
510                        // TODO: handle transformed mesh instances
511                default:
[303]512                        Debug << "intersectable type not supported" << endl;
[267]513                        break;
514                }
515               
516        if (mesh) // copy the mesh data to polygons
517                {
518                        mBox.Include(object->GetBox()); // add to BSP tree aabb
[312]519                        AddMeshToPolygons(mesh, polys, mViewCell);
[267]520                }
521        }
[260]522
[267]523        return (int)polys.size();
[260]524}
525
[267]526void BspTree::Construct(const ViewCellContainer &viewCells)
527{
[295]528        mStat.nodes = 1;
529        mBox.Initialize();      // initialise bsp tree bounding box
[267]530
[286]531        // copy view cell meshes into one big polygon soup
532        PolygonContainer *polys = new PolygonContainer();
[290]533        mStat.polys = Copy2PolygonSoup(viewCells, *polys);
[267]534
[286]535        // construct tree from viewcell polygons
536        Construct(polys);
[267]537}
538
539
540void BspTree::Construct(const ObjectContainer &objects, ViewCellContainer *viewCells)
541{
[295]542        mStat.nodes = 1;
543        mBox.Initialize();      // initialise bsp tree bounding box
[267]544       
545        PolygonContainer *polys = new PolygonContainer();
546       
547        // copy mesh instance polygons into one big polygon soup
548        mStat.polys = Copy2PolygonSoup(objects, *polys);
549
550        // construct tree from polygon soup
551        Construct(polys, viewCells);
552}
553
[261]554void BspTree::Construct(const RayContainer &rays, ViewCellContainer *viewCells)
[260]555{
556        // TODO
557}
558
[267]559void BspTree::Construct(PolygonContainer *polys, ViewCellContainer *viewCells)
560{
561        std::stack<BspTraversalData> tStack;
562       
[297]563        BspTraversalData tData(new BspLeaf(), polys, 0, mViewCell);
[267]564        tStack.push(tData);
565
566        long startTime = GetTime();
567        Debug << "**** Contructing tree using objects ****\n";
568        while (!tStack.empty())
569        {
570                tData = tStack.top();
571            tStack.pop();
572
573                // subdivide leaf node
[308]574                BspNode *root = Subdivide(tStack, tData);
[239]575
[308]576                if (viewCells && root->IsLeaf())
577                {       // generate new view cell for each leaf
578                        ViewCell *viewCell = new ViewCell();
579                        viewCells->push_back(viewCell);
580
581                        dynamic_cast<BspLeaf *>(root)->SetViewCell(viewCell);
582                }
583
[263]584                // empty tree => new root corresponding to unbounded space
[262]585                if (!mRoot)
[239]586                        mRoot = root;
[267]587        }
[233]588
[267]589        Debug << "**** Finished tree construction ****\n";
[294]590        Debug << "BSP tree contruction time: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
[267]591}
[260]592
[267]593
[308]594BspNode *BspTree::Subdivide(BspTraversalStack &tStack, BspTraversalData &tData)
[267]595{
596        //-- terminate traversal 
[295]597        if ((tData.mPolygons->size() <= sTermMaxPolygons) || (tData.mDepth >= sTermMaxDepth))
[267]598        {
[303]599#ifdef _DEBUG
[308]600                Debug << "subdivision terminated at depth " << tData.mDepth << ", #polys: "
601                          << (int)tData.mPolygons->size() << endl;
[303]602#endif
[267]603
604                EvaluateLeafStats(tData);
605
[286]606                BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
[308]607               
608                // add view cell to leaf
609                if (!leaf->GetViewCell())
[303]610                        leaf->SetViewCell(tData.mViewCell);
[267]611
[289]612                // remaining polygons are discarded or added to node
[308]613                leaf->ProcessPolygons(tData.mPolygons, mStoreSplitPolys);
[289]614                DEL_PTR(tData.mPolygons);
615
[308]616                return leaf;
[267]617        }
618
[289]619        //-- continue subdivision
[267]620        PolygonContainer *backPolys = new PolygonContainer();
621        PolygonContainer *frontPolys = new PolygonContainer();
[289]622        PolygonContainer coincident;
[276]623       
[289]624        // create new interior node and two leaf nodes
[267]625        BspInterior *interior = SubdivideNode(dynamic_cast<BspLeaf *>(tData.mNode),
626                                                                                  tData.mPolygons,
627                                                                                  frontPolys,
[276]628                                                                                  backPolys,
[289]629                                                                                  &coincident);
[267]630
[297]631        ViewCell *frontViewCell = mViewCell;
632        ViewCell *backViewCell = mViewCell;
[308]633
634#ifdef _DEBUG   
635        if (frontPolys->empty() && backPolys->empty() && (coincident.size() > 2))
636        {       for (PolygonContainer::iterator it = coincident.begin(); it != coincident.end(); ++it)
637                        Debug << (*it) << " " << (*it)->GetArea() << " " << (*it)->mParent << endl ;
638                Debug << endl;}
639#endif
640
641        //-- extract view cells from coincident polygons according to plane normal
642        ExtractViewCells(&backViewCell, &frontViewCell, coincident, interior->mPlane,
643                                                 frontPolys->empty(), backPolys->empty());
[297]644       
645        // don't need coincident polygons anymore
[304]646        interior->ProcessPolygons(&coincident, mStoreSplitPolys);
[289]647
[267]648        // push the children on the stack
[289]649        // split polygon is only needed in the back leaf
[297]650        tStack.push(BspTraversalData(interior->GetFront(), frontPolys, tData.mDepth + 1, frontViewCell));
651        tStack.push(BspTraversalData(interior->GetBack(), backPolys, tData.mDepth + 1, backViewCell));
[267]652
[289]653        // cleanup
654        DEL_PTR(tData.mNode);
655        DEL_PTR(tData.mPolygons);
656
[267]657        return interior;
[195]658}
[190]659
[297]660void BspTree::ExtractViewCells(ViewCell **backViewCell,
661                                                           ViewCell **frontViewCell,
662                                                           const PolygonContainer &coincident,
663                                                           const Plane3 splitPlane,
664                                                           const bool extractFront,
665                                                           const bool extractBack) const
666{
667        bool foundFront = !extractFront, foundBack = !extractBack;
[262]668
[297]669        PolygonContainer::const_iterator it, it_end = coincident.end();
670
[308]671        //-- find first view cells in front and back leafs
[297]672        for (it = coincident.begin(); !(foundFront && foundBack) &&
[308]673                (it != it_end); ++ it)
[297]674        {
675                if (DotProd((*it)->GetSupportingPlane().mNormal, splitPlane.mNormal > 0))
676                {
677                        *backViewCell = dynamic_cast<ViewCell *>((*it)->mParent);
678                        foundBack = true;
679                }
680                else
681                {
682                        *frontViewCell = dynamic_cast<ViewCell *>((*it)->mParent);
683                        foundFront = true;
684                }
[303]685                //if (foundFront) Debug << "front viewCell: " << *frontViewCell << endl;
686                //if (foundBack) Debug << "back viewCell: " << *backViewCell << endl;
[297]687        }
688}
689
[267]690BspInterior *BspTree::SubdivideNode(BspLeaf *leaf,
691                                                                        PolygonContainer *polys,
[276]692                                                                        PolygonContainer *frontPolys,
[289]693                                                                        PolygonContainer *backPolys,
694                                                                        PolygonContainer *coincident)
[267]695{
696        mStat.nodes += 2;
697
698        // add the new nodes to the tree + select subdivision plane
[302]699        BspInterior *interior = new BspInterior(SelectPlane(leaf, *polys));
[267]700
701#ifdef _DEBUG
702        Debug << interior << endl;
703#endif
704
705        // split polygon according to current plane
706        int splits = 0;
707       
[304]708        interior->SplitPolygons(polys, frontPolys, backPolys, coincident, splits, mStoreSplitPolys);
[289]709       
[267]710        mStat.splits += splits;
711
712        BspInterior *parent = leaf->GetParent();
713
714        // replace a link from node's parent
715        if (parent)
716        {
717                parent->ReplaceChildLink(leaf, interior);
718                interior->SetParent(parent);
719        }
720
721        // and setup child links
722        interior->SetupChildLinks(new BspLeaf(interior), new BspLeaf(interior));
723       
724        return interior;
[260]725}
726
[302]727void BspTree::SortSplitCandidates(const PolygonContainer &polys,
728                                                                  const int axis,
729                                                                  vector<SortableEntry> &splitCandidates) const
[195]730{
[302]731  splitCandidates.clear();
732 
733  int requestedSize = 2 * (int)polys.size();
734  // creates a sorted split candidates array 
735  splitCandidates.reserve(requestedSize);
736 
737  PolygonContainer::const_iterator it, it_end = polys.end();
738
739  AxisAlignedBox3 box;
740
741  // insert all queries
742  for(it = polys.begin(); it != it_end; ++ it)
743  {
744          box.Initialize();
745          box.Include(*(*it));
746         
747          splitCandidates.push_back(SortableEntry(SortableEntry::POLY_MIN, box.Min(axis), *it));
748      splitCandidates.push_back(SortableEntry(SortableEntry::POLY_MAX, box.Max(axis), *it));
749  }
750 
751  stable_sort(splitCandidates.begin(), splitCandidates.end());
752}
753
754
755float BspTree::BestCostRatio(const PolygonContainer &polys,
756                                                         const AxisAlignedBox3 &box,
757                                                         const int axis,
758                                                         float &position,
759                                                         int &objectsBack,
760                                                         int &objectsFront) const
761{
762        vector<SortableEntry> splitCandidates;
763
764        SortSplitCandidates(polys, axis, splitCandidates);
765       
766        // go through the lists, count the number of objects left and right
767        // and evaluate the following cost funcion:
768        // C = ct_div_ci  + (ol + or)/queries
769       
770        int objectsLeft = 0, objectsRight = (int)polys.size();
771       
772        float minBox = box.Min(axis);
773        float maxBox = box.Max(axis);
774        float boxArea = box.SurfaceArea();
775 
776        float minBand = minBox + sSplitBorder * (maxBox - minBox);
777        float maxBand = minBox + (1.0f - sSplitBorder) * (maxBox - minBox);
778       
779        float minSum = 1e20f;
780        vector<SortableEntry>::const_iterator ci, ci_end = splitCandidates.end();
781
782        for(ci = splitCandidates.begin(); ci != ci_end; ++ ci)
783        {
784                switch ((*ci).type)
785                {
786                        case SortableEntry::POLY_MIN:
787                                ++ objectsLeft;
788                                break;
789                        case SortableEntry::POLY_MAX:
790                            -- objectsRight;
791                                break;
792                        default:
793                                break;
794                }
795               
796                if ((*ci).value > minBand && (*ci).value < maxBand)
797                {
798                        AxisAlignedBox3 lbox = box;
799                        AxisAlignedBox3 rbox = box;
800                        lbox.SetMax(axis, (*ci).value);
801                        rbox.SetMin(axis, (*ci).value);
802
803                        float sum = objectsLeft * lbox.SurfaceArea() +
804                                                objectsRight * rbox.SurfaceArea();
805     
806                        if (sum < minSum)
807                        {
808                                minSum = sum;
809                                position = (*ci).value;
810
811                                objectsBack = objectsLeft;
812                                objectsFront = objectsRight;
813                        }
814                }
815        }
816 
817        float oldCost = (float)polys.size();
818        float newCost = sCt_div_ci + minSum / boxArea;
819        float ratio = newCost / oldCost;
820
821
822#if 0
823  Debug << "====================" << endl;
824  Debug << "costRatio=" << ratio << " pos=" << position<<" t=" << (position - minBox)/(maxBox - minBox)
825      << "\t o=(" << objectsBack << "," << objectsFront << ")" << endl;
826#endif
827  return ratio;
828}
829
[305]830Plane3 BspTree::SelectPlane(BspLeaf *leaf, PolygonContainer &polys)
[302]831{
[295]832        if (polys.size() == 0)
[263]833        {
834                Debug << "Warning: No split candidate available\n";
835                return Plane3();
836        }
837
[297]838        if ((sSplitPlaneStrategy & AXIS_ALIGNED) &&
839                ((int)polys.size() > sTermMaxPolysForAxisAligned))
[236]840        {
[295]841                AxisAlignedBox3 box;
842                box.Initialize();
843       
[297]844                // todo: area subdivision
[295]845                Polygon3::IncludeInBox(polys, box);
846       
[301]847                int objectsBack = 0, objectsFront = 0;
848                int axis = 0;
849                float costRatio = MAX_FLOAT;
850                Vector3 position;
851
[302]852                for (int i = 0; i < 3; ++ i)
[301]853                {
854                        float p = 0;
[302]855                        float r = BestCostRatio(polys, box, i, p, objectsBack, objectsFront);
856                       
[301]857                        if (r < costRatio)
858                        {
859                                costRatio = r;
860                                axis = i;
861                                position = p;
862                        }
863                }
864               
[302]865                if (costRatio < sMaxCostRatio)
866                {
867                        Vector3 norm(0,0,0); norm[axis] = 1.0f;
868                        return Plane3(norm, position);
869                }
[301]870                /*int axis = box.Size().DrivingAxis();
[295]871                Vector3 norm(0,0,0); norm[axis] = 1;
[304]872                Vector3 position = (box.Min()[axis] + box.Max()[axis]) * 0.5f;
873                return Plane3(norm, position);*/
[295]874        }
875
[297]876        // simplest strategy: just take next polygon
877        if (sSplitPlaneStrategy & NEXT_POLYGON)
878        {
879                return polys.front()->GetSupportingPlane();
880        }
881
[260]882        // use heuristics to find appropriate plane
[263]883        return SelectPlaneHeuristics(polys, sMaxCandidates);
[195]884}
885
[305]886Plane3 BspTree::SelectPlaneHeuristics(PolygonContainer &polys, int maxTests)
[238]887{
[294]888        float lowestCost = MAX_FLOAT;
[265]889        int bestPlaneIdx = 0;
[238]890       
[304]891        int limit = maxTests > 0 ? Min((int)polys.size(), maxTests) : (int)polys.size();
892       
893        int candidateIdx = limit;
[306]894       
[265]895        for (int i = 0; i < limit; ++ i)
[238]896        {
[305]897                candidateIdx = GetNextCandidateIdx(candidateIdx, polys);
[304]898
[295]899                Plane3 candidatePlane = polys[candidateIdx]->GetSupportingPlane();
[239]900               
[238]901                // evaluate current candidate
[295]902                float candidateCost = EvalSplitPlane(polys, candidatePlane);
[238]903                       
[240]904                if (candidateCost < lowestCost)
[238]905                {
[265]906                        bestPlaneIdx = candidateIdx;
[240]907                        lowestCost = candidateCost;
[238]908                }
909        }
[305]910       
[301]911        //Debug << "Plane lowest cost: " << lowestCost << endl;
[295]912        return polys[bestPlaneIdx]->GetSupportingPlane();
[238]913}
914
[305]915int BspTree::GetNextCandidateIdx(int currentIdx, PolygonContainer &polys)
[238]916{
[305]917        int candidateIdx = Random(currentIdx--);
918       
[306]919        //Debug << "new candidate " << candidateIdx << endl;
920
[305]921        // swap candidates to avoid testing same plane 2 times
922        Polygon3 *p = polys[candidateIdx];
923        polys[candidateIdx] = polys[currentIdx];
924        polys[currentIdx] = p;
925       
926        return currentIdx;
[295]927}
[238]928
[305]929float BspTree::EvalSplitPlane(PolygonContainer &polys, const Plane3 &candidatePlane)
[295]930{
[301]931        float val = 0;
[295]932       
[296]933        if (sSplitPlaneStrategy & VERTICAL_AXIS)
[238]934        {
[297]935                Vector3 tinyAxis(0,0,0); tinyAxis[mBox.Size().TinyAxis()] = 1.0f;
[303]936                // we put a penalty on the dot product between the "tiny" vertical axis
[297]937                // and the split plane axis
[301]938                val += sVerticalSplitsFactor *
[306]939                           fabs(DotProd(candidatePlane.mNormal, tinyAxis));
[295]940        }
[306]941
[297]942        //-- strategies where the effect of the split plane on the polygons is tested
[306]943        if (!((sSplitPlaneStrategy & BALANCED_POLYS) ||
944                  (sSplitPlaneStrategy & LEAST_SPLITS)   ||
945                  (sSplitPlaneStrategy & LARGEST_POLY_AREA) ||
946                  (sSplitPlaneStrategy & BALANCED_VIEW_CELLS)))
947                return val;
948       
949        PolygonContainer::const_iterator it, it_end = polys.end();
950        float sumBalancedPolys = 0;
951        float sumSplits = 0;
952        float sumPolyArea = 0;
953        float sumBalancedViewCells = 0;
954        //float totalArea = 0;
955
956        // container for view cells
957        ObjectContainer frontViewCells;
958        ObjectContainer backViewCells;
959
960        for (it = polys.begin(); it != it_end; ++ it)
[295]961        {
[306]962                int classification = (*it)->ClassifyPlane(candidatePlane);
[301]963
[306]964                if (sSplitPlaneStrategy & BALANCED_POLYS)
965                        sumBalancedPolys += sBalancedPolysTable[classification];
966               
967                if (sSplitPlaneStrategy & LEAST_SPLITS)
968                        sumSplits += sLeastSplitsTable[classification];
969
970                if (sSplitPlaneStrategy & LARGEST_POLY_AREA)
[238]971                {
[306]972                        if (classification == Polygon3::COINCIDENT)
973                        {               
974                                float area = (*it)->GetArea();
975                                //Debug << "polygon area: " << area << " ";
976                                sumPolyArea += area;
[299]977                        }
[306]978                        //totalArea += area;
[301]979                }
[238]980
[307]981                // assign view cells to back or front according to classificaion
[306]982                if (sSplitPlaneStrategy & BALANCED_VIEW_CELLS)
[297]983                {
[308]984                        MeshInstance *viewCell = (*it)->mParent;
[306]985               
986                        if (classification == Polygon3::FRONT_SIDE)
[297]987                                frontViewCells.push_back(viewCell);
988                        else if (viewCell && (classification == Polygon3::BACK_SIDE))
989                                backViewCells.push_back(viewCell);
990                }
[306]991        }
[297]992
[306]993        if (sSplitPlaneStrategy & BALANCED_POLYS)
994                val += sBalancedPolysFactor * fabs(sumBalancedPolys) / (float)polys.size();
995
996        if (sSplitPlaneStrategy & LEAST_SPLITS)   
997                val += sLeastSplitsFactor * sumSplits / (float)polys.size();
998
[308]999        if (sSplitPlaneStrategy & LARGEST_POLY_AREA)
[306]1000                val += sLargestPolyAreaFactor * (float)polys.size() / sumPolyArea; // HACK
1001
1002        if (sSplitPlaneStrategy & BALANCED_VIEW_CELLS)
1003        {
[297]1004                // count number of unique view cells
1005                sort(frontViewCells.begin(), frontViewCells.end());
1006                sort(backViewCells.begin(), backViewCells.end());
1007
1008                ObjectContainer::const_iterator frontIt, frontIt_end = frontViewCells.end();
[306]1009       
[308]1010                Intersectable *vc = NULL;
[297]1011                // increase counter for view cells in front of plane
[306]1012                for (frontIt = frontViewCells.begin(); frontIt != frontIt_end; ++frontIt)
[297]1013                {
[308]1014                        if (*frontIt != vc)
[297]1015                        {
[308]1016                                vc = *frontIt;
[301]1017                                sumBalancedViewCells += 1.0f;
[297]1018                        }
1019                }
1020
1021                ObjectContainer::const_iterator backIt, backIt_end = backViewCells.end();
[308]1022                vc = NULL;
[297]1023                // decrease counter for view cells on back side of plane
[306]1024                for (backIt = backViewCells.begin(); backIt != backIt_end; ++backIt)
[297]1025                {
[308]1026                        if (*backIt != vc)
[297]1027                        {
[308]1028                                vc = *backIt;
[306]1029                                sumBalancedViewCells -= 1.0f;
[297]1030                        }
1031                }
[301]1032
[306]1033                val += sBalancedViewCellsFactor * fabs(sumBalancedViewCells) /
1034                        (float)(frontViewCells.size() + backViewCells.size());
[297]1035        }
1036
[295]1037        // return linear combination of the sums
[301]1038        return val;
[238]1039}
1040
[267]1041void BspTree::ParseEnvironment()
1042{
[310]1043        //-- parse bsp cell tree construction method
1044        char constructionMethodStr[60];
1045       
1046        environment->GetStringValue("BspTree.constructionMethod", constructionMethodStr);
1047
1048        sConstructionMethod = FROM_INPUT_VIEW_CELLS;
1049       
1050        if (strcmp(constructionMethodStr, "fromViewCells") == 0)
1051                sConstructionMethod = FROM_INPUT_VIEW_CELLS;
1052        else if (strcmp(constructionMethodStr, "fromSceneGeometry") == 0)
1053                sConstructionMethod = FROM_SCENE_GEOMETRY;
1054        else if (strcmp(constructionMethodStr, "fromRays") == 0)
1055                sConstructionMethod = FROM_RAYS;
1056        else
1057        {
1058                cerr << "Wrong construction method " << constructionMethodStr << endl;
1059                exit(1);
1060    }
1061
1062        Debug << "Construction method: " << constructionMethodStr << endl;
1063
[267]1064        environment->GetIntValue("BspTree.Termination.maxDepth", sTermMaxDepth);
1065        environment->GetIntValue("BspTree.Termination.maxPolygons", sTermMaxPolygons);
[297]1066        environment->GetIntValue("BspTree.Termination.maxPolysForAxisAligned",
1067                                                         sTermMaxPolysForAxisAligned);
[267]1068        environment->GetIntValue("BspTree.maxCandidates", sMaxCandidates);
[294]1069        environment->GetIntValue("BspTree.splitPlaneStrategy", sSplitPlaneStrategy);
[267]1070
[302]1071        // need kdtree criteria for axis aligned split
1072        environment->GetFloatValue("MeshKdTree.Termination.ct_div_ci", sCt_div_ci);
1073        environment->GetFloatValue("MeshKdTree.splitBorder", sSplitBorder);
1074        environment->GetFloatValue("MeshKdTree.Termination.maxCostRatio", sMaxCostRatio);
1075
[297]1076    Debug << "BSP max depth: " << sTermMaxDepth << endl;
[267]1077        Debug << "BSP max polys: " << sTermMaxPolygons << endl;
1078        Debug << "BSP max candidates: " << sMaxCandidates << endl;
[297]1079       
1080        Debug << "Split plane strategy: ";
1081        if (sSplitPlaneStrategy & NEXT_POLYGON)
1082                Debug << "next polygon ";
1083        if (sSplitPlaneStrategy & AXIS_ALIGNED)
1084                Debug << "axis aligned ";
1085        if (sSplitPlaneStrategy & LEAST_SPLITS)     
1086                Debug << "least splits ";
1087        if (sSplitPlaneStrategy & BALANCED_POLYS)
1088                Debug << "balanced polygons ";
1089        if (sSplitPlaneStrategy & BALANCED_VIEW_CELLS)
1090                Debug << "balanced view cells ";
1091        if (sSplitPlaneStrategy & LARGEST_POLY_AREA)
1092                Debug << "largest polygon area ";
1093        if (sSplitPlaneStrategy & VERTICAL_AXIS)
1094                Debug << "vertical axis ";
[267]1095
[297]1096        Debug << endl;
[267]1097}
1098
[240]1099void BspTree::CollectLeaves(vector<BspLeaf *> &leaves)
1100{
1101        stack<BspNode *> nodeStack;
1102        nodeStack.push(mRoot);
1103 
1104        while (!nodeStack.empty())
1105        {
1106                BspNode *node = nodeStack.top();
1107   
1108                nodeStack.pop();
1109   
1110                if (node->IsLeaf())
1111                {
1112                        BspLeaf *leaf = (BspLeaf *)node;
1113                       
1114                        leaves.push_back(leaf);
1115                } else
1116                {
1117                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1118                        nodeStack.push(interior->GetBack());
1119                        nodeStack.push(interior->GetFront());
1120                }
1121        }
[267]1122}
1123
1124AxisAlignedBox3 BspTree::GetBoundingBox() const
1125{
1126        return mBox;
1127}
1128
1129BspNode *BspTree::GetRoot() const
1130{
1131        return mRoot;
1132}
1133
1134bool BspTree::StorePolys() const
1135{
[304]1136        return mStoreSplitPolys;
[267]1137}
1138
[235]1139void BspTree::EvaluateLeafStats(const BspTraversalData &data)
1140{
[239]1141        // the node became a leaf -> evaluate stats for leafs
1142        BspLeaf *leaf = dynamic_cast<BspLeaf *>(data.mNode);
[235]1143
[295]1144        if (data.mDepth >= sTermMaxDepth)
[239]1145        {
1146                ++ mStat.maxDepthNodes;
1147        }
[238]1148
[265]1149        // store maximal and minimal depth
[239]1150        if (data.mDepth > mStat.maxDepth)
1151                mStat.maxDepth = data.mDepth;
[265]1152        if (data.mDepth < mStat.minDepth)
1153                mStat.minDepth = data.mDepth;
[235]1154
[267]1155        // accumulate depth to compute average
[265]1156        mStat.accumDepth += data.mDepth;
1157
1158        if (leaf->mViewCell)
1159                ++ mStat.viewCellLeaves;
1160
[239]1161#ifdef _DEBUG
[265]1162        Debug << "BSP Traversal data. Depth: " << data.mDepth << " (max: " << mTermMaxDepth << "), #polygons: " <<
[295]1163          data.mPolygons->size() << " (max: " << sTermMaxPolygons << ")" << endl;
[239]1164#endif
[235]1165}
[241]1166
1167int BspTree::CastRay(Ray &ray)
1168{
1169        int hits = 0;
1170 
1171        stack<BspRayTraversalData> tStack;
1172 
1173        float maxt = 1e6;
1174        float mint = 0;
[311]1175       
[241]1176        Intersectable::NewMail();
1177
1178        // test with tree bounding box
1179        if (!mBox.GetMinMaxT(ray, &mint, &maxt))
[311]1180        {
[241]1181                return 0;
[311]1182        }
[241]1183
1184        if (mint < 0)
1185                mint = 0;
1186 
1187        maxt += Limits::Threshold;
1188 
1189        Vector3 entp = ray.Extrap(mint);
1190        Vector3 extp = ray.Extrap(maxt);
1191 
1192        BspNode *node = mRoot;
1193        BspNode *farChild;
1194       
[260]1195        while (1)
[241]1196        {
1197                if (!node->IsLeaf())
1198                {
1199                        BspInterior *in = (BspInterior *) node;
1200                       
1201                        Plane3 *splitPlane = in->GetPlane();
1202
1203                        float t = 0;
1204                        bool coplanar = false;
1205               
1206                        int entSide = splitPlane->Side(entp);
1207                        int extSide = splitPlane->Side(extp);
1208
1209                        Vector3 intersection;
1210
1211                        if (entSide < 0)
1212                        {
[242]1213                                node = in->GetBack();
1214
1215                                if(extSide <= 0)
[241]1216                                        continue;
[242]1217                                       
1218                                farChild = in->GetFront(); // plane splits ray
1219
[241]1220                        } else if (entSide > 0)
1221                        {
[242]1222                                node = in->GetFront();
1223
1224                                if (extSide >= 0)
[241]1225                                        continue;
[242]1226
1227                                farChild = in->GetBack();        // plane splits ray                   
[241]1228                        }
[242]1229                        else // ray and plane are coincident // WHAT TO DO IN THIS CASE ?
[241]1230                        {
[242]1231                                node = in->GetFront();
[241]1232                                continue;
1233                        }
1234
[242]1235                        // push data for far child
[241]1236                        tStack.push(BspRayTraversalData(farChild, extp, maxt));
1237
[242]1238                        // find intersection with plane between ray origin and exit point
1239                        extp = splitPlane->FindIntersection(ray.GetLoc(), extp, &maxt);
[308]1240                } else // reached leaf => intersection with view cell
[241]1241                {
1242                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
[308]1243                       
1244                        //ray.mBspLeaves.push_back(leaf);
[311]1245                        //Debug << "adding view cell" << leaf->mViewCell;
[308]1246                        if (!leaf->mViewCell->Mailed())
[241]1247                        {
[308]1248                                ray.viewCells.push_back(leaf->mViewCell);
1249                                mViewCell->Mail();
1250                                ++ hits;
1251                        }
[311]1252                        //Debug << "view cell added" << endl;
[309]1253                        // get the next node from the stack
[241]1254                        if (tStack.empty())
1255                                break;
1256     
1257                        entp = extp;
1258                        mint = maxt;
1259                        BspRayTraversalData &s  = tStack.top();
[242]1260
[241]1261                        node = s.mNode;
1262                        extp = s.mExitPoint;
1263                        maxt = s.mMaxT;
1264
1265                        tStack.pop();
1266                }
[260]1267        }
[241]1268
[260]1269        return hits;
[241]1270}
1271
[262]1272bool BspTree::Export(const string filename)
1273{
1274        Exporter *exporter = Exporter::GetExporter(filename);
1275
1276        if (exporter)
1277        {
1278                exporter->ExportBspTree(*this);
1279                return true;
1280        }       
1281
1282        return false;
1283}
[308]1284
1285void BspTree::CollectViewCells(BspNode *n, ViewCellContainer &viewCells)
1286{
1287        stack<BspNode *> nodeStack;
1288
1289        nodeStack.push(n);
1290
1291        while (!nodeStack.empty())
1292        {
1293                BspNode *node = nodeStack.top();
1294                nodeStack.pop();
1295
1296                if (node->IsLeaf())
1297                {
1298                        ViewCell *viewCell = dynamic_cast<BspLeaf *>(node)->mViewCell;
1299
1300                        if (!viewCell->Mailed())
1301                        {
1302                                viewCell->Mail();
1303                                viewCells.push_back(viewCell);
1304                        }
1305                }
1306                else
1307                {
1308                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1309                        nodeStack.push(interior->mFront);
1310                        nodeStack.push(interior->mBack);
1311                }
1312        }
1313}
[245]1314//} // GtpVisibilityPreprocessor
Note: See TracBrowser for help on using the repository browser.