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

Revision 573, 69.0 KB checked in by mattausch, 18 years ago (diff)

implemented functtion for view cell construction

Line 
1#include "Plane3.h"
2#include "ViewCellBsp.h"
3#include "Mesh.h"
4#include "common.h"
5#include "ViewCell.h"
6#include "Environment.h"
7#include "Polygon3.h"
8#include "Ray.h"
9#include "AxisAlignedBox3.h"
10#include "Triangle3.h"
11#include "Tetrahedron3.h"
12
13#include <stack>
14
15#include "Exporter.h"
16#include "Plane3.h"
17
18//-- static members
19
20int BspNode::sMailId = 1;
21
22/** Evaluates split plane classification with respect to the plane's
23        contribution for a minimum number splits in the tree.
24*/
25const float BspTree::sLeastPolySplitsTable[] = {0, 0, 1, 0};
26/** Evaluates split plane classification with respect to the plane's
27        contribution for a balanced tree.
28*/
29const float BspTree::sBalancedPolysTable[] = {1, -1, 0, 0};
30
31/** Evaluates split plane classification with respect to the plane's
32        contribution for a minimum number of ray splits.
33*/
34const float BspTree::sLeastRaySplitsTable[] = {0, 0, 1, 1, 0};
35/** Evaluates split plane classification with respect to the plane's
36        contribution for balanced rays.
37*/
38const float BspTree::sBalancedRaysTable[] = {1, -1, 0, 0, 0};
39
40int BspTree::sFrontId = 0;
41int BspTree::sBackId = 0;
42int BspTree::sFrontAndBackId = 0;
43
44
45/****************************************************************/
46/*                  class BspNode implementation                */
47/****************************************************************/
48
49
50BspNode::BspNode():
51mParent(NULL), mTreeValid(true)
52{}
53
54BspNode::BspNode(BspInterior *parent):
55mParent(parent), mTreeValid(true)
56{}
57
58
59bool BspNode::IsRoot() const
60{
61        return mParent == NULL;
62}
63
64
65BspInterior *BspNode::GetParent()
66{
67        return mParent;
68}
69
70
71void BspNode::SetParent(BspInterior *parent)
72{
73        mParent = parent;
74}
75
76
77bool BspNode::IsSibling(BspNode *n) const
78{
79        return  ((this != n) && mParent &&
80                         (mParent->GetFront() == n) || (mParent->GetBack() == n));
81}
82
83
84int BspNode::GetDepth() const
85{
86        int depth = 0;
87        BspNode *p = mParent;
88       
89        while (p)
90        {
91                p = p->mParent;
92                ++ depth;
93        }
94
95        return depth;
96}
97
98
99bool BspNode::TreeValid() const
100{
101        return mTreeValid;
102}
103
104
105void BspNode::SetTreeValid(const bool v)
106{
107        mTreeValid = v;
108}
109
110
111/****************************************************************/
112/*              class BspInterior implementation                */
113/****************************************************************/
114
115
116BspInterior::BspInterior(const Plane3 &plane):
117mPlane(plane), mFront(NULL), mBack(NULL)
118{}
119
120BspInterior::~BspInterior()
121{
122        DEL_PTR(mFront);
123        DEL_PTR(mBack);
124}
125
126bool BspInterior::IsLeaf() const
127{
128        return false;
129}
130
131BspNode *BspInterior::GetBack()
132{
133        return mBack;
134}
135
136BspNode *BspInterior::GetFront()
137{
138        return mFront;
139}
140
141Plane3 BspInterior::GetPlane() const
142{
143        return mPlane;
144}
145
146void BspInterior::ReplaceChildLink(BspNode *oldChild, BspNode *newChild)
147{
148        if (mBack == oldChild)
149                mBack = newChild;
150        else
151                mFront = newChild;
152}
153
154void BspInterior::SetupChildLinks(BspNode *b, BspNode *f)
155{
156    mBack = b;
157    mFront = f;
158}
159
160/****************************************************************/
161/*                  class BspLeaf implementation                */
162/****************************************************************/
163
164
165BspLeaf::BspLeaf(): mViewCell(NULL), mPvs(NULL)
166{
167}
168
169
170BspLeaf::~BspLeaf()
171{
172        DEL_PTR(mPvs);
173}
174
175
176BspLeaf::BspLeaf(BspViewCell *viewCell):
177mViewCell(viewCell)
178{
179}
180
181
182BspLeaf::BspLeaf(BspInterior *parent):
183BspNode(parent), mViewCell(NULL), mPvs(NULL)
184{}
185
186
187
188BspLeaf::BspLeaf(BspInterior *parent, BspViewCell *viewCell):
189BspNode(parent), mViewCell(viewCell), mPvs(NULL)
190{
191}
192
193BspViewCell *BspLeaf::GetViewCell() const
194{
195        return mViewCell;
196}
197
198void BspLeaf::SetViewCell(BspViewCell *viewCell)
199{
200        mViewCell = viewCell;
201}
202
203
204bool BspLeaf::IsLeaf() const
205{
206        return true;
207}
208
209
210/******************************************************************/
211/*                    class BspTree implementation                */
212/******************************************************************/
213
214BspTree::BspTree(): 
215mRoot(NULL),
216mUseAreaForPvs(true),
217mGenerateViewCells(true)
218{
219        Randomize(); // initialise random generator for heuristics
220
221        // the view cell corresponding to unbounded space
222        mRootCell = new BspViewCell();
223
224        //-- termination criteria for autopartition
225        environment->GetIntValue("BspTree.Termination.maxDepth", mTermMaxDepth);
226        environment->GetIntValue("BspTree.Termination.minPvs", mTermMinPvs);
227        environment->GetIntValue("BspTree.Termination.minPolygons", mTermMinPolys);
228        environment->GetIntValue("BspTree.Termination.minRays", mTermMinRays);
229        environment->GetFloatValue("BspTree.Termination.minArea", mTermMinArea);       
230        environment->GetFloatValue("BspTree.Termination.maxRayContribution", mTermMaxRayContribution);
231        environment->GetFloatValue("BspTree.Termination.minAccRayLenght", mTermMinAccRayLength);
232
233        //-- factors for bsp tree split plane heuristics
234        environment->GetFloatValue("BspTree.Factor.verticalSplits", mVerticalSplitsFactor);
235        environment->GetFloatValue("BspTree.Factor.largestPolyArea", mLargestPolyAreaFactor);
236        environment->GetFloatValue("BspTree.Factor.blockedRays", mBlockedRaysFactor);
237        environment->GetFloatValue("BspTree.Factor.leastRaySplits", mLeastRaySplitsFactor);
238        environment->GetFloatValue("BspTree.Factor.balancedRays", mBalancedRaysFactor);
239        environment->GetFloatValue("BspTree.Factor.pvs", mPvsFactor);
240        environment->GetFloatValue("BspTree.Factor.leastSplits" , mLeastSplitsFactor);
241        environment->GetFloatValue("BspTree.Factor.balancedPolys", mBalancedPolysFactor);
242        environment->GetFloatValue("BspTree.Factor.balancedViewCells", mBalancedViewCellsFactor);
243        environment->GetFloatValue("BspTree.Termination.ct_div_ci", mCtDivCi);
244
245        //-- termination criteria for axis aligned split
246        environment->GetFloatValue("BspTree.Termination.AxisAligned.ct_div_ci", mAxisAlignedCtDivCi);
247        environment->GetFloatValue("BspTree.Termination.maxCostRatio", mMaxCostRatio);
248        environment->GetIntValue("BspTree.Termination.AxisAligned.minPolys",
249                                                         mTermMinPolysForAxisAligned);
250        environment->GetIntValue("BspTree.Termination.AxisAligned.minRays",
251                                                         mTermMinRaysForAxisAligned);
252        environment->GetIntValue("BspTree.Termination.AxisAligned.minObjects",
253                                                         mTermMinObjectsForAxisAligned);
254        //-- partition criteria
255        environment->GetIntValue("BspTree.maxPolyCandidates", mMaxPolyCandidates);
256        environment->GetIntValue("BspTree.maxRayCandidates", mMaxRayCandidates);
257        environment->GetIntValue("BspTree.splitPlaneStrategy", mSplitPlaneStrategy);
258        environment->GetFloatValue("BspTree.AxisAligned.splitBorder", mSplitBorder);
259        environment->GetIntValue("BspTree.maxTests", mMaxTests);
260
261        environment->GetFloatValue("BspTree.Construction.epsilon", mEpsilon);
262       
263    Debug << "BSP max depth: " << mTermMaxDepth << endl;
264        Debug << "BSP min PVS: " << mTermMinPvs << endl;
265        Debug << "BSP min area: " << mTermMinArea << endl;
266        Debug << "BSP max polys: " << mTermMinPolys << endl;
267        Debug << "BSP max rays: " << mTermMinRays << endl;
268        Debug << "BSP max polygon candidates: " << mMaxPolyCandidates << endl;
269        Debug << "BSP max plane candidates: " << mMaxRayCandidates << endl;
270
271        Debug << "Split plane strategy: ";
272        if (mSplitPlaneStrategy & RANDOM_POLYGON)
273                Debug << "random polygon ";
274        if (mSplitPlaneStrategy & AXIS_ALIGNED)
275                Debug << "axis aligned ";
276        if (mSplitPlaneStrategy & LEAST_SPLITS)     
277                Debug << "least splits ";
278        if (mSplitPlaneStrategy & BALANCED_POLYS)
279                Debug << "balanced polygons ";
280        if (mSplitPlaneStrategy & BALANCED_VIEW_CELLS)
281                Debug << "balanced view cells ";
282        if (mSplitPlaneStrategy & LARGEST_POLY_AREA)
283                Debug << "largest polygon area ";
284        if (mSplitPlaneStrategy & VERTICAL_AXIS)
285                Debug << "vertical axis ";
286        if (mSplitPlaneStrategy & BLOCKED_RAYS)
287                Debug << "blocked rays ";
288        if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)
289                Debug << "least ray splits ";
290        if (mSplitPlaneStrategy & BALANCED_RAYS)
291                Debug << "balanced rays ";
292        if (mSplitPlaneStrategy & PVS)
293                Debug << "pvs";
294
295        Debug << endl;
296}
297
298
299const BspTreeStatistics &BspTree::GetStatistics() const
300{
301        return mStat;
302}
303
304
305int BspTree::SplitPolygons(const Plane3 &plane,
306                                                   PolygonContainer &polys,
307                                                   PolygonContainer &frontPolys,
308                                                   PolygonContainer &backPolys,
309                                                   PolygonContainer &coincident) const
310{
311        int splits = 0;
312
313#ifdef _Debug
314        Debug << "splitting polygons of node " << this << " with plane " << mPlane << endl;
315#endif
316        while (!polys.empty())
317        {
318                Polygon3 *poly = polys.back();
319                polys.pop_back();
320
321                //-- classify polygon
322                const int cf = poly->ClassifyPlane(plane, mEpsilon);
323
324                switch (cf)
325                {
326                        case Polygon3::COINCIDENT:
327                                coincident.push_back(poly);
328                                break;                 
329                        case Polygon3::FRONT_SIDE:     
330                                frontPolys.push_back(poly);
331                                break;
332                        case Polygon3::BACK_SIDE:
333                                backPolys.push_back(poly);
334                                break;
335                        case Polygon3::SPLIT:
336                                {
337                                        Polygon3 *front_piece = new Polygon3(poly->mParent);
338                                        Polygon3 *back_piece = new Polygon3(poly->mParent);
339
340                                        //-- split polygon into front and back part
341                                        poly->Split(plane,
342                                                                *front_piece,
343                                                                *back_piece,
344                                                                mEpsilon);
345                                       
346                                        ++ splits; // increase number of splits
347
348                                        //-- inherit rays from parent polygon for blocked ray criterium
349                                        poly->InheritRays(*front_piece, *back_piece);
350                               
351                                        // check if polygons still valid
352                                        if (front_piece->Valid(mEpsilon))
353                                                frontPolys.push_back(front_piece);
354                                        else
355                                                DEL_PTR(front_piece);
356                               
357                                        if (back_piece->Valid(mEpsilon))
358                                                backPolys.push_back(back_piece);
359                                        else                           
360                                                DEL_PTR(back_piece);
361                               
362#ifdef _DEBUG
363                                        Debug << "split " << *poly << endl << *front_piece << endl << *back_piece << endl;
364#endif
365                                        DEL_PTR(poly);
366                                }
367                                break;
368                        default:
369                Debug << "SHOULD NEVER COME HERE\n";
370                                break;
371                }
372        }
373
374        return splits;
375}
376
377
378void BspTreeStatistics::Print(ostream &app) const
379{
380        app << "===== BspTree statistics ===============\n";
381
382        app << setprecision(4);
383
384        app << "#N_CTIME  ( Construction time [s] )\n" << Time() << " \n";
385
386        app << "#N_NODES ( Number of nodes )\n" << nodes << "\n";
387
388        app << "#N_INTERIORS ( Number of interior nodes )\n" << Interior() << "\n";
389
390        app << "#N_LEAVES ( Number of leaves )\n" << Leaves() << "\n";
391
392        app << "#N_POLYSPLITS ( Number of polygon splits )\n" << polySplits << "\n";
393
394        app << "#AXIS_ALIGNED_SPLITS (number of axis aligned splits)\n" << splits[0] + splits[1] + splits[2] << endl;
395
396        app << "#N_SPLITS ( Number of splits in axes x y z\n";
397
398        for (int i = 0; i < 3; ++ i)
399                app << splits[i] << " ";
400        app << endl;
401
402        app << "#N_PMAXDEPTHLEAVES ( Percentage of leaves at maximum depth )\n"
403                <<      maxDepthNodes * 100 / (double)Leaves() << endl;
404
405        app << "#N_PMINPVSLEAVES  ( Percentage of leaves with mininimal PVS )\n"
406                << minPvsNodes * 100 / (double)Leaves() << endl;
407
408        app << "#N_PMINRAYSLEAVES  ( Percentage of leaves with minimal number of rays)\n"
409                << minRaysNodes * 100 / (double)Leaves() << endl;
410
411        app << "#N_MAXCOSTNODES  ( Percentage of leaves with terminated because of max cost ratio )\n"
412                << maxCostNodes * 100 / (double)Leaves() << endl;
413
414        app << "#N_PMINAREALEAVES  ( Percentage of leaves with mininum probability )\n"
415                << minProbabilityNodes * 100 / (double)Leaves() << endl;
416
417        app << "#N_PMAXRAYCONTRIBLEAVES  ( Percentage of leaves with maximal ray contribution )\n"
418                <<      maxRayContribNodes * 100 / (double)Leaves() << endl;
419
420        app << "#N_PMAXDEPTH ( Maximal reached depth )\n" << maxDepth << endl;
421
422        app << "#N_PMINDEPTH ( Minimal reached depth )\n" << minDepth << endl;
423
424        app << "#AVGDEPTH ( average depth )\n" << AvgDepth() << endl;
425
426        app << "#N_INPUTPOLYGONS (number of input polygons )\n" << polys << endl;
427
428        app << "#N_INVALIDLEAVES (number of invalid leaves )\n" << invalidLeaves << endl;
429
430        app << "#N_RAYS (number of rays / leaf)\n" << AvgRays() << endl;
431        //app << "#N_PVS: " << pvs << endl;
432
433        app << "#N_ROUTPUT_INPUT_POLYGONS ( ratio polygons after subdivision / input polygons )\n" <<
434                 (polys + polySplits) / (double)polys << endl;
435       
436        app << "===== END OF BspTree statistics ==========\n";
437}
438
439
440BspTree::~BspTree()
441{
442        DEL_PTR(mRoot);
443
444        // HACK: view cells not generated => root cell not used
445        if (mGenerateViewCells)
446                DEL_PTR(mRootCell);
447}
448
449BspViewCell *BspTree::GetRootCell() const
450{
451        return mRootCell;
452}
453
454void BspTree::InsertViewCell(ViewCell *viewCell)
455{
456        PolygonContainer *polys = new PolygonContainer();
457
458        // don't generate new view cell, insert this one
459        mGenerateViewCells = false;
460        // extract polygons that guide the split process
461        mStat.polys += AddMeshToPolygons(viewCell->GetMesh(), *polys, viewCell);
462        mBox.Include(viewCell->GetBox()); // add to BSP aabb
463
464        InsertPolygons(polys);
465}
466
467void BspTree::InsertPolygons(PolygonContainer *polys)
468{       
469        BspTraversalStack tStack;
470
471        // traverse existing tree or create new tree
472    if (!mRoot)
473                mRoot = new BspLeaf();
474
475        tStack.push(BspTraversalData(mRoot,
476                                                                 polys,
477                                                                 0,
478                                                                 mRootCell,
479                                                                 new BoundedRayContainer(),
480                                                                 0,
481                                                                 mBox.SurfaceArea(),
482                                                                 new BspNodeGeometry()));
483
484        while (!tStack.empty())
485        {
486                // filter polygons donw the tree
487                BspTraversalData tData = tStack.top();
488            tStack.pop();
489                       
490                if (!tData.mNode->IsLeaf())
491                {
492                        BspInterior *interior = dynamic_cast<BspInterior *>(tData.mNode);
493
494                        //-- filter view cell polygons down the tree until a leaf is reached
495                        if (!tData.mPolygons->empty())
496                        {
497                                PolygonContainer *frontPolys = new PolygonContainer();
498                                PolygonContainer *backPolys = new PolygonContainer();
499                                PolygonContainer coincident;
500
501                                int splits = 0;
502               
503                                // split viewcell polygons with respect to split plane
504                                splits += SplitPolygons(interior->GetPlane(),
505                                                                                *tData.mPolygons,
506                                                                                *frontPolys,
507                                                                                *backPolys,
508                                                                                coincident);
509                               
510                                // extract view cells associated with the split polygons
511                                ViewCell *frontViewCell = mRootCell;
512                                ViewCell *backViewCell = mRootCell;
513                       
514                                BspTraversalData frontData(interior->GetFront(),
515                                                                                   frontPolys,
516                                                                                   tData.mDepth + 1,
517                                                                                   mRootCell,   
518                                                                                   tData.mRays,
519                                                                                   tData.mPvs,
520                                                                                   mBox.SurfaceArea(),
521                                                                                   new BspNodeGeometry());
522
523                                BspTraversalData backData(interior->GetBack(),
524                                                                                  backPolys,
525                                                                                  tData.mDepth + 1,
526                                                                                  mRootCell,   
527                                                                                  tData.mRays,
528                                                                                  tData.mPvs,
529                                                                                  mBox.SurfaceArea(),
530                                                                                  new BspNodeGeometry());
531
532                                if (!mGenerateViewCells)
533                                {
534                                        ExtractViewCells(frontData,
535                                                                         backData,
536                                                                         coincident,
537                                                                         interior->mPlane);
538                                }
539
540                                // don't need coincident polygons anymore
541                                CLEAR_CONTAINER(coincident);
542
543                                mStat.polySplits += splits;
544
545                                // push the children on the stack
546                                tStack.push(frontData);
547                                tStack.push(backData);
548                        }
549
550                        // cleanup
551                        DEL_PTR(tData.mPolygons);
552                        DEL_PTR(tData.mRays);
553                }
554                else
555                {
556                        // reached leaf => subdivide current viewcell
557                        BspNode *subRoot = Subdivide(tStack, tData);
558                }
559        }
560}
561
562int BspTree::AddMeshToPolygons(Mesh *mesh,
563                                                           PolygonContainer &polys,
564                                                           MeshInstance *parent)
565{
566        FaceContainer::const_iterator fi;
567       
568        // copy the face data to polygons
569        for (fi = mesh->mFaces.begin(); fi != mesh->mFaces.end(); ++ fi)
570        {
571                Polygon3 *poly = new Polygon3((*fi), mesh);
572               
573                if (poly->Valid(mEpsilon))
574                {
575                        poly->mParent = parent; // set parent intersectable
576                        polys.push_back(poly);
577                }
578                else
579                        DEL_PTR(poly);
580        }
581        return (int)mesh->mFaces.size();
582}
583
584int BspTree::AddToPolygonSoup(const ViewCellContainer &viewCells,
585                                                          PolygonContainer &polys,
586                                                          int maxObjects)
587{
588        int limit = (maxObjects > 0) ?
589                Min((int)viewCells.size(), maxObjects) : (int)viewCells.size();
590 
591        int polysSize = 0;
592
593        for (int i = 0; i < limit; ++ i)
594        {
595                if (viewCells[i]->GetMesh()) // copy the mesh data to polygons
596                {
597                        mBox.Include(viewCells[i]->GetBox()); // add to BSP tree aabb
598                        polysSize += AddMeshToPolygons(viewCells[i]->GetMesh(), polys, viewCells[i]);
599                }
600        }
601
602        return polysSize;
603}
604
605int BspTree::AddToPolygonSoup(const ObjectContainer &objects, PolygonContainer &polys, int maxObjects)
606{
607        int limit = (maxObjects > 0) ? Min((int)objects.size(), maxObjects) : (int)objects.size();
608 
609        for (int i = 0; i < limit; ++i)
610        {
611                Intersectable *object = objects[i];//*it;
612                Mesh *mesh = NULL;
613
614                switch (object->Type()) // extract the meshes
615                {
616                case Intersectable::MESH_INSTANCE:
617                        mesh = dynamic_cast<MeshInstance *>(object)->GetMesh();
618                        break;
619                case Intersectable::VIEW_CELL:
620                        mesh = dynamic_cast<ViewCell *>(object)->GetMesh();
621                        break;
622                        // TODO: handle transformed mesh instances
623                default:
624                        Debug << "intersectable type not supported" << endl;
625                        break;
626                }
627               
628        if (mesh) // copy the mesh data to polygons
629                {
630                        mBox.Include(object->GetBox()); // add to BSP tree aabb
631                        AddMeshToPolygons(mesh, polys, mRootCell);
632                }
633        }
634
635        return (int)polys.size();
636}
637
638void BspTree::Construct(const ViewCellContainer &viewCells)
639{
640        mStat.nodes = 1;
641        mBox.Initialize();      // initialise bsp tree bounding box
642
643        // copy view cell meshes into one big polygon soup
644        PolygonContainer *polys = new PolygonContainer();
645        mStat.polys = AddToPolygonSoup(viewCells, *polys);
646
647        // view cells are given
648        mGenerateViewCells = false;
649        // construct tree from the view cell polygons
650        Construct(polys, new BoundedRayContainer());
651}
652
653
654void BspTree::Construct(const ObjectContainer &objects)
655{
656        mStat.nodes = 1;
657        mBox.Initialize();      // initialise bsp tree bounding box
658       
659        PolygonContainer *polys = new PolygonContainer();
660
661        mGenerateViewCells = true;
662        // copy mesh instance polygons into one big polygon soup
663        mStat.polys = AddToPolygonSoup(objects, *polys);
664
665        // construct tree from polygon soup
666        Construct(polys, new BoundedRayContainer());
667}
668
669void BspTree::Construct(const RayContainer &sampleRays)
670{
671    mStat.nodes = 1;
672        mBox.Initialize();      // initialise BSP tree bounding box
673       
674        PolygonContainer *polys = new PolygonContainer();
675        BoundedRayContainer *rays = new BoundedRayContainer();
676
677        RayContainer::const_iterator rit, rit_end = sampleRays.end();
678
679        // generate view cells
680        mGenerateViewCells = true;
681
682        long startTime = GetTime();
683
684        Debug << "**** Extracting polygons from rays ****\n";
685
686        std::map<Face *, Polygon3 *> facePolyMap;
687
688        //-- extract polygons intersected by the rays
689        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
690        {
691                Ray *ray = *rit;
692       
693                // get ray-face intersection. Store polygon representing the rays together
694                // with rays intersecting the face.
695                if (!ray->intersections.empty())
696                {
697                        MeshInstance *obj = dynamic_cast<MeshInstance *>(ray->intersections[0].mObject);
698                        Face *face = obj->GetMesh()->mFaces[ray->intersections[0].mFace];
699
700                        std::map<Face *, Polygon3 *>::iterator it = facePolyMap.find(face);
701
702                        if (it != facePolyMap.end())
703                        {
704                                //store rays if needed for heuristics
705                                if (mSplitPlaneStrategy & BLOCKED_RAYS)
706                                        (*it).second->mPiercingRays.push_back(ray);
707                        }
708                        else
709                        {       //store rays if needed for heuristics
710                                Polygon3 *poly = new Polygon3(face, obj->GetMesh());
711                                poly->mParent = obj;
712                                polys->push_back(poly);
713
714                                if (mSplitPlaneStrategy & BLOCKED_RAYS)
715                                        poly->mPiercingRays.push_back(ray);
716
717                                facePolyMap[face] = poly;
718                        }
719                }
720        }
721       
722        facePolyMap.clear();
723
724        // compute bounding box
725        Polygon3::IncludeInBox(*polys, mBox);
726
727        //-- store rays
728        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
729        {
730                Ray *ray = *rit;
731        ray->SetId(-1); // reset id
732
733                float minT, maxT;
734                if (mBox.GetRaySegment(*ray, minT, maxT))
735                        rays->push_back(new BoundedRay(ray, minT, maxT));
736        }
737
738        mStat.polys = (int)polys->size();
739
740        Debug << "**** Finished polygon extraction ****" << endl;
741        Debug << (int)polys->size() << " polys extracted from " << (int)sampleRays.size() << " rays" << endl;
742        Debug << "extraction time: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
743
744        Construct(polys, rays);
745}
746
747void BspTree::Construct(const ObjectContainer &objects, const RayContainer &sampleRays)
748{
749    mStat.nodes = 1;
750        mBox.Initialize();      // initialise BSP tree bounding box
751       
752        BoundedRayContainer *rays = new BoundedRayContainer();
753        PolygonContainer *polys = new PolygonContainer();
754       
755        mGenerateViewCells = true;
756
757        // copy mesh instance polygons into one big polygon soup
758        mStat.polys = AddToPolygonSoup(objects, *polys);
759
760        RayContainer::const_iterator rit, rit_end = sampleRays.end();
761
762        //-- store rays
763        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
764        {
765                Ray *ray = *rit;
766        ray->SetId(-1); // reset id
767
768                float minT, maxT;
769                if (mBox.GetRaySegment(*ray, minT, maxT))
770                        rays->push_back(new BoundedRay(ray, minT, maxT));
771        }
772
773        Debug << "tree has " << (int)polys->size() << " polys, " << (int)sampleRays.size() << " rays" << endl;
774        Construct(polys, rays);
775}
776
777void BspTree::Construct(PolygonContainer *polys, BoundedRayContainer *rays)
778{
779        BspTraversalStack tStack;
780
781        mRoot = new BspLeaf();
782
783        // constrruct root node geometry
784        BspNodeGeometry *geom = new BspNodeGeometry();
785        ConstructGeometry(mRoot, *geom);
786
787        BspTraversalData tData(mRoot, polys, 0, mRootCell, rays,
788                                                   ComputePvsSize(*rays), geom->GetArea(), geom);
789
790        tStack.push(tData);
791
792        mStat.Start();
793        cout << "Contructing bsp tree ... ";
794        long startTime = GetTime();
795        while (!tStack.empty())
796        {
797                tData = tStack.top();
798
799            tStack.pop();
800
801                // subdivide leaf node
802                BspNode *r = Subdivide(tStack, tData);
803
804                if (r == mRoot)
805                        Debug << "BSP tree construction time spent at root: " << TimeDiff(startTime, GetTime())*1e-3 << " secs" << endl;
806        }
807
808        cout << "finished\n";
809
810        mStat.Stop();
811}
812
813bool BspTree::TerminationCriteriaMet(const BspTraversalData &data) const
814{
815        return
816                (((int)data.mPolygons->size() <= mTermMinPolys) ||
817                 ((int)data.mRays->size() <= mTermMinRays) ||
818                 (data.mPvs <= mTermMinPvs) ||
819                 (data.mArea <= mTermMinArea) ||
820                 (data.mDepth >= mTermMaxDepth) ||
821                 (data.GetAvgRayContribution() < mTermMaxRayContribution));
822}
823
824BspNode *BspTree::Subdivide(BspTraversalStack &tStack, BspTraversalData &tData)
825{
826        //-- terminate traversal 
827        if (TerminationCriteriaMet(tData))             
828        {
829                BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
830       
831                BspViewCell *viewCell;
832
833                // generate new view cell for each leaf
834                if (mGenerateViewCells)
835                        viewCell = new BspViewCell();
836                else
837                        // add view cell to leaf
838                        viewCell = dynamic_cast<BspViewCell *>(tData.mViewCell);
839               
840                leaf->SetViewCell(viewCell);
841                viewCell->mLeaves.push_back(leaf);
842
843                //-- add pvs
844                if (viewCell != mRootCell)
845                {
846                        int conSamp = 0, sampCon = 0;
847                        AddToPvs(leaf, *tData.mRays, conSamp, sampCon);
848                       
849                        mStat.contributingSamples += conSamp;
850                        mStat.sampleContributions += sampCon;
851                }
852
853                EvaluateLeafStats(tData);
854               
855                //-- clean up
856               
857                // discard polygons
858                CLEAR_CONTAINER(*tData.mPolygons);
859                // discard rays
860                CLEAR_CONTAINER(*tData.mRays);
861
862                DEL_PTR(tData.mPolygons);
863                DEL_PTR(tData.mRays);
864                DEL_PTR(tData.mGeometry);
865
866                return leaf;
867        }
868
869        //-- continue subdivision
870        PolygonContainer coincident;
871       
872        BspTraversalData tFrontData(NULL, new PolygonContainer(), tData.mDepth + 1, mRootCell,
873                                                                new BoundedRayContainer(), 0, 0, new BspNodeGeometry());
874        BspTraversalData tBackData(NULL, new PolygonContainer(), tData.mDepth + 1, mRootCell,
875                                                           new BoundedRayContainer(), 0, 0, new BspNodeGeometry());
876
877        // create new interior node and two leaf nodes
878        BspInterior *interior =
879                SubdivideNode(tData, tFrontData, tBackData, coincident);
880
881#ifdef _DEBUG   
882//      if (frontPolys->empty() && backPolys->empty() && (coincident.size() > 2))
883//      {       for (PolygonContainer::iterator it = coincident.begin(); it != coincident.end(); ++it)
884//                      Debug << (*it) << " " << (*it)->GetArea() << " " << (*it)->mParent << endl ;
885//              Debug << endl;}
886#endif
887
888        // extract view cells from coincident polygons according to plane normal
889    // only if front or back polygons are empty
890        if (!mGenerateViewCells)
891        {
892                ExtractViewCells(tFrontData,
893                                                 tBackData,
894                                                 coincident,
895                                                 interior->mPlane);                     
896        }
897
898        // don't need coincident polygons anymory
899        CLEAR_CONTAINER(coincident);
900
901        // push the children on the stack
902        tStack.push(tFrontData);
903        tStack.push(tBackData);
904
905        // cleanup
906        DEL_PTR(tData.mNode);
907
908        DEL_PTR(tData.mPolygons);
909        DEL_PTR(tData.mRays);
910        DEL_PTR(tData.mGeometry);               
911       
912        return interior;
913}
914
915void BspTree::ExtractViewCells(BspTraversalData &frontData,
916                                                           BspTraversalData &backData,
917                                                           const PolygonContainer &coincident,
918                                                           const Plane3 &splitPlane) const
919{
920        // if not empty, tree is further subdivided => don't have to find view cell
921        bool foundFront = !frontData.mPolygons->empty();
922        bool foundBack = !frontData.mPolygons->empty();
923
924        PolygonContainer::const_iterator it =
925                coincident.begin(), it_end = coincident.end();
926
927        //-- find first view cells in front and back leafs
928        for (; !(foundFront && foundBack) && (it != it_end); ++ it)
929        {
930                if (DotProd((*it)->GetNormal(), splitPlane.mNormal) > 0)
931                {
932                        backData.mViewCell = dynamic_cast<ViewCell *>((*it)->mParent);
933                        foundBack = true;
934                }
935                else
936                {
937                        frontData.mViewCell = dynamic_cast<ViewCell *>((*it)->mParent);
938                        foundFront = true;
939                }
940        }
941}
942
943BspInterior *BspTree::SubdivideNode(BspTraversalData &tData,
944                                                                        BspTraversalData &frontData,
945                                                                        BspTraversalData &backData,
946                                                                        PolygonContainer &coincident)
947{
948        mStat.nodes += 2;
949       
950        BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
951
952        Debug << "*********************" << endl;
953        long startTime = GetTime();
954       
955        // select subdivision plane
956        BspInterior *interior =
957                new BspInterior(SelectPlane(leaf, tData));
958        Debug << "time used for split plane selection: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
959#ifdef _DEBUG
960        Debug << interior << endl;
961#endif
962       
963
964        Debug << "number of rays: " << (int)tData.mRays->size() << endl;
965        Debug << "number of polys: " << (int)tData.mPolygons->size() << endl;
966
967        startTime = GetTime();
968       
969        // subdivide rays into front and back rays
970        SplitRays(interior->mPlane, *tData.mRays, *frontData.mRays, *backData.mRays);
971       
972        Debug << "time used for rays splitting: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
973
974        startTime = GetTime();
975        // subdivide polygons with plane
976        mStat.polySplits += SplitPolygons(interior->GetPlane(),
977                                                                          *tData.mPolygons,
978                                                                          *frontData.mPolygons,
979                                                                          *backData.mPolygons,
980                                                                          coincident);
981
982        Debug << "time used for polygon splitting: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
983
984    // compute pvs
985        frontData.mPvs = ComputePvsSize(*frontData.mRays);
986        backData.mPvs = ComputePvsSize(*backData.mRays);
987
988        // split geometry and compute area
989        if (1)
990        {
991                tData.mGeometry->SplitGeometry(*frontData.mGeometry,
992                                                                           *backData.mGeometry,
993                                                                           interior->mPlane,
994                                                                           mBox,
995                                                                           mEpsilon);
996       
997               
998                frontData.mArea = frontData.mGeometry->GetArea();
999                backData.mArea = backData.mGeometry->GetArea();
1000        }
1001
1002        // compute accumulated ray length
1003        //frontData.mAccRayLength = AccumulatedRayLength(*frontData.mRays);
1004        //backData.mAccRayLength = AccumulatedRayLength(*backData.mRays);
1005
1006        //-- create front and back leaf
1007
1008        BspInterior *parent = leaf->GetParent();
1009
1010        // replace a link from node's parent
1011        if (!leaf->IsRoot())
1012        {
1013                parent->ReplaceChildLink(leaf, interior);
1014                interior->SetParent(parent);
1015        }
1016        else // new root
1017        {
1018                mRoot = interior;
1019        }
1020
1021        // and setup child links
1022        interior->SetupChildLinks(new BspLeaf(interior), new BspLeaf(interior));
1023       
1024        frontData.mNode = interior->GetFront();
1025        backData.mNode = interior->GetBack();
1026       
1027        //DEL_PTR(leaf);
1028        return interior;
1029}
1030
1031void BspTree::SortSplitCandidates(const PolygonContainer &polys,
1032                                                                  const int axis,
1033                                                                  vector<SortableEntry> &splitCandidates) const
1034{
1035        splitCandidates.clear();
1036
1037        int requestedSize = 2 * (int)polys.size();
1038        // creates a sorted split candidates array 
1039        splitCandidates.reserve(requestedSize);
1040
1041        PolygonContainer::const_iterator it, it_end = polys.end();
1042
1043        AxisAlignedBox3 box;
1044
1045        // insert all queries
1046        for(it = polys.begin(); it != it_end; ++ it)
1047        {
1048                box.Initialize();
1049                box.Include(*(*it));
1050               
1051                splitCandidates.push_back(SortableEntry(SortableEntry::POLY_MIN, box.Min(axis), *it));
1052                splitCandidates.push_back(SortableEntry(SortableEntry::POLY_MAX, box.Max(axis), *it));
1053        }
1054
1055        stable_sort(splitCandidates.begin(), splitCandidates.end());
1056}
1057
1058
1059float BspTree::BestCostRatio(const PolygonContainer &polys,
1060                                                         const AxisAlignedBox3 &box,
1061                                                         const int axis,
1062                                                         float &position,
1063                                                         int &objectsBack,
1064                                                         int &objectsFront) const
1065{
1066        vector<SortableEntry> splitCandidates;
1067
1068        SortSplitCandidates(polys, axis, splitCandidates);
1069       
1070        // go through the lists, count the number of objects left and right
1071        // and evaluate the following cost funcion:
1072        // C = ct_div_ci  + (ol + or)/queries
1073       
1074        int objectsLeft = 0, objectsRight = (int)polys.size();
1075       
1076        float minBox = box.Min(axis);
1077        float maxBox = box.Max(axis);
1078        float boxArea = box.SurfaceArea();
1079 
1080        float minBand = minBox + mSplitBorder * (maxBox - minBox);
1081        float maxBand = minBox + (1.0f - mSplitBorder) * (maxBox - minBox);
1082       
1083        float minSum = 1e20f;
1084        vector<SortableEntry>::const_iterator ci, ci_end = splitCandidates.end();
1085
1086        for(ci = splitCandidates.begin(); ci != ci_end; ++ ci)
1087        {
1088                switch ((*ci).type)
1089                {
1090                        case SortableEntry::POLY_MIN:
1091                                ++ objectsLeft;
1092                                break;
1093                        case SortableEntry::POLY_MAX:
1094                            -- objectsRight;
1095                                break;
1096                        default:
1097                                break;
1098                }
1099               
1100                if ((*ci).value > minBand && (*ci).value < maxBand)
1101                {
1102                        AxisAlignedBox3 lbox = box;
1103                        AxisAlignedBox3 rbox = box;
1104                        lbox.SetMax(axis, (*ci).value);
1105                        rbox.SetMin(axis, (*ci).value);
1106
1107                        const float sum = objectsLeft * lbox.SurfaceArea() +
1108                                                          objectsRight * rbox.SurfaceArea();
1109     
1110                        if (sum < minSum)
1111                        {
1112                                minSum = sum;
1113                                position = (*ci).value;
1114
1115                                objectsBack = objectsLeft;
1116                                objectsFront = objectsRight;
1117                        }
1118                }
1119        }
1120 
1121        const float oldCost = (float)polys.size();
1122        const float newCost = mAxisAlignedCtDivCi + minSum / boxArea;
1123        const float ratio = newCost / oldCost;
1124
1125
1126#if 0
1127  Debug << "====================" << endl;
1128  Debug << "costRatio=" << ratio << " pos=" << position<<" t=" << (position - minBox)/(maxBox - minBox)
1129      << "\t o=(" << objectsBack << "," << objectsFront << ")" << endl;
1130#endif
1131  return ratio;
1132}
1133
1134bool BspTree::SelectAxisAlignedPlane(Plane3 &plane,
1135                                                                         const PolygonContainer &polys) const
1136{
1137        AxisAlignedBox3 box;
1138        box.Initialize();
1139       
1140        // create bounding box of region
1141        Polygon3::IncludeInBox(polys, box);
1142       
1143        int objectsBack = 0, objectsFront = 0;
1144        int axis = 0;
1145        float costRatio = MAX_FLOAT;
1146        Vector3 position;
1147
1148        //-- area subdivision
1149        for (int i = 0; i < 3; ++ i)
1150        {
1151                float p = 0;
1152                float r = BestCostRatio(polys, box, i, p, objectsBack, objectsFront);
1153               
1154                if (r < costRatio)
1155                {
1156                        costRatio = r;
1157                        axis = i;
1158                        position = p;
1159                }
1160        }
1161       
1162        if (costRatio >= mMaxCostRatio)
1163                return false;
1164
1165        Vector3 norm(0,0,0); norm[axis] = 1.0f;
1166        plane = Plane3(norm, position);
1167
1168        return true;
1169}
1170
1171
1172Plane3 BspTree::SelectPlane(BspLeaf *leaf, BspTraversalData &data)
1173{
1174        if (data.mPolygons->empty() && data.mRays->empty())
1175        {
1176                Debug << "Warning: No autopartition polygon candidate available\n";
1177       
1178                // return axis aligned split
1179                AxisAlignedBox3 box;
1180                box.Initialize();
1181       
1182                // create bounding box of region
1183                Polygon3::IncludeInBox(*data.mPolygons, box);
1184
1185                const int axis = box.Size().DrivingAxis();
1186                const Vector3 position = (box.Min()[axis] + box.Max()[axis])*0.5f;
1187
1188                Vector3 norm(0,0,0); norm[axis] = 1.0f;
1189                return Plane3(norm, position);
1190        }
1191       
1192        if ((mSplitPlaneStrategy & AXIS_ALIGNED) &&
1193                ((int)data.mPolygons->size() > mTermMinPolysForAxisAligned) &&
1194                ((int)data.mRays->size() > mTermMinRaysForAxisAligned) &&
1195                ((mTermMinObjectsForAxisAligned < 0) ||
1196                  (Polygon3::ParentObjectsSize(*data.mPolygons) > mTermMinObjectsForAxisAligned)))
1197        {
1198                Plane3 plane;
1199                if (SelectAxisAlignedPlane(plane, *data.mPolygons))
1200                        return plane;
1201        }
1202
1203        // simplest strategy: just take next polygon
1204        if (mSplitPlaneStrategy & RANDOM_POLYGON)
1205        {
1206        if (!data.mPolygons->empty())
1207                {
1208                        Polygon3 *nextPoly =
1209                                (*data.mPolygons)[(int)RandomValue(0, (Real)((int)data.mPolygons->size() - 1))];
1210                        return nextPoly->GetSupportingPlane();
1211                }
1212                else
1213                {
1214                        const int candidateIdx = (int)RandomValue(0, (Real)((int)data.mRays->size() - 1));
1215                        BoundedRay *bRay = (*data.mRays)[candidateIdx];
1216
1217                        Ray *ray = bRay->mRay;
1218                                               
1219                        const Vector3 minPt = ray->Extrap(bRay->mMinT);
1220                        const Vector3 maxPt = ray->Extrap(bRay->mMaxT);
1221
1222                        const Vector3 pt = (maxPt + minPt) * 0.5;
1223
1224                        const Vector3 normal = ray->GetDir();
1225                       
1226                        return Plane3(normal, pt);
1227                }
1228
1229                return Plane3();
1230        }
1231
1232        // use heuristics to find appropriate plane
1233        return SelectPlaneHeuristics(leaf, data);
1234}
1235
1236
1237Plane3 BspTree::ChooseCandidatePlane(const BoundedRayContainer &rays) const
1238{       
1239        const int candidateIdx = (int)RandomValue(0, (Real)((int)rays.size() - 1));
1240        BoundedRay *bRay = rays[candidateIdx];
1241        Ray *ray = bRay->mRay;
1242
1243        const Vector3 minPt = ray->Extrap(bRay->mMinT);
1244        const Vector3 maxPt = ray->Extrap(bRay->mMaxT);
1245
1246        const Vector3 pt = (maxPt + minPt) * 0.5;
1247
1248        const Vector3 normal = ray->GetDir();
1249                       
1250        return Plane3(normal, pt);
1251}
1252
1253Plane3 BspTree::ChooseCandidatePlane2(const BoundedRayContainer &rays) const
1254{       
1255        Vector3 pt[3];
1256        int idx[3];
1257        int cmaxT = 0;
1258        int cminT = 0;
1259        bool chooseMin = false;
1260
1261        for (int j = 0; j < 3; j ++)
1262        {
1263                idx[j] = (int)RandomValue(0, Real((int)rays.size() * 2 - 1));
1264                               
1265                if (idx[j] >= (int)rays.size())
1266                {
1267                        idx[j] -= (int)rays.size();             
1268                        chooseMin = (cminT < 2);
1269                }
1270                else
1271                        chooseMin = (cmaxT < 2);
1272
1273                BoundedRay *bRay = rays[idx[j]];
1274                pt[j] = chooseMin ? bRay->mRay->Extrap(bRay->mMinT) :
1275                                                        bRay->mRay->Extrap(bRay->mMaxT);
1276        }       
1277                       
1278        return Plane3(pt[0], pt[1], pt[2]);
1279}
1280
1281Plane3 BspTree::ChooseCandidatePlane3(const BoundedRayContainer &rays) const
1282{       
1283        Vector3 pt[3];
1284       
1285        int idx1 = (int)RandomValue(0, (Real)((int)rays.size() - 1));
1286        int idx2 = (int)RandomValue(0, (Real)((int)rays.size() - 1));
1287
1288        // check if rays different
1289        if (idx1 == idx2)
1290                idx2 = (idx2 + 1) % (int)rays.size();
1291
1292        const BoundedRay *ray1 = rays[idx1];
1293        const BoundedRay *ray2 = rays[idx2];
1294
1295        // normal vector of the plane parallel to both lines
1296        const Vector3 norm =
1297                Normalize(CrossProd(ray1->mRay->GetDir(), ray2->mRay->GetDir()));
1298
1299        const Vector3 orig1 = ray1->mRay->Extrap(ray1->mMinT);
1300        const Vector3 orig2 = ray2->mRay->Extrap(ray2->mMinT);
1301
1302        // vector from line 1 to line 2
1303        const Vector3 vd = orig1 - orig2;
1304       
1305        // project vector on normal to get distance
1306        const float dist = DotProd(vd, norm);
1307
1308        // point on plane lies halfway between the two planes
1309        const Vector3 planePt = orig1 + norm * dist * 0.5;
1310
1311        return Plane3(norm, planePt);
1312}
1313
1314
1315Plane3 BspTree::SelectPlaneHeuristics(BspLeaf *leaf, BspTraversalData &data)
1316{
1317        float lowestCost = MAX_FLOAT;
1318        Plane3 bestPlane;
1319        // intermediate plane
1320        Plane3 plane;
1321
1322        const int limit = Min((int)data.mPolygons->size(), mMaxPolyCandidates);
1323        int maxIdx = (int)data.mPolygons->size();
1324       
1325        for (int i = 0; i < limit; ++ i)
1326        {
1327                // assure that no index is taken twice
1328                const int candidateIdx = (int)RandomValue(0, (Real)(-- maxIdx));
1329                //Debug << "current Idx: " << maxIdx << " cand idx " << candidateIdx << endl;
1330               
1331                Polygon3 *poly = (*data.mPolygons)[candidateIdx];
1332
1333                // swap candidate to the end to avoid testing same plane
1334                std::swap((*data.mPolygons)[maxIdx], (*data.mPolygons)[candidateIdx]);
1335       
1336                //Polygon3 *poly = (*data.mPolygons)[(int)RandomValue(0, (int)polys.size() - 1)];
1337
1338                // evaluate current candidate
1339                const float candidateCost =
1340                        SplitPlaneCost(poly->GetSupportingPlane(), data);
1341
1342                if (candidateCost < lowestCost)
1343                {
1344                        bestPlane = poly->GetSupportingPlane();
1345                        lowestCost = candidateCost;
1346                }
1347        }
1348       
1349        //-- choose candidate planes extracted from rays
1350        for (int i = 0; i < mMaxRayCandidates; ++ i)
1351        {
1352                plane = ChooseCandidatePlane3(*data.mRays);
1353                const float candidateCost = SplitPlaneCost(plane, data);
1354
1355                if (candidateCost < lowestCost)
1356                {
1357                        bestPlane = plane;     
1358                        lowestCost = candidateCost;
1359                }
1360        }
1361
1362#ifdef _DEBUG
1363        Debug << "plane lowest cost: " << lowestCost << endl;
1364#endif
1365
1366        return bestPlane;
1367}
1368
1369
1370float BspTree::SplitPlaneCost(const Plane3 &candidatePlane,
1371                                                          const PolygonContainer &polys) const
1372{
1373        float val = 0;
1374
1375        float sumBalancedPolys = 0;
1376        float sumSplits = 0;
1377        float sumPolyArea = 0;
1378        float sumBalancedViewCells = 0;
1379        float sumBlockedRays = 0;
1380        float totalBlockedRays = 0;
1381        //float totalArea = 0;
1382        int totalViewCells = 0;
1383
1384        // need three unique ids for each type of view cell
1385        // for balanced view cells criterium
1386        ViewCell::NewMail();
1387        const int backId = ViewCell::sMailId;
1388        ViewCell::NewMail();
1389        const int frontId = ViewCell::sMailId;
1390        ViewCell::NewMail();
1391        const int frontAndBackId = ViewCell::sMailId;
1392
1393        bool useRand;;
1394        int limit;
1395
1396        // choose test polyongs randomly if over threshold
1397        if ((int)polys.size() > mMaxTests)
1398        {
1399                useRand = true;
1400                limit = mMaxTests;
1401        }
1402        else
1403        {
1404                useRand = false;
1405                limit = (int)polys.size();
1406        }
1407
1408        for (int i = 0; i < limit; ++ i)
1409        {
1410                const int testIdx = useRand ? (int)RandomValue(0, (Real)(limit - 1)) : i;
1411
1412                Polygon3 *poly = polys[testIdx];
1413
1414        const int classification =
1415                        poly->ClassifyPlane(candidatePlane, mEpsilon);
1416
1417                if (mSplitPlaneStrategy & BALANCED_POLYS)
1418                        sumBalancedPolys += sBalancedPolysTable[classification];
1419               
1420                if (mSplitPlaneStrategy & LEAST_SPLITS)
1421                        sumSplits += sLeastPolySplitsTable[classification];
1422
1423                if (mSplitPlaneStrategy & LARGEST_POLY_AREA)
1424                {
1425                        if (classification == Polygon3::COINCIDENT)
1426                                sumPolyArea += poly->GetArea();
1427                        //totalArea += area;
1428                }
1429               
1430                if (mSplitPlaneStrategy & BLOCKED_RAYS)
1431                {
1432                        const float blockedRays = (float)poly->mPiercingRays.size();
1433               
1434                        if (classification == Polygon3::COINCIDENT)
1435                                sumBlockedRays += blockedRays;
1436                       
1437                        totalBlockedRays += blockedRays;
1438                }
1439
1440                // assign view cells to back or front according to classificaion
1441                if (mSplitPlaneStrategy & BALANCED_VIEW_CELLS)
1442                {
1443                        MeshInstance *viewCell = poly->mParent;
1444               
1445                        // assure that we only count a view cell
1446                        // once for the front and once for the back side of the plane
1447                        if (classification == Polygon3::FRONT_SIDE)
1448                        {
1449                                if ((viewCell->mMailbox != frontId) &&
1450                                        (viewCell->mMailbox != frontAndBackId))
1451                                {
1452                                        sumBalancedViewCells += 1.0;
1453
1454                                        if (viewCell->mMailbox != backId)
1455                                                viewCell->mMailbox = frontId;
1456                                        else
1457                                                viewCell->mMailbox = frontAndBackId;
1458                                       
1459                                        ++ totalViewCells;
1460                                }
1461                        }
1462                        else if (classification == Polygon3::BACK_SIDE)
1463                        {
1464                                if ((viewCell->mMailbox != backId) &&
1465                                    (viewCell->mMailbox != frontAndBackId))
1466                                {
1467                                        sumBalancedViewCells -= 1.0;
1468
1469                                        if (viewCell->mMailbox != frontId)
1470                                                viewCell->mMailbox = backId;
1471                                        else
1472                                                viewCell->mMailbox = frontAndBackId;
1473
1474                                        ++ totalViewCells;
1475                                }
1476                        }
1477                }
1478        }
1479
1480        const float polysSize = (float)polys.size() + Limits::Small;
1481
1482        // all values should be approx. between 0 and 1 so they can be combined
1483        // and scaled with the factors according to their importance
1484        if (mSplitPlaneStrategy & BALANCED_POLYS)
1485                val += mBalancedPolysFactor * fabs(sumBalancedPolys) / polysSize;
1486       
1487        if (mSplitPlaneStrategy & LEAST_SPLITS) 
1488                val += mLeastSplitsFactor * sumSplits / polysSize;
1489
1490        if (mSplitPlaneStrategy & LARGEST_POLY_AREA)
1491                // HACK: polys.size should be total area so scaling is between 0 and 1
1492                val += mLargestPolyAreaFactor * (float)polys.size() / sumPolyArea;
1493
1494        if (mSplitPlaneStrategy & BLOCKED_RAYS)
1495                if (totalBlockedRays != 0)
1496                        val += mBlockedRaysFactor * (totalBlockedRays - sumBlockedRays) / totalBlockedRays;
1497
1498        if (mSplitPlaneStrategy & BALANCED_VIEW_CELLS)
1499                val += mBalancedViewCellsFactor * fabs(sumBalancedViewCells) /
1500                        ((float)totalViewCells + Limits::Small);
1501       
1502        return val;
1503}
1504
1505
1506inline void BspTree::GenerateUniqueIdsForPvs()
1507{
1508        Intersectable::NewMail(); sBackId = ViewCell::sMailId;
1509        Intersectable::NewMail(); sFrontId = ViewCell::sMailId;
1510        Intersectable::NewMail(); sFrontAndBackId = ViewCell::sMailId;
1511}
1512
1513
1514float BspTree::SplitPlaneCost(const Plane3 &candidatePlane,
1515                                                          const BoundedRayContainer &rays,
1516                                                          const int pvs,
1517                                                          const float area,
1518                                                          const BspNodeGeometry &cell) const
1519{
1520        float val = 0;
1521
1522        float sumBalancedRays = 0;
1523        float sumRaySplits = 0;
1524
1525        int frontPvs = 0;
1526        int backPvs = 0;
1527
1528        // probability that view point lies in child
1529        float pOverall = 0;
1530        float pFront = 0;
1531        float pBack = 0;
1532
1533        const bool pvsUseLen = false;
1534
1535        if (mSplitPlaneStrategy & PVS)
1536        {
1537                // create unique ids for pvs heuristics
1538                GenerateUniqueIdsForPvs();
1539
1540                if (mUseAreaForPvs) // use front and back cell areas to approximate volume
1541                {
1542                        // construct child geometry with regard to the candidate split plane
1543                        BspNodeGeometry frontCell;
1544                        BspNodeGeometry backCell;
1545
1546                        cell.SplitGeometry(frontCell,
1547                                                           backCell,
1548                                                           candidatePlane,
1549                                                           mBox,
1550                                                           mEpsilon);
1551               
1552                        pFront = frontCell.GetArea();
1553                        pBack = backCell.GetArea();
1554
1555                        pOverall = area;
1556                }
1557        }
1558                       
1559        bool useRand;
1560        int limit;
1561
1562        // choose test polyongs randomly if over threshold
1563        if ((int)rays.size() > mMaxTests)
1564        {
1565                useRand = true;
1566                limit = mMaxTests;
1567        }
1568        else
1569        {
1570                useRand = false;
1571                limit = (int)rays.size();
1572        }
1573
1574        for (int i = 0; i < limit; ++ i)
1575        {
1576                const int testIdx = useRand ? (int)RandomValue(0, (Real)(limit - 1)) : i;
1577       
1578                BoundedRay *bRay = rays[testIdx];
1579
1580                Ray *ray = bRay->mRay;
1581                const float minT = bRay->mMinT;
1582                const float maxT = bRay->mMaxT;
1583
1584                Vector3 entP, extP;
1585
1586                const int cf =
1587                        ray->ClassifyPlane(candidatePlane, minT, maxT, entP, extP);
1588
1589                if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)
1590                {
1591                        sumBalancedRays += sBalancedRaysTable[cf];
1592                }
1593               
1594                if (mSplitPlaneStrategy & BALANCED_RAYS)
1595                {
1596                        sumRaySplits += sLeastRaySplitsTable[cf];
1597                }
1598
1599                if (mSplitPlaneStrategy & PVS)
1600                {
1601                        // in case the ray intersects an object
1602                        // assure that we only count the object
1603                        // once for the front and once for the back side of the plane
1604                       
1605                        // add the termination object
1606                        if (!ray->intersections.empty())
1607                                AddObjToPvs(ray->intersections[0].mObject, cf, frontPvs, backPvs);
1608                       
1609                        // add the source object
1610                        AddObjToPvs(ray->sourceObject.mObject, cf, frontPvs, backPvs);
1611                       
1612                        if (mUseAreaForPvs)
1613                        {
1614                                float len = 1;
1615                       
1616                                if (pvsUseLen)
1617                                        len = SqrDistance(entP, extP);
1618       
1619                                // use length of rays to approximate volume
1620                                if (Ray::BACK && Ray::COINCIDENT)
1621                                        pBack += len;
1622                                if (Ray::FRONT && Ray::COINCIDENT)
1623                                        pFront += len;
1624                                if (Ray::FRONT_BACK || Ray::BACK_FRONT)
1625                                {
1626                                        if (pvsUseLen)
1627                                        {
1628                                                const Vector3 extp = ray->Extrap(maxT);
1629                                                const float t = candidatePlane.FindT(ray->GetLoc(), extp);
1630                               
1631                                                const float newT = t * maxT;
1632                                                const float newLen = SqrDistance(ray->Extrap(newT), extp);
1633
1634                                                if (Ray::FRONT_BACK)
1635                                                {
1636                                                        pFront += len - newLen;
1637                                                        pBack += newLen;
1638                                                }
1639                                                else
1640                                                {
1641                                                        pBack += len - newLen;
1642                                                        pFront += newLen;
1643                                                }
1644                                        }
1645                                        else
1646                                        {
1647                                                ++ pFront;
1648                                                ++ pBack;
1649                                        }
1650                                }
1651                        }
1652                }
1653        }
1654
1655        const float raysSize = (float)rays.size() + Limits::Small;
1656
1657        if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)
1658                val += mLeastRaySplitsFactor * sumRaySplits / raysSize;
1659
1660        if (mSplitPlaneStrategy & BALANCED_RAYS)
1661                val += mBalancedRaysFactor * fabs(sumBalancedRays) /  raysSize;
1662
1663        const float denom = pOverall * (float)pvs * 2.0f + Limits::Small;
1664
1665        if (mSplitPlaneStrategy & PVS)
1666        {
1667                val += mPvsFactor * (frontPvs * pFront + (backPvs * pBack)) / denom;
1668
1669                // give penalty to unbalanced split
1670                if (0)
1671                if (((pFront * 0.2 + Limits::Small) > pBack) ||
1672                        (pFront < (pBack * 0.2 + Limits::Small)))
1673                        val += 0.5;
1674        }
1675
1676       
1677#ifdef _DEBUG
1678        Debug << "totalpvs: " << pvs << " ptotal: " << pOverall
1679                  << " frontpvs: " << frontPvs << " pFront: " << pFront
1680                  << " backpvs: " << backPvs << " pBack: " << pBack << endl << endl;
1681#endif
1682       
1683        return val;
1684}
1685
1686void BspTree::AddObjToPvs(Intersectable *obj,
1687                                                  const int cf,
1688                                                  int &frontPvs,
1689                                                  int &backPvs) const
1690{
1691        if (!obj)
1692                return;
1693        // TODO: does this really belong to no pvs?
1694        //if (cf == Ray::COINCIDENT) return;
1695
1696        // object belongs to both PVS
1697        const bool bothSides = (cf == Ray::FRONT_BACK) ||
1698                                                   (cf == Ray::BACK_FRONT) ||
1699                                                   (cf == Ray::COINCIDENT);
1700
1701        if ((cf == Ray::FRONT) || bothSides)
1702        {
1703                if ((obj->mMailbox != sFrontId) &&
1704                        (obj->mMailbox != sFrontAndBackId))
1705                {
1706                        ++ frontPvs;
1707
1708                        if (obj->mMailbox == sBackId)
1709                                obj->mMailbox = sFrontAndBackId;       
1710                        else
1711                                obj->mMailbox = sFrontId;                                                               
1712                }
1713        }
1714       
1715        if ((cf == Ray::BACK) || bothSides)
1716        {
1717                if ((obj->mMailbox != sBackId) &&
1718                        (obj->mMailbox != sFrontAndBackId))
1719                {
1720                        ++ backPvs;
1721
1722                        if (obj->mMailbox == sFrontId)
1723                                obj->mMailbox = sFrontAndBackId;
1724                        else
1725                                obj->mMailbox = sBackId;                               
1726                }
1727        }
1728}
1729
1730float BspTree::SplitPlaneCost(const Plane3 &candidatePlane,
1731                                                          BspTraversalData &data) const
1732{
1733        float val = 0;
1734
1735        if (mSplitPlaneStrategy & VERTICAL_AXIS)
1736        {
1737                Vector3 tinyAxis(0,0,0); tinyAxis[mBox.Size().TinyAxis()] = 1.0f;
1738                // we put a penalty on the dot product between the "tiny" vertical axis
1739                // and the split plane axis
1740                val += mVerticalSplitsFactor *
1741                           fabs(DotProd(candidatePlane.mNormal, tinyAxis));
1742        }
1743
1744        // the following criteria loop over all polygons to find the cost value
1745        if ((mSplitPlaneStrategy & BALANCED_POLYS)      ||
1746                (mSplitPlaneStrategy & LEAST_SPLITS)        ||
1747                (mSplitPlaneStrategy & LARGEST_POLY_AREA)   ||
1748                (mSplitPlaneStrategy & BALANCED_VIEW_CELLS) ||
1749                (mSplitPlaneStrategy & BLOCKED_RAYS))
1750        {
1751                val += SplitPlaneCost(candidatePlane, *data.mPolygons);
1752        }
1753
1754        // the following criteria loop over all rays to find the cost value
1755        if ((mSplitPlaneStrategy & BALANCED_RAYS)      ||
1756                (mSplitPlaneStrategy & LEAST_RAY_SPLITS)   ||
1757                (mSplitPlaneStrategy & PVS))
1758        {
1759                val += SplitPlaneCost(candidatePlane, *data.mRays, data.mPvs,
1760                                                          data.mArea, *data.mGeometry);
1761        }
1762
1763        // return linear combination of the sums
1764        return val;
1765}
1766
1767void BspTree::CollectLeaves(vector<BspLeaf *> &leaves) const
1768{
1769        stack<BspNode *> nodeStack;
1770        nodeStack.push(mRoot);
1771 
1772        while (!nodeStack.empty())
1773        {
1774                BspNode *node = nodeStack.top();
1775   
1776                nodeStack.pop();
1777   
1778                if (node->IsLeaf())
1779                {
1780                        BspLeaf *leaf = (BspLeaf *)node;               
1781                        leaves.push_back(leaf);
1782                }
1783                else
1784                {
1785                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1786
1787                        nodeStack.push(interior->GetBack());
1788                        nodeStack.push(interior->GetFront());
1789                }
1790        }
1791}
1792
1793
1794AxisAlignedBox3 BspTree::GetBoundingBox() const
1795{
1796        return mBox;
1797}
1798
1799
1800BspNode *BspTree::GetRoot() const
1801{
1802        return mRoot;
1803}
1804
1805void BspTree::EvaluateLeafStats(const BspTraversalData &data)
1806{
1807        // the node became a leaf -> evaluate stats for leafs
1808        BspLeaf *leaf = dynamic_cast<BspLeaf *>(data.mNode);
1809
1810        // store maximal and minimal depth
1811        if (data.mDepth > mStat.maxDepth)
1812                mStat.maxDepth = data.mDepth;
1813
1814        if (data.mDepth < mStat.minDepth)
1815                mStat.minDepth = data.mDepth;
1816
1817        // accumulate depth to compute average depth
1818        mStat.accumDepth += data.mDepth;
1819        // accumulate rays to compute rays /  leaf
1820        mStat.accumRays += (int)data.mRays->size();
1821
1822        if (data.mDepth >= mTermMaxDepth)
1823                ++ mStat.maxDepthNodes;
1824
1825        if (data.mPvs < mTermMinPvs)
1826                ++ mStat.minPvsNodes;
1827
1828        if ((int)data.mRays->size() < mTermMinRays)
1829                ++ mStat.minRaysNodes;
1830
1831        if (data.GetAvgRayContribution() > mTermMaxRayContribution)
1832                ++ mStat.maxRayContribNodes;
1833       
1834        if (data.mGeometry->GetArea() <= mTermMinArea)
1835                ++ mStat.minProbabilityNodes;
1836
1837#ifdef _DEBUG
1838        Debug << "BSP stats: "
1839                  << "Depth: " << data.mDepth << " (max: " << mTermMaxDepth << "), "
1840                  << "PVS: " << data.mPvs << " (min: " << mTermMinPvs << "), "
1841                  << "Area: " << data.mArea << " (min: " << mTermMinArea << "), "
1842                  << "#polygons: " << (int)data.mPolygons->size() << " (max: " << mTermMinPolys << "), "
1843                  << "#rays: " << (int)data.mRays->size() << " (max: " << mTermMinRays << "), "
1844                  << "#pvs: " << leaf->GetViewCell()->GetPvs().GetSize() << "=, "
1845                  << "#avg ray contrib (pvs): " << (float)data.mPvs / (float)data.mRays->size() << endl;
1846#endif
1847}
1848
1849int
1850BspTree::_CastRay(Ray &ray)
1851{
1852        int hits = 0;
1853 
1854        stack<BspRayTraversalData> tStack;
1855 
1856        float maxt, mint;
1857
1858        if (!mBox.GetRaySegment(ray, mint, maxt))
1859                return 0;
1860
1861        Intersectable::NewMail();
1862
1863        Vector3 entp = ray.Extrap(mint);
1864        Vector3 extp = ray.Extrap(maxt);
1865 
1866        BspNode *node = mRoot;
1867        BspNode *farChild = NULL;
1868       
1869        while (1)
1870        {
1871                if (!node->IsLeaf())
1872                {
1873                        BspInterior *in = dynamic_cast<BspInterior *>(node);
1874                       
1875                        Plane3 splitPlane = in->GetPlane();
1876                        const int entSide = splitPlane.Side(entp);
1877                        const int extSide = splitPlane.Side(extp);
1878
1879                        if (entSide < 0)
1880                        {
1881                                node = in->GetBack();
1882
1883                                if(extSide <= 0) // plane does not split ray => no far child
1884                                        continue;
1885                                       
1886                                farChild = in->GetFront(); // plane splits ray
1887
1888                        } else if (entSide > 0)
1889                        {
1890                                node = in->GetFront();
1891
1892                                if (extSide >= 0) // plane does not split ray => no far child
1893                                        continue;
1894
1895                                farChild = in->GetBack(); // plane splits ray                   
1896                        }
1897                        else // ray and plane are coincident
1898                        {
1899                                // WHAT TO DO IN THIS CASE ?
1900                                //break;
1901                                node = in->GetFront();
1902                                continue;
1903                        }
1904
1905                        // push data for far child
1906                        tStack.push(BspRayTraversalData(farChild, extp, maxt));
1907
1908                        // find intersection of ray segment with plane
1909                        float t;
1910                        extp = splitPlane.FindIntersection(ray.GetLoc(), extp, &t);
1911                        maxt *= t;
1912                       
1913                } else // reached leaf => intersection with view cell
1914                {
1915                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
1916     
1917                        if (!leaf->mViewCell->Mailed())
1918                        {
1919                          //                            ray.bspIntersections.push_back(Ray::BspIntersection(maxt, leaf));
1920                                leaf->mViewCell->Mail();
1921                                ++ hits;
1922                        }
1923                       
1924                        //-- fetch the next far child from the stack
1925                        if (tStack.empty())
1926                                break;
1927     
1928                        entp = extp;
1929                        mint = maxt; // NOTE: need this?
1930
1931                        if (ray.GetType() == Ray::LINE_SEGMENT && mint > 1.0f)
1932                                break;
1933
1934                        BspRayTraversalData &s = tStack.top();
1935
1936                        node = s.mNode;
1937                        extp = s.mExitPoint;
1938                        maxt = s.mMaxT;
1939
1940                        tStack.pop();
1941                }
1942        }
1943
1944        return hits;
1945}
1946
1947
1948int BspTree::CastLineSegment(const Vector3 &origin,
1949                                                         const Vector3 &termination,
1950                                                         vector<ViewCell *> &viewcells)
1951{
1952        int hits = 0;
1953        stack<BspRayTraversalData> tStack;
1954
1955        float mint = 0.0f, maxt = 1.0f;
1956
1957        Intersectable::NewMail();
1958
1959        Vector3 entp = origin;
1960        Vector3 extp = termination;
1961
1962        BspNode *node = mRoot;
1963        BspNode *farChild = NULL;
1964
1965        while (1)
1966        {
1967                if (!node->IsLeaf()) 
1968                {
1969                        BspInterior *in = dynamic_cast<BspInterior *>(node);
1970               
1971                        Plane3 splitPlane = in->GetPlane();
1972                       
1973                        const int entSide = splitPlane.Side(entp);
1974                        const int extSide = splitPlane.Side(extp);
1975
1976                        if (entSide < 0)
1977                        {
1978                                node = in->GetBack();
1979               
1980                                if(extSide <= 0) // plane does not split ray => no far child
1981                                        continue;
1982               
1983                                farChild = in->GetFront(); // plane splits ray
1984               
1985                        }
1986                        else if (entSide > 0)
1987                        {
1988                                node = in->GetFront();
1989                       
1990                                if (extSide >= 0) // plane does not split ray => no far child
1991                                        continue;
1992                       
1993                                farChild = in->GetBack(); // plane splits ray                   
1994                        }
1995                        else // ray and plane are coincident
1996                        {
1997                                // WHAT TO DO IN THIS CASE ?
1998                                //break;
1999                                node = in->GetFront();
2000                                continue;
2001                        }
2002               
2003                        // push data for far child
2004                        tStack.push(BspRayTraversalData(farChild, extp, maxt));
2005               
2006                        // find intersection of ray segment with plane
2007                        float t;
2008                        extp = splitPlane.FindIntersection(origin, extp, &t);
2009                        maxt *= t; 
2010                }
2011                else
2012                {
2013                        // reached leaf => intersection with view cell
2014                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
2015               
2016                        if (!leaf->mViewCell->Mailed())
2017                        {
2018                                viewcells.push_back(leaf->mViewCell);
2019                                leaf->mViewCell->Mail();
2020                                hits++;
2021                        }
2022               
2023                        //-- fetch the next far child from the stack
2024                        if (tStack.empty())
2025                                break;
2026           
2027                        entp = extp;
2028                        mint = maxt; // NOTE: need this?
2029               
2030                        BspRayTraversalData &s = tStack.top();
2031               
2032                        node = s.mNode;
2033                        extp = s.mExitPoint;
2034                        maxt = s.mMaxT;
2035               
2036                        tStack.pop();
2037                }
2038        }
2039        return hits;
2040}
2041
2042bool BspTree::Export(const string filename)
2043{
2044        Exporter *exporter = Exporter::GetExporter(filename);
2045
2046        if (exporter)
2047        {
2048                exporter->ExportBspTree(*this);
2049                return true;
2050        }       
2051
2052        return false;
2053}
2054
2055void BspTree::CollectViewCells(ViewCellContainer &viewCells) const
2056{
2057        stack<BspNode *> nodeStack;
2058        nodeStack.push(mRoot);
2059
2060        ViewCell::NewMail();
2061
2062        while (!nodeStack.empty())
2063        {
2064                BspNode *node = nodeStack.top();
2065                nodeStack.pop();
2066
2067                if (node->IsLeaf())
2068                {
2069                        ViewCell *viewCell = dynamic_cast<BspLeaf *>(node)->mViewCell;
2070
2071                        if (!viewCell->Mailed())
2072                        {
2073                                viewCell->Mail();
2074                                viewCells.push_back(viewCell);
2075                        }
2076                }
2077                else
2078                {
2079                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2080
2081                        nodeStack.push(interior->GetFront());
2082                        nodeStack.push(interior->GetBack());
2083                }
2084        }
2085}
2086
2087
2088BspTreeStatistics &BspTree::GetStat()
2089{
2090        return mStat;
2091}
2092
2093
2094float BspTree::AccumulatedRayLength(BoundedRayContainer &rays) const
2095{
2096        float len = 0;
2097
2098        BoundedRayContainer::const_iterator it, it_end = rays.end();
2099
2100        for (it = rays.begin(); it != it_end; ++ it)
2101        {
2102                len += SqrDistance((*it)->mRay->Extrap((*it)->mMinT),
2103                                                   (*it)->mRay->Extrap((*it)->mMaxT));
2104        }
2105
2106        return len;
2107}
2108
2109
2110int BspTree::SplitRays(const Plane3 &plane,
2111                                           BoundedRayContainer &rays,
2112                                           BoundedRayContainer &frontRays,
2113                                           BoundedRayContainer &backRays)
2114{
2115        int splits = 0;
2116       
2117        while (!rays.empty())
2118        {
2119                BoundedRay *bRay = rays.back();
2120                Ray *ray = bRay->mRay;
2121                float minT = bRay->mMinT;
2122                float maxT = bRay->mMaxT;
2123
2124                rays.pop_back();
2125       
2126                Vector3 entP, extP;
2127
2128                const int cf =
2129                        ray->ClassifyPlane(plane, minT, maxT, entP, extP);
2130               
2131                // set id to ray classification
2132                ray->SetId(cf);
2133
2134                switch (cf)
2135                {
2136                case Ray::COINCIDENT: // TODO: should really discard ray?
2137                        frontRays.push_back(bRay);
2138                        //DEL_PTR(bRay);
2139                        break;
2140                case Ray::BACK:
2141                        backRays.push_back(bRay);
2142                        break;
2143                case Ray::FRONT:
2144                        frontRays.push_back(bRay);
2145                        break;
2146                case Ray::FRONT_BACK:
2147                        {
2148                                // find intersection of ray segment with plane
2149                                const float t = plane.FindT(ray->GetLoc(), extP);
2150                               
2151                                const float newT = t * maxT;
2152
2153                                frontRays.push_back(new BoundedRay(ray, minT, newT));
2154                                backRays.push_back(new BoundedRay(ray, newT, maxT));
2155
2156                                DEL_PTR(bRay);
2157                        }
2158                        break;
2159                case Ray::BACK_FRONT:
2160                        {
2161                                // find intersection of ray segment with plane
2162                                const float t = plane.FindT(ray->GetLoc(), extP);
2163                                const float newT = t * bRay->mMaxT;
2164
2165                                backRays.push_back(new BoundedRay(ray, minT, newT));
2166                                frontRays.push_back(new BoundedRay(ray, newT, maxT));
2167
2168                                DEL_PTR(bRay);
2169
2170                                ++ splits;
2171                        }
2172                        break;
2173                default:
2174                        Debug << "Should not come here 4" << endl;
2175                        break;
2176                }
2177        }
2178
2179        return splits;
2180}
2181
2182void BspTree::ExtractHalfSpaces(BspNode *n, vector<Plane3> &halfSpaces) const
2183{
2184        BspNode *lastNode;
2185        do
2186        {
2187                lastNode = n;
2188
2189                // want to get planes defining geometry of this node => don't take
2190                // split plane of node itself
2191                n = n->GetParent();
2192               
2193                if (n)
2194                {
2195                        BspInterior *interior = dynamic_cast<BspInterior *>(n);
2196                        Plane3 halfSpace = dynamic_cast<BspInterior *>(interior)->GetPlane();
2197
2198            if (interior->GetFront() != lastNode)
2199                                halfSpace.ReverseOrientation();
2200
2201                        halfSpaces.push_back(halfSpace);
2202                }
2203        }
2204        while (n);
2205}
2206
2207void BspTree::ConstructGeometry(BspViewCell *vc, BspNodeGeometry &geom) const
2208{
2209        vector<BspLeaf *> leaves = vc->mLeaves;
2210
2211        vector<BspLeaf *>::const_iterator it, it_end = leaves.end();
2212
2213        for (it = leaves.begin(); it != it_end; ++ it)
2214                ConstructGeometry(*it, geom);
2215}
2216
2217
2218void BspTree::ConstructGeometry(BspNode *n, BspNodeGeometry &geom) const
2219{
2220        vector<Plane3> halfSpaces;
2221        ExtractHalfSpaces(n, halfSpaces);
2222
2223        PolygonContainer candidates;
2224
2225        // bounded planes are added to the polygons (reverse polygons
2226        // as they have to be outfacing
2227        for (int i = 0; i < (int)halfSpaces.size(); ++ i)
2228        {
2229                Polygon3 *p = GetBoundingBox().CrossSection(halfSpaces[i]);
2230               
2231                if (p->Valid(mEpsilon))
2232                {
2233                        candidates.push_back(p->CreateReversePolygon());
2234                        DEL_PTR(p);
2235                }
2236        }
2237
2238        // add faces of bounding box (also could be faces of the cell)
2239        for (int i = 0; i < 6; ++ i)
2240        {
2241                VertexContainer vertices;
2242       
2243                for (int j = 0; j < 4; ++ j)
2244                        vertices.push_back(mBox.GetFace(i).mVertices[j]);
2245
2246                candidates.push_back(new Polygon3(vertices));
2247        }
2248
2249        for (int i = 0; i < (int)candidates.size(); ++ i)
2250        {
2251                // polygon is split by all other planes
2252                for (int j = 0; (j < (int)halfSpaces.size()) && candidates[i]; ++ j)
2253                {
2254                        if (i == j) // polygon and plane are coincident
2255                                continue;
2256
2257                        VertexContainer splitPts;
2258                        Polygon3 *frontPoly, *backPoly;
2259
2260                        const int cf = candidates[i]->
2261                                ClassifyPlane(halfSpaces[j], mEpsilon);
2262                       
2263                        switch (cf)
2264                        {
2265                                case Polygon3::SPLIT:
2266                                        frontPoly = new Polygon3();
2267                                        backPoly = new Polygon3();
2268
2269                                        candidates[i]->Split(halfSpaces[j],
2270                                                                                 *frontPoly,
2271                                                                                 *backPoly,
2272                                                                                 mEpsilon);
2273
2274                                        DEL_PTR(candidates[i]);
2275
2276                                        if (frontPoly->Valid(mEpsilon))
2277                                                candidates[i] = frontPoly;
2278                                        else
2279                                                DEL_PTR(frontPoly);
2280
2281                                        DEL_PTR(backPoly);
2282                                        break;
2283                                case Polygon3::BACK_SIDE:
2284                                        DEL_PTR(candidates[i]);
2285                                        break;
2286                                // just take polygon as it is
2287                                case Polygon3::FRONT_SIDE:
2288                                case Polygon3::COINCIDENT:
2289                                default:
2290                                        break;
2291                        }
2292                }
2293               
2294                if (candidates[i])
2295                        geom.mPolys.push_back(candidates[i]);
2296        }
2297}
2298
2299
2300int BspTree::FindNeighbors(BspNode *n, vector<BspLeaf *> &neighbors,
2301                                                   const bool onlyUnmailed) const
2302{
2303        BspNodeGeometry geom;
2304        ConstructGeometry(n, geom);
2305
2306        stack<BspNode *> nodeStack;
2307        nodeStack.push(mRoot);
2308               
2309        // planes needed to verify that we found neighbor leaf.
2310        vector<Plane3> halfSpaces;
2311        ExtractHalfSpaces(n, halfSpaces);
2312
2313        while (!nodeStack.empty())
2314        {
2315                BspNode *node = nodeStack.top();
2316                nodeStack.pop();
2317
2318                if (node->IsLeaf())
2319                {
2320            if (node != n && (!onlyUnmailed || !node->Mailed()))
2321                        {
2322                                // test all planes of current node if neighbour
2323                                // candidate really is neighbour
2324                                BspNodeGeometry candidateGeom;
2325                                ConstructGeometry(node, candidateGeom);
2326                               
2327                                bool isAdjacent = true;
2328                                for (int i = 0; (i < halfSpaces.size()) && isAdjacent; ++ i)
2329                                {
2330                                        const int cf =
2331                                                Polygon3::ClassifyPlane(candidateGeom.mPolys,
2332                                                                                                halfSpaces[i],
2333                                                                                                mEpsilon);
2334
2335                                        if (cf == Polygon3::BACK_SIDE)
2336                                                isAdjacent = false;
2337                                }
2338
2339                                if (isAdjacent)
2340                                        neighbors.push_back(dynamic_cast<BspLeaf *>(node));
2341                        }
2342                }
2343                else
2344                {
2345                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2346       
2347                        const int cf = Polygon3::ClassifyPlane(geom.mPolys,
2348                                                                                                   interior->mPlane,
2349                                                                                                   mEpsilon);
2350
2351                        if (cf == Polygon3::FRONT_SIDE)
2352                                nodeStack.push(interior->GetFront());
2353                        else
2354                                if (cf == Polygon3::BACK_SIDE)
2355                                        nodeStack.push(interior->GetBack());
2356                                else
2357                                {
2358                                        // random decision
2359                                        nodeStack.push(interior->GetBack());
2360                                        nodeStack.push(interior->GetFront());
2361                                }
2362                }
2363        }
2364       
2365        return (int)neighbors.size();
2366}
2367
2368
2369BspLeaf *BspTree::GetRandomLeaf(const Plane3 &halfspace)
2370{
2371    stack<BspNode *> nodeStack;
2372        nodeStack.push(mRoot);
2373       
2374        int mask = rand();
2375 
2376        while (!nodeStack.empty())
2377        {
2378                BspNode *node = nodeStack.top();
2379                nodeStack.pop();
2380         
2381                if (node->IsLeaf())
2382                {
2383                        return dynamic_cast<BspLeaf *>(node);
2384                }
2385                else
2386                {
2387                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2388                        BspNode *next;
2389       
2390                        BspNodeGeometry geom;
2391                        // todo: not very efficient: constructs full cell everytime
2392                        ConstructGeometry(interior, geom);
2393
2394                        const int cf = Polygon3::ClassifyPlane(geom.mPolys,
2395                                                                                                   halfspace,
2396                                                                                                   mEpsilon);
2397
2398                        if (cf == Polygon3::BACK_SIDE)
2399                                next = interior->GetFront();
2400                        else
2401                                if (cf == Polygon3::FRONT_SIDE)
2402                                        next = interior->GetFront();
2403                        else
2404                        {
2405                                // random decision
2406                                if (mask & 1)
2407                                        next = interior->GetBack();
2408                                else
2409                                        next = interior->GetFront();
2410                                mask = mask >> 1;
2411                        }
2412
2413                        nodeStack.push(next);
2414                }
2415        }
2416       
2417        return NULL;
2418}
2419
2420BspLeaf *BspTree::GetRandomLeaf(const bool onlyUnmailed)
2421{
2422        stack<BspNode *> nodeStack;
2423       
2424        nodeStack.push(mRoot);
2425
2426        int mask = rand();
2427       
2428        while (!nodeStack.empty())
2429        {
2430                BspNode *node = nodeStack.top();
2431                nodeStack.pop();
2432               
2433                if (node->IsLeaf())
2434                {
2435                        if ( (!onlyUnmailed || !node->Mailed()) )
2436                                return dynamic_cast<BspLeaf *>(node);
2437                }
2438                else
2439                {
2440                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2441
2442                        // random decision
2443                        if (mask & 1)
2444                                nodeStack.push(interior->GetBack());
2445                        else
2446                                nodeStack.push(interior->GetFront());
2447
2448                        mask = mask >> 1;
2449                }
2450        }
2451       
2452        return NULL;
2453}
2454
2455void BspTree::AddToPvs(BspLeaf *leaf,
2456                                           const BoundedRayContainer &rays,
2457                                           int &sampleContributions,
2458                                           int &contributingSamples)
2459{
2460        sampleContributions = 0;
2461        contributingSamples = 0;
2462
2463    BoundedRayContainer::const_iterator it, it_end = rays.end();
2464
2465        ViewCell *vc = leaf->GetViewCell();
2466
2467        // add contributions from samples to the PVS
2468        for (it = rays.begin(); it != it_end; ++ it)
2469        {
2470                int contribution = 0;
2471                Ray *ray = (*it)->mRay;
2472                float relContribution;
2473                if (!ray->intersections.empty())
2474                  contribution += vc->GetPvs().AddSample(ray->intersections[0].mObject,
2475                                                                                                 1.0f,
2476                                                                                                 relContribution);
2477               
2478                if (ray->sourceObject.mObject)
2479                        contribution += vc->GetPvs().AddSample(ray->sourceObject.mObject,
2480                                                                                                   1.0f,
2481                                                                                                   relContribution);
2482               
2483                if (contribution)
2484                {
2485                        sampleContributions += contribution;
2486                        ++ contributingSamples;
2487                }
2488
2489                //if (ray->mFlags & Ray::STORE_BSP_INTERSECTIONS)
2490                //      ray->bspIntersections.push_back(Ray::BspIntersection((*it)->mMinT, this));
2491        }
2492}
2493
2494int BspTree::ComputePvsSize(const BoundedRayContainer &rays) const
2495{
2496        int pvsSize = 0;
2497
2498        BoundedRayContainer::const_iterator rit, rit_end = rays.end();
2499
2500        Intersectable::NewMail();
2501
2502        for (rit = rays.begin(); rit != rays.end(); ++ rit)
2503        {
2504                Ray *ray = (*rit)->mRay;
2505               
2506                if (!ray->intersections.empty())
2507                {
2508                        if (!ray->intersections[0].mObject->Mailed())
2509                        {
2510                                ray->intersections[0].mObject->Mail();
2511                                ++ pvsSize;
2512                        }
2513                }
2514                if (ray->sourceObject.mObject)
2515                {
2516                        if (!ray->sourceObject.mObject->Mailed())
2517                        {
2518                                ray->sourceObject.mObject->Mail();
2519                                ++ pvsSize;
2520                        }
2521                }
2522        }
2523
2524        return pvsSize;
2525}
2526
2527float BspTree::GetEpsilon() const
2528{
2529        return mEpsilon;
2530}
2531
2532
2533/*************************************************************/
2534/*            BspNodeGeometry Implementation                 */
2535/*************************************************************/
2536
2537
2538BspNodeGeometry::BspNodeGeometry(const BspNodeGeometry &rhs)
2539{
2540        PolygonContainer::const_iterator it, it_end = rhs.mPolys.end();
2541        for (it = rhs.mPolys.begin(); it != it_end; ++ it)
2542        {
2543                Polygon3 *poly = *it;
2544                mPolys.push_back(new Polygon3(*poly));
2545        }
2546}
2547
2548BspNodeGeometry::~BspNodeGeometry()
2549{
2550        CLEAR_CONTAINER(mPolys);
2551}
2552
2553
2554float BspNodeGeometry::GetArea() const
2555{
2556        return Polygon3::GetArea(mPolys);
2557}
2558
2559
2560float BspNodeGeometry::GetVolume() const
2561{
2562        //-- compute volume using tetrahedralization of the geometry
2563        //   and adding the volume of the single tetrahedrons
2564        float volume = 0;
2565        const float f = 1.0f / 6.0f;
2566
2567        PolygonContainer::const_iterator pit, pit_end = mPolys.end();
2568
2569        // note: can take arbitrary point, e.g., the origin. However,
2570        // center of mass prevents precision errors
2571        const Vector3 center = CenterOfMass();
2572
2573        for (pit = mPolys.begin(); pit != pit_end; ++ pit)
2574        {
2575                Polygon3 *poly = *pit;
2576                const Vector3 v0 = poly->mVertices[0] - center;
2577
2578                for (int i = 1; i < (int)poly->mVertices.size() - 1; ++ i)
2579                {
2580                        const Vector3 v1 = poly->mVertices[i] - center;
2581                        const Vector3 v2 = poly->mVertices[i + 1] - center;
2582
2583                        volume += f * (DotProd(v0, CrossProd(v1, v2)));
2584                }
2585        }
2586
2587        return volume;
2588}
2589
2590
2591Vector3 BspNodeGeometry::CenterOfMass() const
2592{
2593        int n = 0;
2594
2595        Vector3 center(0,0,0);
2596
2597        PolygonContainer::const_iterator pit, pit_end = mPolys.end();
2598
2599        for (pit = mPolys.begin(); pit != pit_end; ++ pit)
2600        {
2601                Polygon3 *poly = *pit;
2602               
2603                VertexContainer::const_iterator vit, vit_end = poly->mVertices.end();
2604
2605                for(vit = poly->mVertices.begin(); vit != vit_end; ++ vit)
2606                {
2607                        center += *vit;
2608                        ++ n;
2609                }
2610        }
2611
2612        return center / (float)n;
2613}
2614
2615
2616void BspNodeGeometry::AddToMesh(Mesh &mesh)
2617{
2618        PolygonContainer::const_iterator it, it_end = mPolys.end();
2619       
2620        for (it = mPolys.begin(); it != mPolys.end(); ++ it)
2621        {
2622                (*it)->AddToMesh(mesh);
2623        }
2624}
2625
2626
2627void BspNodeGeometry::SplitGeometry(BspNodeGeometry &front,
2628                                                                        BspNodeGeometry &back,
2629                                                                        const Plane3 &splitPlane,
2630                                                                        const AxisAlignedBox3 &box,
2631                                                                        const float epsilon) const
2632{       
2633        // get cross section of new polygon
2634        Polygon3 *planePoly = box.CrossSection(splitPlane);
2635
2636        // split polygon with all other polygons
2637        planePoly = SplitPolygon(planePoly, epsilon);
2638
2639        //-- new polygon splits all other polygons
2640        for (int i = 0; i < (int)mPolys.size(); ++ i)
2641        {
2642                /// don't use epsilon here to get exact split planes
2643                const int cf =
2644                        mPolys[i]->ClassifyPlane(splitPlane, Limits::Small);
2645                       
2646                switch (cf)
2647                {
2648                        case Polygon3::SPLIT:
2649                                {
2650                                        Polygon3 *poly = new Polygon3(mPolys[i]->mVertices);
2651
2652                                        Polygon3 *frontPoly = new Polygon3();
2653                                        Polygon3 *backPoly = new Polygon3();
2654                               
2655                                        poly->Split(splitPlane,
2656                                                                *frontPoly,
2657                                                                *backPoly,
2658                                                                epsilon);
2659
2660                                        DEL_PTR(poly);
2661
2662                                        if (frontPoly->Valid(epsilon))
2663                                                front.mPolys.push_back(frontPoly);
2664                                        else
2665                                                DEL_PTR(frontPoly);
2666
2667                                        if (backPoly->Valid(epsilon))
2668                                                back.mPolys.push_back(backPoly);
2669                                        else
2670                                                DEL_PTR(backPoly);
2671                                }
2672                               
2673                                break;
2674                        case Polygon3::BACK_SIDE:
2675                                back.mPolys.push_back(new Polygon3(mPolys[i]->mVertices));                     
2676                                break;
2677                        case Polygon3::FRONT_SIDE:
2678                                front.mPolys.push_back(new Polygon3(mPolys[i]->mVertices));     
2679                                break;
2680                        case Polygon3::COINCIDENT:
2681                                //front.mPolys.push_back(CreateReversePolygon(mPolys[i]));
2682                                back.mPolys.push_back(new Polygon3(mPolys[i]->mVertices));
2683                                break;
2684                        default:
2685                                break;
2686                }
2687        }
2688
2689        //-- finally add the new polygon to the child node geometries
2690        if (planePoly)
2691        {
2692                // add polygon with normal pointing into positive half space to back cell
2693                back.mPolys.push_back(planePoly);
2694                // add polygon with reverse orientation to front cell
2695                front.mPolys.push_back(planePoly->CreateReversePolygon());
2696        }
2697
2698        //Debug << "returning new geometry " << mPolys.size() << " f: " << front.mPolys.size() << " b: " << back.mPolys.size() << endl;
2699        //Debug << "old area " << GetArea() << " f: " << front.GetArea() << " b: " << back.GetArea() << endl;
2700}
2701
2702Polygon3 *BspNodeGeometry::SplitPolygon(Polygon3 *planePoly,
2703                                                                                const float epsilon) const
2704{
2705        if (!planePoly->Valid(epsilon))
2706                DEL_PTR(planePoly);
2707
2708        // polygon is split by all other planes
2709        for (int i = 0; (i < (int)mPolys.size()) && planePoly; ++ i)
2710        {
2711                Plane3 plane = mPolys[i]->GetSupportingPlane();
2712
2713                /// don't use epsilon here to get exact split planes
2714                const int cf =
2715                        planePoly->ClassifyPlane(plane, Limits::Small);
2716                       
2717                // split new polygon with all previous planes
2718                switch (cf)
2719                {
2720                        case Polygon3::SPLIT:
2721                                {
2722                                        Polygon3 *frontPoly = new Polygon3();
2723                                        Polygon3 *backPoly = new Polygon3();
2724
2725                                        planePoly->Split(plane,
2726                                                                         *frontPoly,
2727                                                                         *backPoly,
2728                                                                         epsilon);
2729                                       
2730                                        // don't need anymore
2731                                        DEL_PTR(planePoly);
2732                                        DEL_PTR(frontPoly);
2733
2734                                        // back polygon is belonging to geometry
2735                                        if (backPoly->Valid(epsilon))
2736                                                planePoly = backPoly;
2737                                        else
2738                                                DEL_PTR(backPoly);
2739                                }
2740                                break;
2741                        case Polygon3::FRONT_SIDE:
2742                                DEL_PTR(planePoly);
2743                break;
2744                        // polygon is taken as it is
2745                        case Polygon3::BACK_SIDE:
2746                        case Polygon3::COINCIDENT:
2747                        default:
2748                                break;
2749                }
2750        }
2751
2752        return planePoly;
2753}
2754
2755
2756ViewCell *
2757BspTree::GetViewCell(const Vector3 &point)
2758{
2759  if (mRoot == NULL)
2760        return NULL;
2761 
2762
2763  stack<BspNode *> nodeStack;
2764  nodeStack.push(mRoot);
2765 
2766  ViewCell *viewcell = NULL;
2767 
2768  while (!nodeStack.empty())  {
2769        BspNode *node = nodeStack.top();
2770        nodeStack.pop();
2771       
2772        if (node->IsLeaf()) {
2773          viewcell = dynamic_cast<BspLeaf *>(node)->mViewCell;
2774          break;
2775        } else {
2776         
2777          BspInterior *interior = dynamic_cast<BspInterior *>(node);
2778               
2779          // random decision
2780          if (interior->GetPlane().Side(point) < 0)
2781                nodeStack.push(interior->GetBack());
2782          else
2783                nodeStack.push(interior->GetFront());
2784        }
2785  }
2786 
2787  return viewcell;
2788}
2789
2790void BspNodeGeometry::IncludeInBox(AxisAlignedBox3 &box)
2791{
2792        Polygon3::IncludeInBox(mPolys, box);
2793}
Note: See TracBrowser for help on using the repository browser.