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

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