source: trunk/VUT/GtpVisibilityPreprocessor/src/VspBspTree.cpp @ 479

Revision 479, 51.4 KB checked in by mattausch, 19 years ago (diff)
Line 
1#include <stack>
2#include <time.h>
3#include <iomanip>
4
5#include "Plane3.h"
6#include "VspBspTree.h"
7#include "Mesh.h"
8#include "common.h"
9#include "ViewCell.h"
10#include "Environment.h"
11#include "Polygon3.h"
12#include "Ray.h"
13#include "AxisAlignedBox3.h"
14#include "Exporter.h"
15#include "Plane3.h"
16#include "ViewCellBsp.h"
17#include "ViewCellsManager.h"
18
19
20//-- static members
21/** Evaluates split plane classification with respect to the plane's
22        contribution for a minimum number of ray splits.
23*/
24const float VspBspTree::sLeastRaySplitsTable[] = {0, 0, 1, 1, 0};
25/** Evaluates split plane classification with respect to the plane's
26        contribution for balanced rays.
27*/
28const float VspBspTree::sBalancedRaysTable[] = {1, -1, 0, 0, 0};
29
30
31int VspBspTree::sFrontId = 0;
32int VspBspTree::sBackId = 0;
33int VspBspTree::sFrontAndBackId = 0;
34
35float BspMergeCandidate::sOverallCost = Limits::Small;
36
37/****************************************************************/
38/*                  class VspBspTree implementation             */
39/****************************************************************/
40
41VspBspTree::VspBspTree():
42mRoot(NULL),
43mPvsUseArea(true),
44mCostNormalizer(Limits::Small),
45mViewCellsManager(NULL),
46mStoreRays(true)
47{
48        mRootCell = new BspViewCell();
49
50        Randomize(); // initialise random generator for heuristics
51
52        //-- termination criteria for autopartition
53        environment->GetIntValue("VspBspTree.Termination.maxDepth", mTermMaxDepth);
54        environment->GetIntValue("VspBspTree.Termination.minPvs", mTermMinPvs);
55        environment->GetIntValue("VspBspTree.Termination.minRays", mTermMinRays);
56        environment->GetFloatValue("VspBspTree.Termination.minArea", mTermMinArea);     
57        environment->GetFloatValue("VspBspTree.Termination.maxRayContribution", mTermMaxRayContribution);
58        environment->GetFloatValue("VspBspTree.Termination.minAccRayLenght", mTermMinAccRayLength);
59        environment->GetFloatValue("VspBspTree.Termination.maxCostRatio", mTermMaxCostRatio);
60        environment->GetIntValue("VspBspTree.Termination.missTolerance", mTermMissTolerance);
61
62        //-- factors for bsp tree split plane heuristics
63        environment->GetFloatValue("VspBspTree.Factor.balancedRays", mBalancedRaysFactor);
64        environment->GetFloatValue("VspBspTree.Factor.pvs", mPvsFactor);
65        environment->GetFloatValue("VspBspTree.Termination.ct_div_ci", mCtDivCi);
66
67        //-- termination criteria for axis aligned split
68        environment->GetFloatValue("VspBspTree.Termination.AxisAligned.ct_div_ci", mAxisAlignedCtDivCi);
69        environment->GetFloatValue("VspBspTree.Termination.maxCostRatio", mTermMaxCostRatio);
70       
71        environment->GetIntValue("VspBspTree.Termination.AxisAligned.minRays",
72                                                         mTermMinRaysForAxisAligned);
73       
74        //-- partition criteria
75        environment->GetIntValue("VspBspTree.maxPolyCandidates", mMaxPolyCandidates);
76        environment->GetIntValue("VspBspTree.maxRayCandidates", mMaxRayCandidates);
77        environment->GetIntValue("VspBspTree.splitPlaneStrategy", mSplitPlaneStrategy);
78        environment->GetFloatValue("VspBspTree.AxisAligned.splitBorder", mAxisAlignedSplitBorder);
79
80        environment->GetFloatValue("VspBspTree.Construction.epsilon", mEpsilon);
81        environment->GetIntValue("VspBspTree.maxTests", mMaxTests);
82
83        // maximum and minimum number of view cells
84        environment->GetIntValue("VspBspTree.Termination.maxViewCells", mMaxViewCells);
85        environment->GetIntValue("VspBspTree.PostProcess.minViewCells", mMergeMinViewCells);
86        environment->GetIntValue("VspBspTree.PostProcess.maxCostRatio", mMergeMaxCostRatio);
87
88
89        //-- debug output
90        Debug << "******* VSP BSP options ******** " << endl;
91    Debug << "max depth: " << mTermMaxDepth << endl;
92        Debug << "min PVS: " << mTermMinPvs << endl;
93        Debug << "min area: " << mTermMinArea << endl;
94        Debug << "min rays: " << mTermMinRays << endl;
95        Debug << "max ray contri: " << mTermMaxRayContribution << endl;
96        //Debug << "VSP BSP mininam accumulated ray lenght: ", mTermMinAccRayLength) << endl;
97        Debug << "max cost ratio: " << mTermMaxCostRatio << endl;
98        Debug << "miss tolerance: " << mTermMissTolerance << endl;
99        Debug << "max view cells: " << mMaxViewCells << endl;
100        Debug << "max polygon candidates: " << mMaxPolyCandidates << endl;
101        Debug << "max plane candidates: " << mMaxRayCandidates << endl;
102       
103        Debug << "Split plane strategy: ";
104        if (mSplitPlaneStrategy & RANDOM_POLYGON)
105        {
106                Debug << "random polygon ";
107        }
108        if (mSplitPlaneStrategy & AXIS_ALIGNED)
109        {
110                Debug << "axis aligned ";
111        }
112        if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)
113        {
114                mCostNormalizer += mLeastRaySplitsFactor;
115                Debug << "least ray splits ";
116        }
117        if (mSplitPlaneStrategy & BALANCED_RAYS)
118        {
119                mCostNormalizer += mBalancedRaysFactor;
120                Debug << "balanced rays ";
121        }
122        if (mSplitPlaneStrategy & PVS)
123        {
124                mCostNormalizer += mPvsFactor;
125                Debug << "pvs";
126        }
127
128        Debug << endl;
129}
130
131
132const BspTreeStatistics &VspBspTree::GetStatistics() const
133{
134        return mStat;
135}
136
137
138VspBspTree::~VspBspTree()
139{
140        DEL_PTR(mRoot);
141        DEL_PTR(mRootCell);
142}
143
144int VspBspTree::AddMeshToPolygons(Mesh *mesh,
145                                                                  PolygonContainer &polys,
146                                                                  MeshInstance *parent)
147{
148        FaceContainer::const_iterator fi;
149       
150        // copy the face data to polygons
151        for (fi = mesh->mFaces.begin(); fi != mesh->mFaces.end(); ++ fi)
152        {
153                Polygon3 *poly = new Polygon3((*fi), mesh);
154               
155                if (poly->Valid(mEpsilon))
156                {
157                        poly->mParent = parent; // set parent intersectable
158                        polys.push_back(poly);
159                }
160                else
161                        DEL_PTR(poly);
162        }
163        return (int)mesh->mFaces.size();
164}
165
166int VspBspTree::AddToPolygonSoup(const ViewCellContainer &viewCells,
167                                                          PolygonContainer &polys,
168                                                          int maxObjects)
169{
170        int limit = (maxObjects > 0) ?
171                Min((int)viewCells.size(), maxObjects) : (int)viewCells.size();
172 
173        int polysSize = 0;
174
175        for (int i = 0; i < limit; ++ i)
176        {
177                if (viewCells[i]->GetMesh()) // copy the mesh data to polygons
178                {
179                        mBox.Include(viewCells[i]->GetBox()); // add to BSP tree aabb
180                        polysSize +=
181                                AddMeshToPolygons(viewCells[i]->GetMesh(),
182                                                                  polys,
183                                                                  viewCells[i]);
184                }
185        }
186
187        return polysSize;
188}
189
190int VspBspTree::AddToPolygonSoup(const ObjectContainer &objects,
191                                                                 PolygonContainer &polys,
192                                                                 int maxObjects)
193{
194        int limit = (maxObjects > 0) ?
195                Min((int)objects.size(), maxObjects) : (int)objects.size();
196 
197        for (int i = 0; i < limit; ++i)
198        {
199                Intersectable *object = objects[i];//*it;
200                Mesh *mesh = NULL;
201
202                switch (object->Type()) // extract the meshes
203                {
204                case Intersectable::MESH_INSTANCE:
205                        mesh = dynamic_cast<MeshInstance *>(object)->GetMesh();
206                        break;
207                case Intersectable::VIEW_CELL:
208                        mesh = dynamic_cast<ViewCell *>(object)->GetMesh();
209                        break;
210                        // TODO: handle transformed mesh instances
211                default:
212                        Debug << "intersectable type not supported" << endl;
213                        break;
214                }
215               
216        if (mesh) // copy the mesh data to polygons
217                {
218                        mBox.Include(object->GetBox()); // add to BSP tree aabb
219                        AddMeshToPolygons(mesh, polys, mRootCell);
220                }
221        }
222
223        return (int)polys.size();
224}
225
226void VspBspTree::Construct(const VssRayContainer &sampleRays)
227{
228    mStat.nodes = 1;
229        mBox.Initialize();      // initialise BSP tree bounding box
230       
231        PolygonContainer polys;
232        RayInfoContainer *rays = new RayInfoContainer();
233
234        VssRayContainer::const_iterator rit, rit_end = sampleRays.end();
235
236        long startTime = GetTime();
237
238        cout << "Extracting polygons from rays ...";
239
240        Intersectable::NewMail();
241
242        //-- extract polygons intersected by the rays
243        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
244        {
245                VssRay *ray = *rit;
246       
247                if (ray->mTerminationObject && !ray->mTerminationObject->Mailed())
248                {
249                        ray->mTerminationObject->Mail();
250                        MeshInstance *obj = dynamic_cast<MeshInstance *>(ray->mTerminationObject);
251                        AddMeshToPolygons(obj->GetMesh(), polys, obj);
252                }
253
254                if (ray->mOriginObject && !ray->mOriginObject->Mailed())
255                {
256                        ray->mOriginObject->Mail();
257                        MeshInstance *obj = dynamic_cast<MeshInstance *>(ray->mOriginObject);
258                        AddMeshToPolygons(obj->GetMesh(), polys, obj);
259                }
260        }
261
262        // compute bounding box
263        Polygon3::IncludeInBox(polys, mBox);
264
265        //-- store rays
266        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
267        {
268                VssRay *ray = *rit;
269               
270                float minT, maxT;
271
272                // TODO: not very efficient to implictly cast between rays types ...
273                if (mBox.GetRaySegment(*ray, minT, maxT))
274                {
275                        float len = ray->Length();
276                       
277                        if (!len)
278                                len = Limits::Small;
279                       
280                        rays->push_back(RayInfo(ray, minT / len, maxT / len));
281                }
282        }
283
284        mTermMinArea *= mBox.SurfaceArea(); // normalize
285        mStat.polys = (int)polys.size();
286
287        cout << "finished" << endl;
288
289        Debug << "\nPolygon extraction: " << (int)polys.size() << " polys extracted from "
290                  << (int)sampleRays.size() << " rays in "
291                  << TimeDiff(startTime, GetTime())*1e-3 << " secs" << endl << endl;
292
293        Construct(polys, rays);
294
295        // clean up polygons
296        CLEAR_CONTAINER(polys);
297}
298
299void VspBspTree::Construct(const PolygonContainer &polys, RayInfoContainer *rays)
300{
301        VspBspTraversalStack tStack;
302
303        mRoot = new BspLeaf();
304
305        // constrruct root node geometry
306        BspNodeGeometry *geom = new BspNodeGeometry();
307        ConstructGeometry(mRoot, *geom);
308
309        VspBspTraversalData tData(mRoot,
310                                                          new PolygonContainer(polys),
311                                                          0,
312                                                          rays,
313                              ComputePvsSize(*rays),
314                                                          geom->GetArea(),
315                                                          geom);
316
317        tStack.push(tData);
318
319        mStat.Start();
320        cout << "Contructing vsp bsp tree ... ";
321
322        long startTime = GetTime();
323       
324        while (!tStack.empty())
325        {
326                tData = tStack.top();
327
328            tStack.pop();
329
330                // subdivide leaf node
331                BspNode *r = Subdivide(tStack, tData);
332
333                if (r == mRoot)
334                        Debug << "VSP BSP tree construction time spent at root: "
335                                  << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl << endl;
336        }
337
338        cout << "finished\n";
339
340        mStat.Stop();
341}
342
343bool VspBspTree::TerminationCriteriaMet(const VspBspTraversalData &data) const
344{
345        return
346                (((int)data.mRays->size() <= mTermMinRays) ||
347                 (data.mPvs <= mTermMinPvs)   ||
348                 (data.mArea <= mTermMinArea) ||
349                 (mStat.nodes / 2 + 1 >= mMaxViewCells) ||
350                // (data.GetAvgRayContribution() >= mTermMaxRayContribution) ||
351                 (data.mDepth >= mTermMaxDepth));
352}
353
354BspNode *VspBspTree::Subdivide(VspBspTraversalStack &tStack,
355                                                           VspBspTraversalData &tData)
356{
357        BspNode *newNode = tData.mNode;
358
359        if (!TerminationCriteriaMet(tData))
360        {
361                PolygonContainer coincident;
362       
363                VspBspTraversalData tFrontData;
364                VspBspTraversalData tBackData;
365
366                // create new interior node and two leaf nodes
367                // or return leaf as it is (if maxCostRatio missed)
368                newNode = SubdivideNode(tData, tFrontData, tBackData, coincident);
369
370                if (!newNode->IsLeaf()) //-- continue subdivision
371                {
372                        // push the children on the stack
373                        tStack.push(tFrontData);
374                        tStack.push(tBackData);
375
376                        // delete old leaf node
377                        DEL_PTR(tData.mNode);   
378                }
379        }
380       
381        //-- terminate traversal and create new view cell
382        if (newNode->IsLeaf())
383        {
384                BspLeaf *leaf = dynamic_cast<BspLeaf *>(newNode);
385       
386                // create new view cell for this leaf
387                BspViewCell *viewCell = new BspViewCell();
388                leaf->SetViewCell(viewCell);
389               
390                if (mStoreRays)
391                {
392                        RayInfoContainer::const_iterator it, it_end = tData.mRays->end();
393                        for (it = tData.mRays->begin(); it != it_end; ++ it)
394                                leaf->mVssRays.push_back((*it).mRay);
395                }
396
397                viewCell->mLeaves.push_back(leaf);
398                viewCell->SetArea(tData.mArea);
399
400                //-- update pvs
401                int conSamp = 0, sampCon = 0;
402                AddToPvs(leaf, *tData.mRays, conSamp, sampCon);
403                       
404                mStat.contributingSamples += conSamp;
405                mStat.sampleContributions += sampCon;
406               
407                EvaluateLeafStats(tData);
408        }
409       
410               
411        //-- cleanup
412        tData.Clear();
413
414        return newNode;
415}
416
417BspNode *VspBspTree::SubdivideNode(VspBspTraversalData &tData,
418                                                                   VspBspTraversalData &frontData,
419                                                                   VspBspTraversalData &backData,
420                                                                   PolygonContainer &coincident)
421{
422        BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
423
424        int maxCostMisses = tData.mMaxCostMisses;
425
426        // select subdivision plane
427        Plane3 splitPlane;
428        if (!SelectPlane(splitPlane, leaf, tData))
429        {
430                ++ maxCostMisses;
431
432                if (maxCostMisses >= mTermMissTolerance)
433                {
434                        // terminate branch because of max cost
435                        ++ mStat.maxCostNodes;
436            return leaf;
437                }
438        }
439
440        mStat.nodes += 2;
441
442        //-- subdivide further
443        BspInterior *interior = new BspInterior(splitPlane);
444
445#ifdef _DEBUG
446        Debug << interior << endl;
447#endif
448       
449        //-- the front and back traversal data is filled with the new values
450        frontData.mPolygons = new PolygonContainer();
451        frontData.mDepth = tData.mDepth + 1;
452        frontData.mRays = new RayInfoContainer();
453        frontData.mGeometry = new BspNodeGeometry();
454
455        backData.mPolygons = new PolygonContainer();
456        backData.mDepth = tData.mDepth + 1;
457        backData.mRays = new RayInfoContainer();
458        backData.mGeometry = new BspNodeGeometry();
459
460        // subdivide rays
461        SplitRays(interior->GetPlane(),
462                          *tData.mRays,
463                          *frontData.mRays,
464                          *backData.mRays);
465       
466        // subdivide polygons
467        mStat.splits += SplitPolygons(interior->GetPlane(),
468                                                                  *tData.mPolygons,
469                                          *frontData.mPolygons,
470                                                                  *backData.mPolygons,
471                                                                  coincident);
472
473       
474        // how often was max cost ratio missed in this branch?
475        frontData.mMaxCostMisses = maxCostMisses;
476        backData.mMaxCostMisses = maxCostMisses;
477
478        // compute pvs
479        frontData.mPvs = ComputePvsSize(*frontData.mRays);
480        backData.mPvs = ComputePvsSize(*backData.mRays);
481
482        // split geometry and compute area
483        if (1)
484        {
485                tData.mGeometry->SplitGeometry(*frontData.mGeometry,
486                                                                           *backData.mGeometry,
487                                                                           interior->GetPlane(),
488                                                                           mBox,
489                                                                           mEpsilon);
490       
491                frontData.mArea = frontData.mGeometry->GetArea();
492                backData.mArea = backData.mGeometry->GetArea();
493        }
494
495        // compute accumulated ray length
496        //frontData.mAccRayLength = AccumulatedRayLength(*frontData.mRays);
497        //backData.mAccRayLength = AccumulatedRayLength(*backData.mRays);
498
499        //-- create front and back leaf
500
501        BspInterior *parent = leaf->GetParent();
502
503        // replace a link from node's parent
504        if (!leaf->IsRoot())
505        {
506                parent->ReplaceChildLink(leaf, interior);
507                interior->SetParent(parent);
508        }
509        else // new root
510        {
511                mRoot = interior;
512        }
513
514        // and setup child links
515        interior->SetupChildLinks(new BspLeaf(interior), new BspLeaf(interior));
516       
517        frontData.mNode = interior->GetFront();
518        backData.mNode = interior->GetBack();
519
520        //DEL_PTR(leaf);
521        return interior;
522}
523
524void VspBspTree::AddToPvs(BspLeaf *leaf,
525                                                  const RayInfoContainer &rays,
526                                                  int &sampleContributions,
527                                                  int &contributingSamples)
528{
529        sampleContributions = 0;
530        contributingSamples = 0;
531
532    RayInfoContainer::const_iterator it, it_end = rays.end();
533
534        ViewCell *vc = leaf->GetViewCell();
535
536        // add contributions from samples to the PVS
537        for (it = rays.begin(); it != it_end; ++ it)
538        {
539                int contribution = 0;
540                VssRay *ray = (*it).mRay;
541                       
542                if (ray->mTerminationObject)
543                        contribution += vc->GetPvs().AddSample(ray->mTerminationObject);
544               
545                if (ray->mOriginObject)
546                        contribution += vc->GetPvs().AddSample(ray->mOriginObject);
547
548                if (contribution)
549                {
550                        sampleContributions += contribution;
551                        ++ contributingSamples;
552                }
553                //leaf->mVssRays.push_back(ray);
554        }
555}
556
557void VspBspTree::SortSplitCandidates(const PolygonContainer &polys,
558                                                                         const int axis,
559                                                                         vector<SortableEntry> &splitCandidates) const
560{
561        splitCandidates.clear();
562 
563        const int requestedSize = 2 * (int)polys.size();
564       
565        // creates a sorted split candidates array 
566        splitCandidates.reserve(requestedSize);
567 
568        PolygonContainer::const_iterator it, it_end = polys.end();
569
570        AxisAlignedBox3 box;
571
572        // insert all queries
573        for(it = polys.begin(); it != it_end; ++ it)
574        {
575                box.Initialize();
576                box.Include(*(*it));
577         
578                splitCandidates.push_back(SortableEntry(SortableEntry::POLY_MIN, box.Min(axis), *it));
579                splitCandidates.push_back(SortableEntry(SortableEntry::POLY_MAX, box.Max(axis), *it));
580        }
581 
582        stable_sort(splitCandidates.begin(), splitCandidates.end());
583}
584
585
586float VspBspTree::BestCostRatio(const PolygonContainer &polys,
587                                                                const AxisAlignedBox3 &box,
588                                                                const int axis,
589                                                                float &position,
590                                                                int &objectsBack,
591                                int &objectsFront) const
592{
593        vector<SortableEntry> splitCandidates;
594
595        SortSplitCandidates(polys, axis, splitCandidates);
596       
597        // go through the lists, count the number of objects left and right
598        // and evaluate the following cost funcion:
599        // C = ct_div_ci  + (ol + or)/queries
600       
601        int objectsLeft = 0, objectsRight = (int)polys.size();
602       
603        float minBox = box.Min(axis);
604        float maxBox = box.Max(axis);
605        float boxArea = box.SurfaceArea();
606 
607        float minBand = minBox + mAxisAlignedSplitBorder * (maxBox - minBox);
608        float maxBand = minBox + (1.0f - mAxisAlignedSplitBorder) * (maxBox - minBox);
609       
610        float minSum = 1e20f;
611        vector<SortableEntry>::const_iterator ci, ci_end = splitCandidates.end();
612
613        for(ci = splitCandidates.begin(); ci != ci_end; ++ ci)
614        {
615                switch ((*ci).type)
616                {
617                        case SortableEntry::POLY_MIN:
618                                ++ objectsLeft;
619                                break;
620                        case SortableEntry::POLY_MAX:
621                            -- objectsRight;
622                                break;
623                        default:
624                                break;
625                }
626               
627                if ((*ci).value > minBand && (*ci).value < maxBand)
628                {
629                        AxisAlignedBox3 lbox = box;
630                        AxisAlignedBox3 rbox = box;
631                        lbox.SetMax(axis, (*ci).value);
632                        rbox.SetMin(axis, (*ci).value);
633
634                        float sum = objectsLeft * lbox.SurfaceArea() +
635                                                objectsRight * rbox.SurfaceArea();
636     
637                        if (sum < minSum)
638                        {
639                                minSum = sum;
640                                position = (*ci).value;
641
642                                objectsBack = objectsLeft;
643                                objectsFront = objectsRight;
644                        }
645                }
646        }
647 
648        const float oldCost = (float)polys.size();
649        const float newCost = mAxisAlignedCtDivCi + minSum / boxArea;
650        const float ratio = newCost / oldCost;
651
652
653#if 0
654  Debug << "====================" << endl;
655  Debug << "costRatio=" << ratio << " pos=" << position<<" t=" << (position - minBox)/(maxBox - minBox)
656      << "\t o=(" << objectsBack << "," << objectsFront << ")" << endl;
657#endif
658  return ratio;
659}
660
661bool VspBspTree::SelectAxisAlignedPlane(Plane3 &plane,
662                                        const PolygonContainer &polys) const
663{
664        AxisAlignedBox3 box;
665        box.Initialize();
666       
667        // create bounding box of region
668        Polygon3::IncludeInBox(polys, box);
669       
670        int objectsBack = 0, objectsFront = 0;
671        int axis = 0;
672        float costRatio = MAX_FLOAT;
673        Vector3 position;
674
675        //-- area subdivision
676        for (int i = 0; i < 3; ++ i)
677        {
678                float p = 0;
679                const float r = BestCostRatio(polys, box, i, p, objectsBack, objectsFront);
680               
681                if (r < costRatio)
682                {
683                        costRatio = r;
684                        axis = i;
685                        position = p;
686                }
687        }
688       
689        if (costRatio >= mTermMaxCostRatio)
690                return false;
691
692        Vector3 norm(0,0,0); norm[axis] = 1.0f;
693        plane = Plane3(norm, position);
694
695        return true;
696}
697
698bool VspBspTree::SelectPlane(Plane3 &plane,
699                                                         BspLeaf *leaf,
700                                                         VspBspTraversalData &data)
701{
702        if ((mSplitPlaneStrategy & AXIS_ALIGNED) &&
703                ((int)data.mRays->size() > mTermMinRaysForAxisAligned))
704        {       // TODO: candidates should be rays
705                return SelectAxisAlignedPlane(plane, *data.mPolygons);
706        }
707
708        // simplest strategy: just take next polygon
709        if (mSplitPlaneStrategy & RANDOM_POLYGON)
710        {
711        if (!data.mPolygons->empty())
712                {
713                        const int randIdx = (int)RandomValue(0, (Real)((int)data.mPolygons->size() - 1));
714                        Polygon3 *nextPoly = (*data.mPolygons)[randIdx];
715
716                        plane = nextPoly->GetSupportingPlane();
717                        return true;
718                }
719                else
720                {
721                        //-- choose plane on midpoint of a ray
722                        const int candidateIdx = (int)RandomValue(0, (Real)((int)data.mRays->size() - 1));
723                                                                       
724                        const Vector3 minPt = (*data.mRays)[candidateIdx].ExtrapOrigin();
725                        const Vector3 maxPt = (*data.mRays)[candidateIdx].ExtrapTermination();
726
727                        const Vector3 pt = (maxPt + minPt) * 0.5;
728
729                        const Vector3 normal = (*data.mRays)[candidateIdx].mRay->GetDir();
730                       
731                        plane = Plane3(normal, pt);
732                        return true;
733                }
734
735                return false;
736        }
737
738        // use heuristics to find appropriate plane
739        return SelectPlaneHeuristics(plane, leaf, data);
740}
741
742Plane3 VspBspTree::ChooseCandidatePlane(const RayInfoContainer &rays) const
743{       
744        const int candidateIdx = (int)RandomValue(0, (Real)((int)rays.size() - 1));
745       
746        const Vector3 minPt = rays[candidateIdx].ExtrapOrigin();
747        const Vector3 maxPt = rays[candidateIdx].ExtrapTermination();
748
749        const Vector3 pt = (maxPt + minPt) * 0.5;
750        const Vector3 normal = Normalize(rays[candidateIdx].mRay->GetDir());
751
752        return Plane3(normal, pt);
753}
754
755Plane3 VspBspTree::ChooseCandidatePlane2(const RayInfoContainer &rays) const
756{       
757        Vector3 pt[3];
758       
759        int idx[3];
760        int cmaxT = 0;
761        int cminT = 0;
762        bool chooseMin = false;
763
764        for (int j = 0; j < 3; ++ j)
765        {
766                idx[j] = (int)RandomValue(0, (Real)((int)rays.size() * 2 - 1));
767                       
768                if (idx[j] >= (int)rays.size())
769                {
770                        idx[j] -= (int)rays.size();
771                               
772                        chooseMin = (cminT < 2);
773                }
774                else
775                        chooseMin = (cmaxT < 2);
776
777                RayInfo rayInf = rays[idx[j]];
778                pt[j] = chooseMin ? rayInf.ExtrapOrigin() : rayInf.ExtrapTermination();
779        }       
780
781        return Plane3(pt[0], pt[1], pt[2]);
782}
783
784Plane3 VspBspTree::ChooseCandidatePlane3(const RayInfoContainer &rays) const
785{       
786        Vector3 pt[3];
787       
788        int idx1 = (int)RandomValue(0, (Real)((int)rays.size() - 1));
789        int idx2 = (int)RandomValue(0, (Real)((int)rays.size() - 1));
790
791        // check if rays different
792        if (idx1 == idx2)
793                idx2 = (idx2 + 1) % (int)rays.size();
794
795        const RayInfo ray1 = rays[idx1];
796        const RayInfo ray2 = rays[idx2];
797
798        // normal vector of the plane parallel to both lines
799        const Vector3 norm = Normalize(CrossProd(ray1.mRay->GetDir(), ray2.mRay->GetDir()));
800
801        // vector from line 1 to line 2
802        const Vector3 vd = ray2.ExtrapOrigin() - ray1.ExtrapOrigin();
803       
804        // project vector on normal to get distance
805        const float dist = DotProd(vd, norm);
806
807        // point on plane lies halfway between the two planes
808        const Vector3 planePt = ray1.ExtrapOrigin() + norm * dist * 0.5;
809
810        return Plane3(norm, planePt);
811}
812
813bool VspBspTree::SelectPlaneHeuristics(Plane3 &bestPlane,
814                                                                           BspLeaf *leaf,
815                                                                           VspBspTraversalData &data)
816{
817        float lowestCost = MAX_FLOAT;
818        // intermediate plane
819        Plane3 plane;
820
821        const int limit = Min((int)data.mPolygons->size(), mMaxPolyCandidates);
822        int maxIdx = (int)data.mPolygons->size();
823       
824        for (int i = 0; i < limit; ++ i)
825        {
826                // assure that no index is taken twice
827                const int candidateIdx = (int)RandomValue(0, (Real)(-- maxIdx));
828                //Debug << "current Idx: " << maxIdx << " cand idx " << candidateIdx << endl;
829               
830                Polygon3 *poly = (*data.mPolygons)[candidateIdx];
831
832                // swap candidate to the end to avoid testing same plane
833                std::swap((*data.mPolygons)[maxIdx], (*data.mPolygons)[candidateIdx]);
834       
835                //Polygon3 *poly = (*data.mPolygons)[(int)RandomValue(0, (int)polys.size() - 1)];
836
837                // evaluate current candidate
838                const float candidateCost =
839                        SplitPlaneCost(poly->GetSupportingPlane(), data);
840
841                if (candidateCost < lowestCost)
842                {
843                        bestPlane = poly->GetSupportingPlane();
844                        lowestCost = candidateCost;
845                }
846        }
847       
848        //-- choose candidate planes extracted from rays
849        //-- different methods are available
850        for (int i = 0; i < mMaxRayCandidates; ++ i)
851        {
852                plane = ChooseCandidatePlane3(*data.mRays);
853                const float candidateCost = SplitPlaneCost(plane, data);
854
855                if (candidateCost < lowestCost)
856                {
857                        bestPlane = plane;     
858                        lowestCost = candidateCost;
859                }
860        }
861
862#ifdef _DEBUG
863        Debug << "plane lowest cost: " << lowestCost << endl;
864#endif
865
866        // cost ratio miss
867        if (lowestCost > mTermMaxCostRatio)
868                return false;
869
870        return true;
871}
872
873
874inline void VspBspTree::GenerateUniqueIdsForPvs()
875{
876        Intersectable::NewMail(); sBackId = ViewCell::sMailId;
877        Intersectable::NewMail(); sFrontId = ViewCell::sMailId;
878        Intersectable::NewMail(); sFrontAndBackId = ViewCell::sMailId;
879}
880
881float VspBspTree::SplitPlaneCost(const Plane3 &candidatePlane,
882                                                                 const VspBspTraversalData &data)
883{
884        float cost = 0;
885
886        float sumBalancedRays = 0;
887        float sumRaySplits = 0;
888       
889        int frontPvs = 0;
890        int backPvs = 0;
891
892        // probability that view point lies in child
893        float pOverall = 0;
894        float pFront = 0;
895        float pBack = 0;
896
897        const bool pvsUseLen = false;
898
899        if (mSplitPlaneStrategy & PVS)
900        {
901                // create unique ids for pvs heuristics
902                GenerateUniqueIdsForPvs();
903       
904                if (mPvsUseArea) // use front and back cell areas to approximate volume
905                {       
906                        // construct child geometry with regard to the candidate split plane
907                        BspNodeGeometry frontCell;
908                        BspNodeGeometry backCell;
909               
910                        data.mGeometry->SplitGeometry(frontCell,
911                                                                                  backCell,
912                                                                                  candidatePlane,
913                                                                                  mBox,
914                                                                                  mEpsilon);
915               
916                        pFront = frontCell.GetArea();
917                        pBack = backCell.GetArea();
918
919                        pOverall = data.mArea;
920                }
921        }
922               
923        int limit;
924        bool useRand;
925
926        // choose test polyongs randomly if over threshold
927        if ((int)data.mRays->size() > mMaxTests)
928        {
929                useRand = true;
930                limit = mMaxTests;
931        }
932        else
933        {
934                useRand = false;
935                limit = (int)data.mRays->size();
936        }
937
938        for (int i = 0; i < limit; ++ i)
939        {
940                const int testIdx = useRand ? (int)RandomValue(0, (Real)(limit - 1)) : i;
941                RayInfo rayInf = (*data.mRays)[testIdx];
942
943                VssRay *ray = rayInf.mRay;
944                float t;
945                const int cf = rayInf.ComputeRayIntersection(candidatePlane, t);
946
947                if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)
948                {
949                        sumBalancedRays += cf;
950                }
951               
952                if (mSplitPlaneStrategy & BALANCED_RAYS)
953                {
954                        if (cf == 0)
955                                ++ sumRaySplits;
956                }
957
958                if (mSplitPlaneStrategy & PVS)
959                {
960                        // in case the ray intersects an object
961                        // assure that we only count the object
962                        // once for the front and once for the back side of the plane
963                       
964                        // add the termination object
965                        AddObjToPvs(ray->mTerminationObject, cf, frontPvs, backPvs);
966                       
967                        // add the source object
968                        AddObjToPvs(ray->mOriginObject, cf, frontPvs, backPvs);
969                       
970                        // use number or length of rays to approximate volume
971                        if (!mPvsUseArea)
972                        {
973                                float len = 1;
974
975                                if (pvsUseLen) // use length of rays
976                                        len = rayInf.SqrSegmentLength();
977                       
978                                pOverall += len;
979
980                                if (cf == 1)
981                                        pFront += len;
982                                if (cf == -1)
983                                        pBack += len;
984                                if (cf == 0)
985                                {
986                                        // use length of rays to approximate volume
987                                        if (pvsUseLen)
988                                        {
989                                                float newLen = len *
990                                                        (rayInf.GetMaxT() - t) /
991                                                        (rayInf.GetMaxT() - rayInf.GetMinT());
992               
993                                                if (candidatePlane.Side(rayInf.ExtrapOrigin()) <= 0)
994                                                {
995                                                        pBack += newLen;
996                                                        pFront += len - newLen;
997                                                }
998                                                else
999                                                {
1000                                                        pFront += newLen;
1001                                                        pBack += len - newLen;
1002                                                }
1003                                        }
1004                                        else
1005                                        {
1006                                                ++ pFront;
1007                                                ++ pBack;
1008                                        }
1009                                }
1010                        }
1011                }
1012        }
1013
1014        const float raysSize = (float)data.mRays->size() + Limits::Small;
1015       
1016        if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)
1017                cost += mLeastRaySplitsFactor * sumRaySplits / raysSize;
1018
1019        if (mSplitPlaneStrategy & BALANCED_RAYS)
1020                cost += mBalancedRaysFactor * fabs(sumBalancedRays) /  raysSize;
1021       
1022        // pvs criterium
1023        if (mSplitPlaneStrategy & PVS)
1024        {
1025                const float oldCost = pOverall * (float)data.mPvs + Limits::Small;
1026                cost += mPvsFactor * (frontPvs * pFront + backPvs * pBack) / oldCost;
1027
1028                //cost += mPvsFactor * 0.5 * (frontPvs * pFront + backPvs * pBack) / oldCost;
1029                //Debug << "new cost: " << cost << " over" << frontPvs * pFront + backPvs * pBack << " old cost " << oldCost << endl;
1030       
1031                if (0) // give penalty to unbalanced split
1032                        if (((pFront * 0.2 + Limits::Small) > pBack) ||
1033                                (pFront < (pBack * 0.2 + Limits::Small)))
1034                                        cost += 0.5;
1035        }
1036
1037#ifdef _DEBUG
1038        Debug << "totalpvs: " << data.mPvs << " ptotal: " << pOverall
1039                  << " frontpvs: " << frontPvs << " pFront: " << pFront
1040                  << " backpvs: " << backPvs << " pBack: " << pBack << endl << endl;
1041#endif
1042       
1043        // normalize cost by sum of linear factors
1044        return cost / (float)mCostNormalizer;
1045}
1046
1047void VspBspTree::AddObjToPvs(Intersectable *obj,
1048                                                         const int cf,
1049                                                         int &frontPvs,
1050                                                         int &backPvs) const
1051{
1052        if (!obj)
1053                return;
1054        // TODO: does this really belong to no pvs?
1055        //if (cf == Ray::COINCIDENT) return;
1056
1057        // object belongs to both PVS
1058        if (cf >= 0)
1059        {
1060                if ((obj->mMailbox != sFrontId) &&
1061                        (obj->mMailbox != sFrontAndBackId))
1062                {
1063                        ++ frontPvs;
1064
1065                        if (obj->mMailbox == sBackId)
1066                                obj->mMailbox = sFrontAndBackId;       
1067                        else
1068                                obj->mMailbox = sFrontId;                                                               
1069                }
1070        }
1071       
1072        if (cf <= 0)
1073        {
1074                if ((obj->mMailbox != sBackId) &&
1075                        (obj->mMailbox != sFrontAndBackId))
1076                {
1077                        ++ backPvs;
1078
1079                        if (obj->mMailbox == sFrontId)
1080                                obj->mMailbox = sFrontAndBackId;
1081                        else
1082                                obj->mMailbox = sBackId;                               
1083                }
1084        }
1085}
1086
1087void VspBspTree::CollectLeaves(vector<BspLeaf *> &leaves) const
1088{
1089        stack<BspNode *> nodeStack;
1090        nodeStack.push(mRoot);
1091 
1092        while (!nodeStack.empty())
1093        {
1094                BspNode *node = nodeStack.top();
1095   
1096                nodeStack.pop();
1097   
1098                if (node->IsLeaf())
1099                {
1100                        BspLeaf *leaf = (BspLeaf *)node;               
1101                        leaves.push_back(leaf);
1102                }
1103                else
1104                {
1105                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1106
1107                        nodeStack.push(interior->GetBack());
1108                        nodeStack.push(interior->GetFront());
1109                }
1110        }
1111}
1112
1113AxisAlignedBox3 VspBspTree::GetBoundingBox() const
1114{
1115        return mBox;
1116}
1117
1118BspNode *VspBspTree::GetRoot() const
1119{
1120        return mRoot;
1121}
1122
1123void VspBspTree::EvaluateLeafStats(const VspBspTraversalData &data)
1124{
1125        // the node became a leaf -> evaluate stats for leafs
1126        BspLeaf *leaf = dynamic_cast<BspLeaf *>(data.mNode);
1127
1128        // store maximal and minimal depth
1129        if (data.mDepth > mStat.maxDepth)
1130                mStat.maxDepth = data.mDepth;
1131
1132        if (data.mDepth < mStat.minDepth)
1133                mStat.minDepth = data.mDepth;
1134       
1135        if (data.mDepth >= mTermMaxDepth)
1136                ++ mStat.maxDepthNodes;
1137
1138        if (data.mPvs < mTermMinPvs)
1139                ++ mStat.minPvsNodes;
1140
1141        if ((int)data.mRays->size() < mTermMinRays)
1142                ++ mStat.minRaysNodes;
1143
1144        if (data.GetAvgRayContribution() > mTermMaxRayContribution)
1145                ++ mStat.maxRayContribNodes;
1146       
1147        if (data.mArea <= mTermMinArea)
1148        {
1149                //Debug << "area: " << data.mArea / mBox.SurfaceArea() << " min area: " << mTermMinArea / mBox.SurfaceArea() << endl;
1150                ++ mStat.minAreaNodes;
1151        }
1152        // accumulate depth to compute average depth
1153        mStat.accumDepth += data.mDepth;
1154
1155#ifdef _DEBUG
1156        Debug << "BSP stats: "
1157                  << "Depth: " << data.mDepth << " (max: " << mTermMaxDepth << "), "
1158                  << "PVS: " << data.mPvs << " (min: " << mTermMinPvs << "), "
1159                  << "Area: " << data.mArea << " (min: " << mTermMinArea << "), "
1160                  << "#rays: " << (int)data.mRays->size() << " (max: " << mTermMinRays << "), "
1161                  << "#pvs: " << leaf->GetViewCell()->GetPvs().GetSize() << "=, "
1162                  << "#avg ray contrib (pvs): " << (float)data.mPvs / (float)data.mRays->size() << endl;
1163#endif
1164}
1165
1166int VspBspTree::CastRay(Ray &ray)
1167{
1168        int hits = 0;
1169 
1170        stack<BspRayTraversalData> tStack;
1171 
1172        float maxt, mint;
1173
1174        if (!mBox.GetRaySegment(ray, mint, maxt))
1175                return 0;
1176
1177        Intersectable::NewMail();
1178
1179        Vector3 entp = ray.Extrap(mint);
1180        Vector3 extp = ray.Extrap(maxt);
1181 
1182        BspNode *node = mRoot;
1183        BspNode *farChild = NULL;
1184       
1185        while (1)
1186        {
1187                if (!node->IsLeaf())
1188                {
1189                        BspInterior *in = dynamic_cast<BspInterior *>(node);
1190
1191                        Plane3 splitPlane = in->GetPlane();
1192                        const int entSide = splitPlane.Side(entp);
1193                        const int extSide = splitPlane.Side(extp);
1194
1195                        if (entSide < 0)
1196                        {
1197                                node = in->GetBack();
1198
1199                                if(extSide <= 0) // plane does not split ray => no far child
1200                                        continue;
1201                                       
1202                                farChild = in->GetFront(); // plane splits ray
1203
1204                        } else if (entSide > 0)
1205                        {
1206                                node = in->GetFront();
1207
1208                                if (extSide >= 0) // plane does not split ray => no far child
1209                                        continue;
1210
1211                                farChild = in->GetBack(); // plane splits ray                   
1212                        }
1213                        else // ray and plane are coincident
1214                        {
1215                                // WHAT TO DO IN THIS CASE ?
1216                                //break;
1217                                node = in->GetFront();
1218                                continue;
1219                        }
1220
1221                        // push data for far child
1222                        tStack.push(BspRayTraversalData(farChild, extp, maxt));
1223
1224                        // find intersection of ray segment with plane
1225                        float t;
1226                        extp = splitPlane.FindIntersection(ray.GetLoc(), extp, &t);
1227                        maxt *= t;
1228                       
1229                } else // reached leaf => intersection with view cell
1230                {
1231                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
1232     
1233                        if (!leaf->GetViewCell()->Mailed())
1234                        {
1235                                //ray.bspIntersections.push_back(Ray::VspBspIntersection(maxt, leaf));
1236                                leaf->GetViewCell()->Mail();
1237                                ++ hits;
1238                        }
1239                       
1240                        //-- fetch the next far child from the stack
1241                        if (tStack.empty())
1242                                break;
1243     
1244                        entp = extp;
1245                        mint = maxt; // NOTE: need this?
1246
1247                        if (ray.GetType() == Ray::LINE_SEGMENT && mint > 1.0f)
1248                                break;
1249
1250                        BspRayTraversalData &s = tStack.top();
1251
1252                        node = s.mNode;
1253                        extp = s.mExitPoint;
1254                        maxt = s.mMaxT;
1255
1256                        tStack.pop();
1257                }
1258        }
1259
1260        return hits;
1261}
1262
1263bool VspBspTree::Export(const string filename)
1264{
1265        Exporter *exporter = Exporter::GetExporter(filename);
1266
1267        if (exporter)
1268        {
1269                //exporter->ExportVspBspTree(*this);
1270                return true;
1271        }       
1272
1273        return false;
1274}
1275
1276void VspBspTree::CollectViewCells(ViewCellContainer &viewCells) const
1277{
1278        stack<BspNode *> nodeStack;
1279        nodeStack.push(mRoot);
1280
1281        ViewCell::NewMail();
1282
1283        while (!nodeStack.empty())
1284        {
1285                BspNode *node = nodeStack.top();
1286                nodeStack.pop();
1287
1288                if (node->IsLeaf())
1289                {
1290                        ViewCell *viewCell = dynamic_cast<BspLeaf *>(node)->GetViewCell();
1291
1292                        if (!viewCell->Mailed())
1293                        {
1294                                viewCell->Mail();
1295                                viewCells.push_back(viewCell);
1296                        }
1297                }
1298                else
1299                {
1300                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1301
1302                        nodeStack.push(interior->GetFront());
1303                        nodeStack.push(interior->GetBack());
1304                }
1305        }
1306}
1307
1308
1309BspTreeStatistics &VspBspTree::GetStat()
1310{
1311        return mStat;
1312}
1313
1314
1315float VspBspTree::AccumulatedRayLength(const RayInfoContainer &rays) const
1316{
1317        float len = 0;
1318
1319        RayInfoContainer::const_iterator it, it_end = rays.end();
1320
1321        for (it = rays.begin(); it != it_end; ++ it)
1322                len += (*it).SegmentLength();
1323
1324        return len;
1325}
1326
1327
1328int VspBspTree::SplitRays(const Plane3 &plane,
1329                                                  RayInfoContainer &rays,
1330                                                  RayInfoContainer &frontRays,
1331                                                  RayInfoContainer &backRays)
1332{
1333        int splits = 0;
1334
1335        while (!rays.empty())
1336        {
1337                RayInfo bRay = rays.back();
1338                rays.pop_back();
1339
1340                VssRay *ray = bRay.mRay;
1341                float t;
1342
1343                        // get classification and receive new t
1344                const int cf = bRay.ComputeRayIntersection(plane, t);
1345       
1346                switch (cf)
1347                {
1348                case -1:
1349                        backRays.push_back(bRay);
1350                        break;
1351                case 1:
1352                        frontRays.push_back(bRay);
1353                        break;
1354                case 0:
1355                        //-- split ray
1356                        //--  look if start point behind or in front of plane
1357                        if (plane.Side(bRay.ExtrapOrigin()) <= 0)
1358                        {       
1359                                backRays.push_back(RayInfo(ray, bRay.GetMinT(), t));
1360                                frontRays.push_back(RayInfo(ray, t, bRay.GetMaxT()));
1361                        }
1362                        else
1363                        {
1364                                frontRays.push_back(RayInfo(ray, bRay.GetMinT(), t));
1365                                backRays.push_back(RayInfo(ray, t, bRay.GetMaxT()));
1366                        }
1367                        break;
1368                default:
1369                        Debug << "Should not come here 4" << endl;
1370                        break;
1371                }
1372        }
1373
1374        return splits;
1375}
1376
1377
1378void VspBspTree::ExtractHalfSpaces(BspNode *n, vector<Plane3> &halfSpaces) const
1379{
1380        BspNode *lastNode;
1381
1382        do
1383        {
1384                lastNode = n;
1385
1386                // want to get planes defining geometry of this node => don't take
1387                // split plane of node itself
1388                n = n->GetParent();
1389               
1390                if (n)
1391                {
1392                        BspInterior *interior = dynamic_cast<BspInterior *>(n);
1393                        Plane3 halfSpace = dynamic_cast<BspInterior *>(interior)->GetPlane();
1394
1395            if (interior->GetFront() != lastNode)
1396                                halfSpace.ReverseOrientation();
1397
1398                        halfSpaces.push_back(halfSpace);
1399                }
1400        }
1401        while (n);
1402}
1403
1404void VspBspTree::ConstructGeometry(BspNode *n,
1405                                                                   BspNodeGeometry &cell) const
1406{
1407        PolygonContainer polys;
1408        ConstructGeometry(n, polys);
1409        cell.mPolys = polys;
1410}
1411
1412void VspBspTree::ConstructGeometry(BspNode *n,
1413                                                                   PolygonContainer &cell) const
1414{
1415        vector<Plane3> halfSpaces;
1416        ExtractHalfSpaces(n, halfSpaces);
1417
1418        PolygonContainer candidatePolys;
1419
1420        // bounded planes are added to the polygons (reverse polygons
1421        // as they have to be outfacing
1422        for (int i = 0; i < (int)halfSpaces.size(); ++ i)
1423        {
1424                Polygon3 *p = GetBoundingBox().CrossSection(halfSpaces[i]);
1425               
1426                if (p->Valid(mEpsilon))
1427                {
1428                        candidatePolys.push_back(p->CreateReversePolygon());
1429                        DEL_PTR(p);
1430                }
1431        }
1432
1433        // add faces of bounding box (also could be faces of the cell)
1434        for (int i = 0; i < 6; ++ i)
1435        {
1436                VertexContainer vertices;
1437       
1438                for (int j = 0; j < 4; ++ j)
1439                        vertices.push_back(mBox.GetFace(i).mVertices[j]);
1440
1441                candidatePolys.push_back(new Polygon3(vertices));
1442        }
1443
1444        for (int i = 0; i < (int)candidatePolys.size(); ++ i)
1445        {
1446                // polygon is split by all other planes
1447                for (int j = 0; (j < (int)halfSpaces.size()) && candidatePolys[i]; ++ j)
1448                {
1449                        if (i == j) // polygon and plane are coincident
1450                                continue;
1451
1452                        VertexContainer splitPts;
1453                        Polygon3 *frontPoly, *backPoly;
1454
1455                        const int cf =
1456                                candidatePolys[i]->ClassifyPlane(halfSpaces[j],
1457                                                                                                 mEpsilon);
1458                       
1459                        switch (cf)
1460                        {
1461                                case Polygon3::SPLIT:
1462                                        frontPoly = new Polygon3();
1463                                        backPoly = new Polygon3();
1464
1465                                        candidatePolys[i]->Split(halfSpaces[j],
1466                                                                                         *frontPoly,
1467                                                                                         *backPoly,
1468                                                                                         mEpsilon);
1469
1470                                        DEL_PTR(candidatePolys[i]);
1471
1472                                        if (frontPoly->Valid(mEpsilon))
1473                                                candidatePolys[i] = frontPoly;
1474                                        else
1475                                                DEL_PTR(frontPoly);
1476
1477                                        DEL_PTR(backPoly);
1478                                        break;
1479                                case Polygon3::BACK_SIDE:
1480                                        DEL_PTR(candidatePolys[i]);
1481                                        break;
1482                                // just take polygon as it is
1483                                case Polygon3::FRONT_SIDE:
1484                                case Polygon3::COINCIDENT:
1485                                default:
1486                                        break;
1487                        }
1488                }
1489               
1490                if (candidatePolys[i])
1491                        cell.push_back(candidatePolys[i]);
1492        }
1493}
1494
1495void VspBspTree::ConstructGeometry(BspViewCell *vc, PolygonContainer &vcGeom) const
1496{
1497        vector<BspLeaf *> leaves = vc->mLeaves;
1498
1499        vector<BspLeaf *>::const_iterator it, it_end = leaves.end();
1500
1501        for (it = leaves.begin(); it != it_end; ++ it)
1502                ConstructGeometry(*it, vcGeom);
1503}
1504
1505int VspBspTree::FindNeighbors(BspNode *n, vector<BspLeaf *> &neighbors,
1506                                                   const bool onlyUnmailed) const
1507{
1508        PolygonContainer cell;
1509
1510        ConstructGeometry(n, cell);
1511
1512        stack<BspNode *> nodeStack;
1513        nodeStack.push(mRoot);
1514               
1515        // planes needed to verify that we found neighbor leaf.
1516        vector<Plane3> halfSpaces;
1517        ExtractHalfSpaces(n, halfSpaces);
1518
1519        while (!nodeStack.empty())
1520        {
1521                BspNode *node = nodeStack.top();
1522                nodeStack.pop();
1523
1524                if (node->IsLeaf())
1525                {
1526            if (node != n && (!onlyUnmailed || !node->Mailed()))
1527                        {
1528                                // test all planes of current node if candidate really
1529                                // is neighbour
1530                                PolygonContainer neighborCandidate;
1531                                ConstructGeometry(node, neighborCandidate);
1532                               
1533                                bool isAdjacent = true;
1534                                for (int i = 0; (i < halfSpaces.size()) && isAdjacent; ++ i)
1535                                {
1536                                        const int cf =
1537                                                Polygon3::ClassifyPlane(neighborCandidate,
1538                                                                                                halfSpaces[i],
1539                                                                                                mEpsilon);
1540
1541                                        if (cf == Polygon3::BACK_SIDE)
1542                                                isAdjacent = false;
1543                                }
1544
1545                                if (isAdjacent)
1546                                        neighbors.push_back(dynamic_cast<BspLeaf *>(node));
1547
1548                                CLEAR_CONTAINER(neighborCandidate);
1549                        }
1550                }
1551                else
1552                {
1553                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1554       
1555                        const int cf = Polygon3::ClassifyPlane(cell,
1556                                                                                                   interior->GetPlane(),
1557                                                                                                   mEpsilon);
1558
1559                        if (cf == Polygon3::FRONT_SIDE)
1560                                nodeStack.push(interior->GetFront());
1561                        else
1562                                if (cf == Polygon3::BACK_SIDE)
1563                                        nodeStack.push(interior->GetBack());
1564                                else
1565                                {
1566                                        // random decision
1567                                        nodeStack.push(interior->GetBack());
1568                                        nodeStack.push(interior->GetFront());
1569                                }
1570                }
1571        }
1572       
1573        CLEAR_CONTAINER(cell);
1574        return (int)neighbors.size();
1575}
1576
1577BspLeaf *VspBspTree::GetRandomLeaf(const Plane3 &halfspace)
1578{
1579    stack<BspNode *> nodeStack;
1580        nodeStack.push(mRoot);
1581       
1582        int mask = rand();
1583 
1584        while (!nodeStack.empty())
1585        {
1586                BspNode *node = nodeStack.top();
1587                nodeStack.pop();
1588         
1589                if (node->IsLeaf())
1590                {
1591                        return dynamic_cast<BspLeaf *>(node);
1592                }
1593                else
1594                {
1595                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1596                       
1597                        BspNode *next;
1598       
1599                        PolygonContainer cell;
1600
1601                        // todo: not very efficient: constructs full cell everytime
1602                        ConstructGeometry(interior, cell);
1603
1604                        const int cf = Polygon3::ClassifyPlane(cell, halfspace, mEpsilon);
1605
1606                        if (cf == Polygon3::BACK_SIDE)
1607                                next = interior->GetFront();
1608                        else
1609                                if (cf == Polygon3::FRONT_SIDE)
1610                                        next = interior->GetFront();
1611                        else
1612                        {
1613                                // random decision
1614                                if (mask & 1)
1615                                        next = interior->GetBack();
1616                                else
1617                                        next = interior->GetFront();
1618                                mask = mask >> 1;
1619                        }
1620
1621                        nodeStack.push(next);
1622                }
1623        }
1624       
1625        return NULL;
1626}
1627
1628BspLeaf *VspBspTree::GetRandomLeaf(const bool onlyUnmailed)
1629{
1630        stack<BspNode *> nodeStack;
1631       
1632        nodeStack.push(mRoot);
1633
1634        int mask = rand();
1635       
1636        while (!nodeStack.empty())
1637        {
1638                BspNode *node = nodeStack.top();
1639                nodeStack.pop();
1640               
1641                if (node->IsLeaf())
1642                {
1643                        if ( (!onlyUnmailed || !node->Mailed()) )
1644                                return dynamic_cast<BspLeaf *>(node);
1645                }
1646                else
1647                {
1648                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1649
1650                        // random decision
1651                        if (mask & 1)
1652                                nodeStack.push(interior->GetBack());
1653                        else
1654                                nodeStack.push(interior->GetFront());
1655
1656                        mask = mask >> 1;
1657                }
1658        }
1659       
1660        return NULL;
1661}
1662
1663int VspBspTree::ComputePvsSize(const RayInfoContainer &rays) const
1664{
1665        int pvsSize = 0;
1666
1667        RayInfoContainer::const_iterator rit, rit_end = rays.end();
1668
1669        Intersectable::NewMail();
1670
1671        for (rit = rays.begin(); rit != rays.end(); ++ rit)
1672        {
1673                VssRay *ray = (*rit).mRay;
1674               
1675                if (ray->mOriginObject)
1676                {
1677                        if (!ray->mOriginObject->Mailed())
1678                        {
1679                                ray->mOriginObject->Mail();
1680                                ++ pvsSize;
1681                        }
1682                }
1683                if (ray->mTerminationObject)
1684                {
1685                        if (!ray->mTerminationObject->Mailed())
1686                        {
1687                                ray->mTerminationObject->Mail();
1688                                ++ pvsSize;
1689                        }
1690                }
1691        }
1692
1693        return pvsSize;
1694}
1695
1696float VspBspTree::GetEpsilon() const
1697{
1698        return mEpsilon;
1699}
1700
1701BspViewCell *VspBspTree::GetRootCell() const
1702{
1703        return mRootCell;
1704}
1705
1706int VspBspTree::SplitPolygons(const Plane3 &plane,
1707                                                          PolygonContainer &polys,
1708                                                          PolygonContainer &frontPolys,
1709                                                          PolygonContainer &backPolys,
1710                                                          PolygonContainer &coincident) const
1711{
1712        int splits = 0;
1713
1714        while (!polys.empty())
1715        {
1716                Polygon3 *poly = polys.back();
1717                polys.pop_back();
1718
1719                // classify polygon
1720                const int cf = poly->ClassifyPlane(plane, mEpsilon);
1721
1722                switch (cf)
1723                {
1724                        case Polygon3::COINCIDENT:
1725                                coincident.push_back(poly);
1726                                break;                 
1727                        case Polygon3::FRONT_SIDE:     
1728                                frontPolys.push_back(poly);
1729                                break;
1730                        case Polygon3::BACK_SIDE:
1731                                backPolys.push_back(poly);
1732                                break;
1733                        case Polygon3::SPLIT:
1734                                backPolys.push_back(poly);
1735                                frontPolys.push_back(poly);
1736                                ++ splits;
1737                                break;
1738                        default:
1739                Debug << "SHOULD NEVER COME HERE\n";
1740                                break;
1741                }
1742        }
1743
1744        return splits;
1745}
1746
1747
1748int VspBspTree::CastLineSegment(const Vector3 &origin,
1749                                                                const Vector3 &termination,
1750                                                                vector<ViewCell *> &viewcells)
1751{
1752        int hits = 0;
1753        stack<BspRayTraversalData> tStack;
1754 
1755        float mint = 0.0f, maxt = 1.0f;
1756 
1757        Intersectable::NewMail();
1758 
1759        Vector3 entp = origin;
1760        Vector3 extp = termination;
1761 
1762        BspNode *node = mRoot;
1763        BspNode *farChild = NULL;
1764 
1765        while (1)
1766        {
1767                if (!node->IsLeaf()) 
1768                {
1769                        BspInterior *in = dynamic_cast<BspInterior *>(node);
1770         
1771                        Plane3 splitPlane = in->GetPlane();
1772                        const int entSide = splitPlane.Side(entp);
1773                        const int extSide = splitPlane.Side(extp);
1774         
1775                        if (entSide < 0)
1776                        {
1777                                node = in->GetBack();
1778               
1779                                if(extSide <= 0) // plane does not split ray => no far child
1780                                        continue;
1781               
1782                                farChild = in->GetFront(); // plane splits ray
1783                        } else if (entSide > 0)
1784                        {
1785                                node = in->GetFront();
1786                 
1787                                if (extSide >= 0) // plane does not split ray => no far child
1788                                        continue;
1789                 
1790                                farChild = in->GetBack(); // plane splits ray                   
1791                        }
1792                        else // ray and plane are coincident
1793                        {
1794                                // WHAT TO DO IN THIS CASE ?
1795                                //break;
1796                                node = in->GetFront();
1797                                continue;
1798                        }
1799         
1800                        // push data for far child
1801                        tStack.push(BspRayTraversalData(farChild, extp, maxt));
1802         
1803                        // find intersection of ray segment with plane
1804                        float t;
1805                        extp = splitPlane.FindIntersection(origin, extp, &t);
1806                        maxt *= t;
1807         
1808                } else
1809                {
1810                        // reached leaf => intersection with view cell
1811                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
1812         
1813                        if (!leaf->GetViewCell()->Mailed())
1814                        {
1815                                viewcells.push_back(leaf->GetViewCell());
1816                                leaf->GetViewCell()->Mail();
1817                                ++ hits;
1818                        }
1819         
1820                        //-- fetch the next far child from the stack
1821                        if (tStack.empty())
1822                                break;
1823     
1824                        entp = extp;
1825                        mint = maxt; // NOTE: need this?
1826         
1827                       
1828                        BspRayTraversalData &s = tStack.top();
1829           
1830                        node = s.mNode;
1831                        extp = s.mExitPoint;
1832                        maxt = s.mMaxT;
1833         
1834                        tStack.pop();
1835                }
1836        }
1837        return hits;
1838}
1839
1840
1841BspNode *VspBspTree::CollapseTree(BspNode *node)
1842{
1843    if (node->IsLeaf())
1844                return node;
1845
1846        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1847
1848        BspNode *front = CollapseTree(interior->GetFront());
1849        BspNode *back = CollapseTree(interior->GetBack());
1850
1851        if (front->IsLeaf() && back->IsLeaf())
1852        {
1853                BspLeaf *frontLeaf = dynamic_cast<BspLeaf *>(front);
1854                BspLeaf *backLeaf = dynamic_cast<BspLeaf *>(back);
1855
1856                //-- collapse tree
1857                if (frontLeaf->GetViewCell() == backLeaf->GetViewCell())
1858                {
1859                        BspViewCell *vc = frontLeaf->GetViewCell();
1860
1861                        BspLeaf *leaf = new BspLeaf(interior->GetParent(), vc);
1862                       
1863                        // replace a link from node's parent
1864                        if (leaf->GetParent())
1865                                leaf->GetParent()->ReplaceChildLink(node, leaf);
1866
1867                        delete interior;
1868
1869                        return leaf;
1870                }
1871        }
1872
1873        return node;
1874}
1875
1876
1877void VspBspTree::RepairVcLeafLists()
1878{
1879        // list not valid anymore => clear
1880        stack<BspNode *> nodeStack;
1881        nodeStack.push(mRoot);
1882
1883        ViewCell::NewMail();
1884
1885        while (!nodeStack.empty())
1886        {
1887                BspNode *node = nodeStack.top();
1888                nodeStack.pop();
1889
1890                if (node->IsLeaf())
1891                {
1892                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
1893
1894                        BspViewCell *viewCell = leaf->GetViewCell();
1895
1896                        if (!viewCell->Mailed())
1897                        {
1898                                viewCell->mLeaves.clear();
1899                                viewCell->Mail();
1900                        }
1901
1902                        viewCell->mLeaves.push_back(leaf);
1903                }
1904                else
1905                {
1906                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1907
1908                        nodeStack.push(interior->GetFront());
1909                        nodeStack.push(interior->GetBack());
1910                }
1911        }
1912}
1913
1914
1915int VspBspTree::MergeLeaves()
1916{
1917        vector<BspLeaf *> leaves;
1918        priority_queue<BspMergeCandidate> mergeQueue;
1919
1920        // collect the leaves, e.g., the "voxels" that will build the view cells
1921        CollectLeaves(leaves);
1922
1923        int vcSize = (int)leaves.size();
1924        int savedVcSize = vcSize;
1925
1926        BspLeaf::NewMail();
1927
1928        vector<BspLeaf *>::const_iterator it, it_end = leaves.end();
1929
1930        // find merge candidates and push them into queue
1931        for (it = leaves.begin(); it != it_end; ++ it)
1932        {
1933                BspLeaf *leaf = *it;
1934
1935                // no leaf is part of two merge candidates
1936                if (!leaf->Mailed())
1937                {
1938                        leaf->Mail();
1939
1940                        vector<BspLeaf *> neighbors;
1941                        FindNeighbors(leaf, neighbors, true);
1942
1943                        vector<BspLeaf *>::const_iterator nit,
1944                                nit_end = neighbors.end();
1945
1946                        for (nit = neighbors.begin(); nit != nit_end; ++ nit)
1947                        {
1948                                BspMergeCandidate mc = BspMergeCandidate(leaf, *nit);
1949                                mergeQueue.push(mc);
1950
1951                                BspMergeCandidate::sOverallCost += mc.GetLeaf1Cost();
1952                                BspMergeCandidate::sOverallCost += mc.GetLeaf2Cost();
1953                        }
1954                }
1955        }
1956
1957        int merged = 0;
1958
1959        Debug << "mergecost: " << mergeQueue.top().GetMergeCost() / BspMergeCandidate::sOverallCost << " " << mMergeMaxCostRatio << endl;
1960        Debug << "overall cost: " << BspMergeCandidate::sOverallCost << endl;
1961
1962        // use priority queue to merge leaves
1963        while (!mergeQueue.empty() && (vcSize > mMergeMinViewCells) &&
1964                   (mergeQueue.top().GetMergeCost() <
1965                    mMergeMaxCostRatio * BspMergeCandidate::sOverallCost))
1966        {
1967                Debug << "mergecost: " << mergeQueue.top().GetMergeCost() / BspMergeCandidate::sOverallCost << " " << mMergeMaxCostRatio << endl;
1968                BspMergeCandidate mc = mergeQueue.top();
1969                mergeQueue.pop();
1970
1971                // both view cells equal!
1972                if (mc.GetLeaf1()->GetViewCell() == mc.GetLeaf2()->GetViewCell())
1973                        continue;
1974
1975                if (mc.Valid())
1976                {
1977                        ViewCell::NewMail();
1978                        MergeViewCells(mc.GetLeaf1(), mc.GetLeaf2());
1979
1980                        ++ merged;
1981                        -- vcSize;
1982                        // increase absolute merge cost
1983                        BspMergeCandidate::sOverallCost += mc.GetMergeCost();
1984                }
1985                // merge candidate not valid, because one of the leaves was already
1986                // merged with another one
1987                else
1988                {
1989                        // validate and reinsert into queue
1990                        mc.SetValid();
1991                        mergeQueue.push(mc);
1992                        //Debug << "validate " << mc.GetMergeCost() << endl;
1993                }
1994        }
1995
1996        // collapse tree according to view cell partition
1997        CollapseTree(mRoot);
1998        // revalidate leaves
1999        RepairVcLeafLists();
2000
2001        //Debug << "merged " << merged << " of " << savedVcSize << " leaves" << endl;
2002
2003        //TODO: should return sample contributions
2004        return merged;
2005}
2006
2007
2008bool VspBspTree::MergeViewCells(BspLeaf *l1, BspLeaf *l2)
2009{
2010        //-- change pointer to view cells of all leaves associated
2011        //-- with the previous view cells
2012        BspViewCell *fVc = l1->GetViewCell();
2013        BspViewCell *bVc = l2->GetViewCell();
2014
2015        BspViewCell *vc = dynamic_cast<BspViewCell *>(
2016                mViewCellsManager->MergeViewCells(*fVc, *bVc));
2017
2018        // if merge was unsuccessful
2019        if (!vc) return false;
2020
2021        // set new size of view cell
2022        vc->SetArea(fVc->GetArea() + bVc->GetArea());
2023
2024        vector<BspLeaf *> fLeaves = fVc->mLeaves;
2025        vector<BspLeaf *> bLeaves = bVc->mLeaves;
2026
2027        vector<BspLeaf *>::const_iterator it;
2028
2029        //-- change view cells of all the other leaves the view cell belongs to
2030        for (it = fLeaves.begin(); it != fLeaves.end(); ++ it)
2031        {
2032                (*it)->SetViewCell(vc);
2033                vc->mLeaves.push_back(*it);
2034        }
2035
2036        for (it = bLeaves.begin(); it != bLeaves.end(); ++ it)
2037        {
2038                (*it)->SetViewCell(vc);
2039                vc->mLeaves.push_back(*it);
2040        }
2041
2042        vc->Mail();
2043
2044        // clean up old view cells
2045        DEL_PTR(fVc);
2046        DEL_PTR(bVc);
2047
2048        return true;
2049}
2050
2051
2052void VspBspTree::SetViewCellsManager(ViewCellsManager *vcm)
2053{
2054        mViewCellsManager = vcm;
2055}
2056
2057/************************************************************************/
2058/*                BspMergeCandidate implementation                      */
2059/************************************************************************/
2060
2061
2062BspMergeCandidate::BspMergeCandidate(BspLeaf *l1, BspLeaf *l2):
2063mMergeCost(0),
2064mLeaf1(l1),
2065mLeaf2(l2),
2066mLeaf1Id(l1->GetViewCell()->mMailbox),
2067mLeaf2Id(l2->GetViewCell()->mMailbox)
2068{
2069        EvalMergeCost();
2070}
2071
2072float BspMergeCandidate::GetLeaf1Cost() const
2073{
2074        BspViewCell *vc = mLeaf1->GetViewCell();
2075        return vc->GetPvs().GetSize() * vc->GetArea();
2076}
2077
2078float BspMergeCandidate::GetLeaf2Cost() const
2079{
2080        BspViewCell *vc = mLeaf2->GetViewCell();
2081        return vc->GetPvs().GetSize() * vc->GetVolume();
2082}
2083
2084void BspMergeCandidate::EvalMergeCost()
2085{
2086        //-- compute pvs difference
2087        BspViewCell *vc1 = mLeaf1->GetViewCell();
2088        BspViewCell *vc2 = mLeaf2->GetViewCell();
2089
2090        const int diff1 = vc1->GetPvs().Diff(vc2->GetPvs());
2091        const int vcPvs = diff1 + vc1->GetPvs().GetSize();
2092
2093        //-- compute ratio of old cost
2094        //-- (added size of left and right view cell times pvs size)
2095        //-- to new rendering cost (size of merged view cell times pvs size)
2096        const float oldCost = GetLeaf1Cost() + GetLeaf2Cost();
2097       
2098        const float newCost =
2099                (float)vcPvs * (vc1->GetArea() + vc2->GetArea());
2100
2101        mMergeCost = newCost - oldCost;
2102
2103//      if (vcPvs > sMaxPvsSize) // strong penalty if pvs size too large
2104//              mMergeCost += 1.0;
2105}
2106
2107void BspMergeCandidate::SetLeaf1(BspLeaf *l)
2108{
2109        mLeaf1 = l;
2110}
2111
2112void BspMergeCandidate::SetLeaf2(BspLeaf *l)
2113{
2114        mLeaf2 = l;
2115}
2116
2117BspLeaf *BspMergeCandidate::GetLeaf1()
2118{
2119        return mLeaf1;
2120}
2121
2122BspLeaf *BspMergeCandidate::GetLeaf2()
2123{
2124        return mLeaf2;
2125}
2126
2127bool BspMergeCandidate::Valid() const
2128{
2129        return
2130                (mLeaf1->GetViewCell()->mMailbox == mLeaf1Id) &&
2131                (mLeaf2->GetViewCell()->mMailbox == mLeaf2Id);
2132}
2133
2134float BspMergeCandidate::GetMergeCost() const
2135{
2136        return mMergeCost;
2137}
2138
2139void BspMergeCandidate::SetValid()
2140{
2141        mLeaf1Id = mLeaf1->GetViewCell()->mMailbox;
2142        mLeaf2Id = mLeaf2->GetViewCell()->mMailbox;
2143
2144        EvalMergeCost();
2145}
Note: See TracBrowser for help on using the repository browser.