source: GTP/trunk/Lib/Vis/Preprocessing/src/VspBspTree.cpp @ 1580

Revision 1580, 99.2 KB checked in by mattausch, 18 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#include "Beam.h"
19
20
21
22namespace GtpVisibilityPreprocessor {
23
24
25#define USE_FIXEDPOINT_T 0
26#define COUNT_ORIGIN_OBJECTS 1
27
28
29//////////////
30//-- static members
31
32int VspBspTree::sFrontId = 0;
33int VspBspTree::sBackId = 0;
34int VspBspTree::sFrontAndBackId = 0;
35
36
37
38typedef pair<BspNode *, BspNodeGeometry *> bspNodePair;
39
40
41// pvs penalty can be different from pvs size
42inline static float EvalPvsPenalty(const int pvs,
43                                                                   const int lower,
44                                                                   const int upper)
45{
46        // clamp to minmax values
47        if (pvs < lower)
48                return (float)lower;
49        if (pvs > upper)
50                return (float)upper;
51
52        return (float)pvs;
53}
54
55
56
57
58/******************************************************************************/
59/*                       class VspBspTree implementation                      */
60/******************************************************************************/
61
62
63VspBspTree::VspBspTree():
64mRoot(NULL),
65mUseAreaForPvs(false),
66mCostNormalizer(Limits::Small),
67mViewCellsManager(NULL),
68mOutOfBoundsCell(NULL),
69mStoreRays(false),
70mRenderCostWeight(0.5),
71mUseRandomAxis(false),
72mTimeStamp(1)
73{
74        bool randomize = false;
75        Environment::GetSingleton()->GetBoolValue("VspBspTree.Construction.randomize", randomize);
76        if (randomize) Randomize(); // initialise random generator for heuristics
77
78        //////////////////
79        //-- termination criteria for autopartition
80
81        Environment::GetSingleton()->GetIntValue("VspBspTree.Termination.maxDepth", mTermMaxDepth);
82        Environment::GetSingleton()->GetIntValue("VspBspTree.Termination.minPvs", mTermMinPvs);
83        Environment::GetSingleton()->GetIntValue("VspBspTree.Termination.minRays", mTermMinRays);
84        Environment::GetSingleton()->GetFloatValue("VspBspTree.Termination.minProbability", mTermMinProbability);
85        Environment::GetSingleton()->GetFloatValue("VspBspTree.Termination.maxRayContribution", mTermMaxRayContribution);
86        Environment::GetSingleton()->GetFloatValue("VspBspTree.Termination.minAccRayLenght", mTermMinAccRayLength);
87       
88        Environment::GetSingleton()->GetIntValue("VspBspTree.Termination.missTolerance", mTermMissTolerance);
89        Environment::GetSingleton()->GetIntValue("VspBspTree.Termination.maxViewCells", mMaxViewCells);
90
91        ////////////////////////
92        //-- cost ratios for early tree termination
93        Environment::GetSingleton()->GetFloatValue("VspBspTree.Termination.maxCostRatio", mTermMaxCostRatio);
94        Environment::GetSingleton()->GetFloatValue("VspBspTree.Termination.minGlobalCostRatio", mTermMinGlobalCostRatio);
95        Environment::GetSingleton()->GetIntValue("VspBspTree.Termination.globalCostMissTolerance", mTermGlobalCostMissTolerance);
96
97        ///////////
98        //-- factors for bsp tree split plane heuristics
99
100        Environment::GetSingleton()->GetFloatValue("VspBspTree.Factor.pvs", mPvsFactor);
101        Environment::GetSingleton()->GetFloatValue("VspBspTree.Termination.ct_div_ci", mCtDivCi);
102
103        //////////
104        //-- partition criteria
105
106        Environment::GetSingleton()->GetIntValue("VspBspTree.maxPolyCandidates", mMaxPolyCandidates);
107        Environment::GetSingleton()->GetIntValue("VspBspTree.maxRayCandidates", mMaxRayCandidates);
108        Environment::GetSingleton()->GetIntValue("VspBspTree.splitPlaneStrategy", mSplitPlaneStrategy);
109
110        Environment::GetSingleton()->GetFloatValue("VspBspTree.Construction.epsilon", mEpsilon);
111        Environment::GetSingleton()->GetIntValue("VspBspTree.maxTests", mMaxTests);
112
113        // if only the driving axis is used for axis aligned split
114        Environment::GetSingleton()->GetBoolValue("VspBspTree.splitUseOnlyDrivingAxis", mOnlyDrivingAxis);
115       
116        //////////////////////
117        //-- termination criteria for axis aligned split
118        Environment::GetSingleton()->GetFloatValue("VspBspTree.Termination.AxisAligned.maxRayContribution",
119                                                                mTermMaxRayContriForAxisAligned);
120        Environment::GetSingleton()->GetIntValue("VspBspTree.Termination.AxisAligned.minRays",
121                                                         mTermMinRaysForAxisAligned);
122
123        Environment::GetSingleton()->GetFloatValue("VspBspTree.maxStaticMemory", mMaxMemory);
124
125        Environment::GetSingleton()->GetFloatValue("VspBspTree.Construction.renderCostWeight", mRenderCostWeight);
126        Environment::GetSingleton()->GetFloatValue("VspBspTree.Construction.renderCostDecreaseWeight", mRenderCostDecreaseWeight);
127        Environment::GetSingleton()->GetBoolValue("VspBspTree.usePolygonSplitIfAvailable", mUsePolygonSplitIfAvailable);
128
129        Environment::GetSingleton()->GetBoolValue("VspBspTree.useCostHeuristics", mUseCostHeuristics);
130        Environment::GetSingleton()->GetBoolValue("VspBspTree.useSplitCostQueue", mUseSplitCostQueue);
131        Environment::GetSingleton()->GetBoolValue("VspBspTree.simulateOctree", mCirculatingAxis);
132        Environment::GetSingleton()->GetBoolValue("VspBspTree.useRandomAxis", mUseRandomAxis);
133        Environment::GetSingleton()->GetIntValue("VspBspTree.nodePriorityQueueType", mNodePriorityQueueType);
134
135       
136        char subdivisionStatsLog[100];
137        Environment::GetSingleton()->GetStringValue("VspBspTree.subdivisionStats", subdivisionStatsLog);
138        mSubdivisionStats.open(subdivisionStatsLog);
139
140        Environment::GetSingleton()->GetFloatValue("VspBspTree.Construction.minBand", mMinBand);
141        Environment::GetSingleton()->GetFloatValue("VspBspTree.Construction.maxBand", mMaxBand);
142        Environment::GetSingleton()->GetBoolValue("VspBspTree.Construction.useDrivingAxisForMaxCost", mUseDrivingAxisIfMaxCostViolated);
143
144        /////////
145        //-- debug output
146
147        Debug << "******* VSP BSP options ******** " << endl;
148    Debug << "max depth: " << mTermMaxDepth << endl;
149        Debug << "min PVS: " << mTermMinPvs << endl;
150        Debug << "min probabiliy: " << mTermMinProbability << endl;
151        Debug << "min rays: " << mTermMinRays << endl;
152        Debug << "max ray contri: " << mTermMaxRayContribution << endl;
153        Debug << "max cost ratio: " << mTermMaxCostRatio << endl;
154        Debug << "miss tolerance: " << mTermMissTolerance << endl;
155        Debug << "max view cells: " << mMaxViewCells << endl;
156        Debug << "max polygon candidates: " << mMaxPolyCandidates << endl;
157        Debug << "randomize: " << randomize << endl;
158
159        Debug << "using area for pvs: " << mUseAreaForPvs << endl;
160        Debug << "render cost weight: " << mRenderCostWeight << endl;
161        Debug << "min global cost ratio: " << mTermMinGlobalCostRatio << endl;
162        Debug << "global cost miss tolerance: " << mTermGlobalCostMissTolerance << endl;
163        Debug << "only driving axis: " << mOnlyDrivingAxis << endl;
164        Debug << "max memory: " << mMaxMemory << endl;
165        Debug << "use poly split if available: " << mUsePolygonSplitIfAvailable << endl;
166        Debug << "use cost heuristics: " << mUseCostHeuristics << endl;
167        Debug << "use split cost queue: " << mUseSplitCostQueue << endl;
168        Debug << "subdivision stats log: " << subdivisionStatsLog << endl;
169        Debug << "use random axis: " << mUseRandomAxis << endl;
170        Debug << "priority queue type: " << mNodePriorityQueueType << endl;
171        Debug << "circulating axis: " << mCirculatingAxis << endl;
172        Debug << "minband: " << mMinBand << endl;
173        Debug << "maxband: " << mMaxBand << endl;
174        Debug << "use driving axis for max cost: " << mUseDrivingAxisIfMaxCostViolated << endl;
175        Debug << "render cost decrease weight: " << mRenderCostDecreaseWeight << endl;
176
177        Debug << "Split plane strategy: ";
178
179        if (mSplitPlaneStrategy & RANDOM_POLYGON)
180        {
181                Debug << "random polygon ";
182        }
183        if (mSplitPlaneStrategy & AXIS_ALIGNED)
184        {
185                Debug << "axis aligned ";
186        }
187        if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)
188        {
189                mCostNormalizer += mLeastRaySplitsFactor;
190                Debug << "least ray splits ";
191        }
192        if (mSplitPlaneStrategy & BALANCED_RAYS)
193        {
194                mCostNormalizer += mBalancedRaysFactor;
195                Debug << "balanced rays ";
196        }
197        if (mSplitPlaneStrategy & PVS)
198        {
199                mCostNormalizer += mPvsFactor;
200                Debug << "pvs";
201        }
202
203        Debug << endl;
204
205        mLocalSubdivisionCandidates = new vector<SortableEntry>;
206}
207
208
209BspViewCell *VspBspTree::GetOutOfBoundsCell()
210{
211        return mOutOfBoundsCell;
212}
213
214
215BspViewCell *VspBspTree::GetOrCreateOutOfBoundsCell()
216{
217        if (!mOutOfBoundsCell)
218        {
219                mOutOfBoundsCell = new BspViewCell();
220                mOutOfBoundsCell->SetId(OUT_OF_BOUNDS_ID);
221                mOutOfBoundsCell->SetValid(false);
222        }
223
224        return mOutOfBoundsCell;
225}
226
227
228const BspTreeStatistics &VspBspTree::GetStatistics() const
229{
230        return mBspStats;
231}
232
233
234VspBspTree::~VspBspTree()
235{
236        DEL_PTR(mRoot);
237        DEL_PTR(mLocalSubdivisionCandidates);
238}
239
240
241int VspBspTree::AddMeshToPolygons(Mesh *mesh,
242                                                                  PolygonContainer &polys,
243                                                                  MeshInstance *parent)
244{
245        FaceContainer::const_iterator fi;
246
247        // copy the face data to polygons
248        for (fi = mesh->mFaces.begin(); fi != mesh->mFaces.end(); ++ fi)
249        {
250                Polygon3 *poly = new Polygon3((*fi), mesh);
251
252                if (poly->Valid(mEpsilon))
253                {
254                        poly->mParent = parent; // set parent intersectable
255                        polys.push_back(poly);
256                }
257                else
258                {
259                        DEL_PTR(poly);
260                }
261        }
262        return (int)mesh->mFaces.size();
263}
264
265
266int VspBspTree::AddToPolygonSoup(const ViewCellContainer &viewCells,
267                                                                 PolygonContainer &polys,
268                                                                 int maxObjects)
269{
270        int limit = (maxObjects > 0) ?
271                Min((int)viewCells.size(), maxObjects) : (int)viewCells.size();
272
273        int polysSize = 0;
274       
275        for (int i = 0; i < limit; ++ i)
276        {
277                Mesh *mesh = viewCells[i]->GetMesh();
278                if (mesh)
279                {       // // copy the mesh into polygons and add to BSP tree aabb
280                        mBoundingBox.Include(viewCells[i]->GetBox());
281                        polysSize += AddMeshToPolygons(mesh,
282                                                                                   polys,
283                                                                                   viewCells[i]);
284                }
285        }
286       
287        return polysSize;
288}
289
290
291int VspBspTree::AddToPolygonSoup(const ObjectContainer &objects,
292                                                                 PolygonContainer &polys,
293                                                                 int maxObjects)
294{
295        int limit = (maxObjects > 0) ?
296                Min((int)objects.size(), maxObjects) : (int)objects.size();
297
298        for (int i = 0; i < limit; ++i)
299        {
300                Intersectable *object = objects[i];//*it;
301                Mesh *mesh = NULL;
302
303                switch (object->Type()) // extract the meshes
304                {
305                case Intersectable::MESH_INSTANCE:
306                        mesh = dynamic_cast<MeshInstance *>(object)->GetMesh();
307                        break;
308                case Intersectable::VIEW_CELL:
309                        mesh = dynamic_cast<ViewCell *>(object)->GetMesh();
310                        break;
311                case Intersectable::TRANSFORMED_MESH_INSTANCE:
312                        {
313                                TransformedMeshInstance *mi = dynamic_cast<TransformedMeshInstance *>(object);
314
315                                if (!mi->GetMesh())     
316                                        break;
317                                mesh = new Mesh();
318                                mi->GetTransformedMesh(*mesh);
319                               
320                break;
321                        }
322                default:
323                        Debug << "intersectable type not supported" << endl;
324                        break;
325                }
326
327        if (mesh) // copy the mesh data to polygons
328                {
329                        mBoundingBox.Include(object->GetBox()); // add to BSP tree aabb
330                        AddMeshToPolygons(mesh, polys, NULL);
331
332                        // cleanup
333                        if (object->Type() == Intersectable::TRANSFORMED_MESH_INSTANCE)
334                                DEL_PTR(mesh);
335                }
336        }
337
338        return (int)polys.size();
339}
340
341
342void VspBspTree::ComputeBoundingBox(const VssRayContainer &sampleRays,
343                                                                        AxisAlignedBox3 *forcedBoundingBox)
344{
345        if (forcedBoundingBox)
346        {
347                mBoundingBox = *forcedBoundingBox;
348        }
349        else // compute vsp tree bounding box
350        {
351                mBoundingBox.Initialize();
352
353                VssRayContainer::const_iterator rit, rit_end = sampleRays.end();
354
355                //-- compute bounding box
356        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
357                {
358                        VssRay *ray = *rit;
359
360                        // compute bounding box of view space
361                        mBoundingBox.Include(ray->GetTermination());
362                        mBoundingBox.Include(ray->GetOrigin());
363                }
364        }
365}
366
367
368void VspBspTree::Construct(const VssRayContainer &sampleRays,
369                                                   AxisAlignedBox3 *forcedBoundingBox)
370{
371        // Compute the bounding box from the rays
372        ComputeBoundingBox(sampleRays, forcedBoundingBox);
373       
374        PolygonContainer polys;
375        RayInfoContainer *rays = new RayInfoContainer();
376
377        ////////////
378        //-- extract polygons from rays if polygon candidate planes are required
379
380        if (mMaxPolyCandidates)
381        {
382                int numObj = 0;
383                Intersectable::NewMail();
384
385        cout << "Extracting polygons from rays ... ";
386                const long startTime = GetTime();
387
388        VssRayContainer::const_iterator rit, rit_end = sampleRays.end();
389
390                //-- extract polygons intersected by the rays
391                for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
392                {
393                        VssRay *ray = *rit;
394                        Intersectable *obj = ray->mTerminationObject;
395
396                        if ((mBoundingBox.IsInside(ray->mTermination) || !forcedBoundingBox) &&
397                                obj && !obj->Mailed())
398                        {
399                                obj->Mail();
400
401                                // handle intersectable
402                                switch (obj->Type())
403                                {
404                                        case Intersectable::TRANSFORMED_MESH_INSTANCE:
405                                                {
406                                                        Mesh mesh;
407                               
408                                                        TransformedMeshInstance *tmobj =
409                                                                dynamic_cast<TransformedMeshInstance *>(obj);
410                               
411                                                        tmobj->GetTransformedMesh(mesh);
412                                                        AddMeshToPolygons(&mesh, polys, tmobj);
413                                                }
414                                                break;
415                                        case Intersectable::MESH_INSTANCE:
416                                                {
417                                                        MeshInstance *mobj = dynamic_cast<MeshInstance *>(obj);
418                                                        AddMeshToPolygons(mobj->GetMesh(), polys, mobj);
419                                                }
420                                                break;
421                                        case Intersectable::TRIANGLE_INTERSECTABLE:
422                                                {
423                                                        // TODO
424                                                        cout << "not implemented yet" << endl;
425                                                }
426                                        default:
427                                                break;
428                                }
429
430                                ++ numObj;
431
432                                //-- compute bounding box
433                                if (!forcedBoundingBox)
434                                        mBoundingBox.Include(ray->mTermination);
435                        }
436
437                        if ((mBoundingBox.IsInside(ray->mOrigin) || !forcedBoundingBox) &&
438                                ray->mOriginObject &&
439                                !ray->mOriginObject->Mailed())
440                        {               
441                                ray->mOriginObject->Mail();
442                                MeshInstance *obj = dynamic_cast<MeshInstance *>(ray->mOriginObject);
443                                AddMeshToPolygons(obj->GetMesh(), polys, obj);
444                               
445                                ++ numObj;
446                        }
447                }
448
449                // throw out unnecessary polygons
450                PreprocessPolygons(polys);
451
452                cout << "finished" << endl;
453
454                Debug << "\n" << (int)polys.size() << " polys extracted from "
455                  << (int)sampleRays.size() << " rays in "
456                  << TimeDiff(startTime, GetTime())*1e-3 << " secs" << endl << endl;
457        }
458       
459        Debug << "maximal pvs (i.e., pvs still considered as valid): "
460                  << mViewCellsManager->GetMaxPvsSize() << endl;
461
462        VssRayContainer::const_iterator rit, rit_end = sampleRays.end();
463
464        //-- store rays
465        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
466        {
467                VssRay *ray = *rit;
468
469                float minT, maxT;
470
471                static Ray hray;
472                hray.Init(*ray);
473
474                // TODO: not very efficient to implictly cast between rays types
475                if (mBoundingBox.GetRaySegment(hray, minT, maxT))
476                {
477                        float len = ray->Length();
478
479                        if (!len)
480                                len = Limits::Small;
481
482                        rays->push_back(RayInfo(ray, minT / len, maxT / len));
483                }
484        }
485
486        // normalize
487        if (mUseAreaForPvs)
488                mTermMinProbability *= mBoundingBox.SurfaceArea();
489        else
490                mTermMinProbability *= mBoundingBox.GetVolume();
491
492
493        mBspStats.nodes = 1;
494        mBspStats.polys = (int)polys.size();
495        mBspStats.mGlobalCostMisses = 0;
496
497
498        // use split cost priority queue
499        if (mUseSplitCostQueue)
500        {
501                ConstructWithSplitQueue(polys, rays);
502        }
503        else
504        {
505                Construct(polys, rays);
506        }
507
508        // clean up polygons
509        CLEAR_CONTAINER(polys);
510}
511
512
513// TODO: return memory usage in MB
514float VspBspTree::GetMemUsage() const
515{
516        return (float)
517                 (sizeof(VspBspTree) +
518                  mBspStats.Leaves() * sizeof(BspLeaf) +
519                  mCreatedViewCells * sizeof(BspViewCell) +
520                  mBspStats.pvs * sizeof(PvsData) +
521                  mBspStats.Interior() * sizeof(BspInterior) +
522                  mBspStats.accumRays * sizeof(RayInfo)) / (1024.0f * 1024.0f);
523}
524
525
526void VspBspTree::Construct(const PolygonContainer &polys, RayInfoContainer *rays)
527{
528        VspBspTraversalQueue tQueue;
529
530        /// create new vsp tree
531        mRoot = new BspLeaf();
532
533        // constrruct root node geometry
534        BspNodeGeometry *geom = new BspNodeGeometry();
535        ConstructGeometry(mRoot, *geom);
536
537        /// we use the overall probability as normalizer
538        /// either the overall area or the volume
539        const float prop = mUseAreaForPvs ? geom->GetArea() : geom->GetVolume();
540
541        /// first traversal data
542        VspBspTraversalData tData(mRoot,
543                                                          new PolygonContainer(polys),
544                                                          0,
545                                                          rays,
546                              ComputePvsSize(*rays),
547                                                          prop,
548                                                          geom);
549
550        // evaluate the priority of this traversal data
551        EvalPriority(tData);
552
553        // first node is kd node, i.e. an axis aligned box
554        if (1)
555        tData.mIsKdNode = true;
556        else
557                tData.mIsKdNode = false;
558
559        tQueue.push(tData);
560
561
562        mTotalCost = tData.mPvs * tData.mProbability / mBoundingBox.GetVolume();
563        mTotalPvsSize = tData.mPvs;
564       
565        // first subdivison statistics
566        AddSubdivisionStats(1, 0, 0, mTotalCost, (float)mTotalPvsSize);
567   
568        mBspStats.Start();
569        cout << "Constructing vsp bsp tree ... \n";
570
571        const long startTime = GetTime();       
572        // used for intermediate time measurements and progress
573        long interTime = GetTime();
574
575        int nLeaves = 500;
576        int nViewCells = 500;
577
578        mOutOfMemory = false;
579        mCreatedViewCells = 0;
580       
581        while (!tQueue.empty())
582        {
583                tData = tQueue.top();
584            tQueue.pop();               
585
586                if (0 && !mOutOfMemory)
587                {
588                        float mem = GetMemUsage();
589
590                        if (mem > mMaxMemory)
591                        {
592                                mOutOfMemory = true;
593                                Debug << "memory limit reached: " << mem << endl;
594                        }
595                }
596
597                // subdivide leaf node
598                const BspNode *r = Subdivide(tQueue, tData);
599
600                if (r == mRoot)
601                        Debug << "VSP BSP tree construction time spent at root: "
602                                  << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
603
604                if (mBspStats.Leaves() >= nLeaves)
605                {
606                        nLeaves += 500;
607
608                        cout << "leaves=" << mBspStats.Leaves() << endl;
609                        Debug << "needed "
610                                  << TimeDiff(interTime, GetTime())*1e-3
611                                  << " secs to create 500 view cells" << endl;
612                        interTime = GetTime();
613                }
614
615                if (mCreatedViewCells >= nViewCells)
616                {
617                        nViewCells += 500;
618
619                        cout << "generated " << mCreatedViewCells << " viewcells" << endl;
620                }
621        }
622
623        Debug << "Used Memory: " << GetMemUsage() << " MB" << endl << endl;
624        cout << "finished in " << TimeDiff(startTime, GetTime())*1e-3 << "secs" << endl;
625
626        mBspStats.Stop();
627}
628
629
630
631void VspBspTree::ConstructWithSplitQueue(const PolygonContainer &polys,
632                                                                                          RayInfoContainer *rays)
633{
634        VspBspSplitQueue tQueue;
635
636        mRoot = new BspLeaf();
637
638        // constrruct root node geometry
639        BspNodeGeometry *geom = new BspNodeGeometry();
640        ConstructGeometry(mRoot, *geom);
641
642        const float prop = mUseAreaForPvs ? geom->GetArea() : geom->GetVolume();
643
644        VspBspTraversalData tData(mRoot,
645                                                          new PolygonContainer(polys),
646                                                          0,
647                                                          rays,
648                              ComputePvsSize(*rays),
649                                                          prop,
650                                                          geom);
651
652
653        // first node is kd node, i.e. an axis aligned box
654        if (1)
655        tData.mIsKdNode = true;
656        else
657                tData.mIsKdNode = false;
658
659        // compute first split candidate
660        VspBspSubdivisionCandidate splitCandidate;
661        splitCandidate.mParentData = tData;
662
663        EvalSubdivisionCandidate(splitCandidate);
664
665        tQueue.push(splitCandidate);
666
667        mTotalCost = tData.mPvs * tData.mProbability / mBoundingBox.GetVolume();
668        mTotalPvsSize = tData.mPvs;
669       
670        // first subdivison statistics
671        AddSubdivisionStats(1, 0, 0, mTotalCost, (float)mTotalPvsSize);
672   
673    mBspStats.Start();
674        cout << "Constructing vsp bsp tree ... \n";
675
676        long startTime = GetTime();     
677        int nLeaves = 500;
678        int nViewCells = 500;
679
680        // used for intermediate time measurements and progress
681        long interTime = GetTime();     
682
683        mOutOfMemory = false;
684
685        mCreatedViewCells = 0;
686       
687        while (!tQueue.empty())
688        {
689                splitCandidate = tQueue.top();
690            tQueue.pop();               
691
692                // cost ratio of cost decrease / totalCost
693                float costRatio = splitCandidate.mRenderCostDecr / mTotalCost;
694
695                //Debug << "cost ratio: " << costRatio << endl;
696                if (costRatio < mTermMinGlobalCostRatio)
697                {
698                        ++ mBspStats.mGlobalCostMisses;
699                }
700
701                if (0 && !mOutOfMemory)
702                {
703                        float mem = GetMemUsage();
704                        if (mem > mMaxMemory)
705                        {
706                                mOutOfMemory = true;
707                                Debug << "memory limit reached: " << mem << endl;
708                        }
709                }
710
711                // subdivide leaf node
712                BspNode *r = Subdivide(tQueue, splitCandidate);
713
714                if (r == mRoot)
715                {
716                        Debug << "VSP BSP tree construction time spent at root: "
717                                  << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
718                }
719
720                if (mBspStats.Leaves() >= nLeaves)
721                {
722                        nLeaves += 500;
723
724                        cout << "leaves=" << mBspStats.Leaves() << endl;
725                        Debug << "needed "
726                                  << TimeDiff(interTime, GetTime())*1e-3
727                                  << " secs to create 500 view cells" << endl;
728                        interTime = GetTime();
729                }
730
731                if (mCreatedViewCells == nViewCells)
732                {
733                        nViewCells += 500;
734                        cout << "generated " << mCreatedViewCells << " viewcells" << endl;
735                }
736        }
737
738        Debug << "Used Memory: " << GetMemUsage() << " MB" << endl << endl;
739        cout << "finished\n";
740
741        mBspStats.Stop();
742}
743
744
745bool VspBspTree::LocalTerminationCriteriaMet(const VspBspTraversalData &data) const
746{
747        return
748                (((int)data.mRays->size() <= mTermMinRays) ||
749                 (data.mPvs <= mTermMinPvs)   ||
750                 (data.mProbability <= mTermMinProbability) ||
751                 (data.GetAvgRayContribution() > mTermMaxRayContribution) ||
752                 (data.mDepth >= mTermMaxDepth));
753}
754
755
756void VspBspTree::AddSubdivisionStats(const int viewCells,
757                                                                         const float renderCostDecr,
758                                                                         const float splitCandidateCost,
759                                                                         const float totalRenderCost,
760                                                                         const float avgRenderCost)
761{
762        mSubdivisionStats
763                        << "#ViewCells\n" << viewCells << endl
764                        << "#RenderCostDecrease\n" << renderCostDecr << endl
765                        << "#SubdivisionCandidateCost\n" << splitCandidateCost << endl
766                        << "#TotalRenderCost\n" << totalRenderCost << endl
767                        << "#AvgRenderCost\n" << avgRenderCost << endl;
768}
769
770
771bool VspBspTree::GlobalTerminationCriteriaMet(const VspBspTraversalData &data) const
772{
773        return
774                (0
775                || mOutOfMemory
776                || (mBspStats.Leaves() >= mMaxViewCells)
777                || (mBspStats.mGlobalCostMisses >= mTermGlobalCostMissTolerance)
778                 );
779}
780
781
782BspNode *VspBspTree::Subdivide(VspBspTraversalQueue &tQueue,
783                                                           VspBspTraversalData &tData)
784{
785        BspNode *newNode = tData.mNode;
786
787        if (!LocalTerminationCriteriaMet(tData) && !GlobalTerminationCriteriaMet(tData))
788        {
789                PolygonContainer coincident;
790
791                VspBspTraversalData tFrontData;
792                VspBspTraversalData tBackData;
793
794                // create new interior node and two leaf nodes
795                // or return leaf as it is (if maxCostRatio missed)
796                int splitAxis;
797                bool splitFurther = true;
798                int maxCostMisses = tData.mMaxCostMisses;
799               
800                Plane3 splitPlane;
801                BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
802               
803                // choose next split plane
804                if (!SelectPlane(splitPlane, leaf, tData, tFrontData, tBackData, splitAxis))
805                {
806                        ++ maxCostMisses;
807
808                        if (maxCostMisses > mTermMissTolerance)
809                        {
810                                // terminate branch because of max cost
811                                ++ mBspStats.maxCostNodes;
812                                splitFurther = false;
813                        }
814                }
815       
816                // if this a valid split => subdivide this node further
817
818                if (splitFurther)
819                {
820                        newNode = SubdivideNode(splitPlane, tData, tFrontData, tBackData, coincident);
821
822                        if (splitAxis < 3)
823                                ++ mBspStats.splits[splitAxis];
824                        else
825                                ++ mBspStats.polySplits;
826
827                        // if it was a kd node (i.e., a box) and the split axis is axis aligned, it is still a kd node
828                        tFrontData.mIsKdNode = tBackData.mIsKdNode = (tData.mIsKdNode && (splitAxis < 3));
829                       
830                        tFrontData.mAxis = tBackData.mAxis = splitAxis;
831
832                        // how often was max cost ratio missed in this branch?
833                        tFrontData.mMaxCostMisses = maxCostMisses;
834                        tBackData.mMaxCostMisses = maxCostMisses;
835
836                        EvalPriority(tFrontData);
837                        EvalPriority(tBackData);
838
839                        // evaluate subdivision stats
840                        if (1)
841                                EvalSubdivisionStats(tData, tFrontData, tBackData);
842                       
843
844                        // push the children on the stack
845                        tQueue.push(tFrontData);
846                        tQueue.push(tBackData);
847
848                        // delete old leaf node
849                        DEL_PTR(tData.mNode);
850                }
851        }
852
853        //-- terminate traversal and create new view cell
854        if (newNode->IsLeaf())
855        {
856                BspLeaf *leaf = dynamic_cast<BspLeaf *>(newNode);
857               
858                BspViewCell *viewCell = new BspViewCell();
859                leaf->SetViewCell(viewCell);
860       
861                //-- update pvs
862                int conSamp = 0;
863                float sampCon = 0.0f;
864                AddToPvs(leaf, *tData.mRays, sampCon, conSamp);
865
866                // update scalar pvs size lookup
867                ObjectPvs &pvs = viewCell->GetPvs();
868                mViewCellsManager->UpdateScalarPvsSize(viewCell, pvs.CountObjectsInPvs(), pvs.GetSize());
869       
870
871                mBspStats.contributingSamples += conSamp;
872                mBspStats.sampleContributions += (int)sampCon;
873
874                //-- store additional info
875                if (mStoreRays)
876                {
877                        RayInfoContainer::const_iterator it, it_end = tData.mRays->end();
878                        for (it = tData.mRays->begin(); it != it_end; ++ it)
879                        {
880                                (*it).mRay->Ref();                     
881                                leaf->mVssRays.push_back((*it).mRay);
882                        }
883                }
884
885                // should I check here?
886                if (0 && !mViewCellsManager->CheckValidity(viewCell, 0,
887                        mViewCellsManager->GetMaxPvsSize()))
888                {
889                        viewCell->SetValid(false);
890                        leaf->SetTreeValid(false);
891                        PropagateUpValidity(leaf);
892
893                        ++ mBspStats.invalidLeaves;
894                }
895               
896                viewCell->mLeaves.push_back(leaf);
897
898                if (mUseAreaForPvs)
899                        viewCell->SetArea(tData.mProbability);
900                else
901                        viewCell->SetVolume(tData.mProbability);
902
903                leaf->mProbability = tData.mProbability;
904
905                // finally evaluate stats until this leaf
906                if (0)
907                        EvaluateLeafStats(tData);               
908        }
909
910        //-- cleanup
911        tData.Clear();
912
913        return newNode;
914}
915
916
917// subdivide node using a split plane queue
918BspNode *VspBspTree::Subdivide(VspBspSplitQueue &tQueue,
919                                                           VspBspSubdivisionCandidate &splitCandidate)
920{
921        VspBspTraversalData &tData = splitCandidate.mParentData;
922
923        BspNode *newNode = tData.mNode;
924
925        if (!LocalTerminationCriteriaMet(tData) && !GlobalTerminationCriteriaMet(tData))
926        {       
927                PolygonContainer coincident;
928
929                VspBspTraversalData tFrontData;
930                VspBspTraversalData tBackData;
931
932                //-- continue subdivision
933               
934                // create new interior node and two leaf node
935                const Plane3 splitPlane = splitCandidate.mSplitPlane;
936                               
937                newNode = SubdivideNode(splitPlane, tData, tFrontData, tBackData, coincident);
938       
939                const int splitAxis = splitCandidate.mSplitAxis;
940                const int maxCostMisses = splitCandidate.mMaxCostMisses;
941
942                if (splitAxis < 3)
943                        ++ mBspStats.splits[splitAxis];
944                else
945                        ++ mBspStats.polySplits;
946
947                tFrontData.mIsKdNode = tBackData.mIsKdNode = (tData.mIsKdNode && (splitAxis < 3));
948                tFrontData.mAxis = tBackData.mAxis = splitAxis;
949
950                // how often was max cost ratio missed in this branch?
951                tFrontData.mMaxCostMisses = maxCostMisses;
952                tBackData.mMaxCostMisses = maxCostMisses;
953                       
954                // statistics
955                if (1)
956                {
957                        float cFront = (float)tFrontData.mPvs * tFrontData.mProbability;
958                        float cBack = (float)tBackData.mPvs * tBackData.mProbability;
959                        float cData = (float)tData.mPvs * tData.mProbability;
960
961                       
962                        float costDecr =
963                                (cFront + cBack - cData) / mBoundingBox.GetVolume();
964
965                        mTotalCost += costDecr;
966                        mTotalPvsSize += tFrontData.mPvs + tBackData.mPvs - tData.mPvs;
967
968                        AddSubdivisionStats(mBspStats.Leaves(),
969                                                                -costDecr, 
970                                                                splitCandidate.GetPriority(),
971                                                                mTotalCost,
972                                                                (float)mTotalPvsSize / (float)mBspStats.Leaves());
973                }
974
975       
976                //-- push the new split candidates on the stack
977                VspBspSubdivisionCandidate frontCandidate;
978                frontCandidate.mParentData = tFrontData;
979
980                VspBspSubdivisionCandidate backCandidate;
981                backCandidate.mParentData = tBackData;
982
983                EvalSubdivisionCandidate(frontCandidate);
984                EvalSubdivisionCandidate(backCandidate);
985       
986                tQueue.push(frontCandidate);
987                tQueue.push(backCandidate);
988       
989                // delete old leaf node
990                DEL_PTR(tData.mNode);
991        }
992
993
994        //////////////////
995        //-- terminate traversal and create new view cell
996        if (newNode->IsLeaf())
997        {
998                BspLeaf *leaf = dynamic_cast<BspLeaf *>(newNode);
999
1000                BspViewCell *viewCell = new BspViewCell();
1001        leaf->SetViewCell(viewCell);
1002               
1003                //-- update pvs
1004                int conSamp = 0;
1005                float sampCon = 0.0f;
1006                AddToPvs(leaf, *tData.mRays, sampCon, conSamp);
1007
1008                // update scalar pvs size value
1009                ObjectPvs &pvs = viewCell->GetPvs();
1010                mViewCellsManager->UpdateScalarPvsSize(viewCell, pvs.CountObjectsInPvs(), pvs.GetSize());
1011
1012                mBspStats.contributingSamples += conSamp;
1013                mBspStats.sampleContributions +=(int) sampCon;
1014
1015                viewCell->mLeaves.push_back(leaf);
1016
1017                ///////////
1018                //-- store additional info
1019                if (mStoreRays)
1020                {
1021                        RayInfoContainer::const_iterator it, it_end = tData.mRays->end();
1022                        for (it = tData.mRays->begin(); it != it_end; ++ it)
1023                        {
1024                                (*it).mRay->Ref();                     
1025                                leaf->mVssRays.push_back((*it).mRay);
1026                        }
1027                }
1028       
1029                if (mUseAreaForPvs)
1030                        viewCell->SetArea(tData.mProbability);
1031                else
1032                        viewCell->SetVolume(tData.mProbability);
1033
1034        leaf->mProbability = tData.mProbability;
1035
1036                // finally evaluate stats until this leaf
1037                if (0)
1038                        EvaluateLeafStats(tData);               
1039        }
1040
1041        //-- cleanup
1042        tData.Clear();
1043
1044        return newNode;
1045}
1046
1047
1048void VspBspTree::EvalPriority(VspBspTraversalData &tData) const
1049{
1050    switch (mNodePriorityQueueType)
1051        {
1052        case BREATH_FIRST:
1053                tData.mPriority = (float)-tData.mDepth;
1054                break;
1055        case DEPTH_FIRST:
1056                tData.mPriority = (float)tData.mDepth;
1057                break;
1058        default:
1059                tData.mPriority = tData.mPvs * tData.mProbability;
1060                //Debug << "priority: " << tData.mPriority << endl;
1061                break;
1062        }
1063}
1064
1065
1066void VspBspTree::EvalSubdivisionCandidate(VspBspSubdivisionCandidate &splitCandidate)
1067{
1068        VspBspTraversalData frontData;
1069        VspBspTraversalData backData;
1070       
1071        BspLeaf *leaf = dynamic_cast<BspLeaf *>(splitCandidate.mParentData.mNode);
1072       
1073        // compute locally best split plane
1074    const bool costRatioViolated =
1075                SelectPlane(splitCandidate.mSplitPlane,
1076                                        leaf,
1077                                        splitCandidate.mParentData,
1078                                        frontData,
1079                                        backData,
1080                                        splitCandidate.mSplitAxis);
1081
1082        // max cost threshold violated?
1083        splitCandidate.mMaxCostMisses = costRatioViolated ?
1084                splitCandidate.mParentData.mMaxCostMisses :
1085                splitCandidate.mParentData.mMaxCostMisses + 1;
1086
1087        float oldRenderCost;
1088
1089        // compute global decrease in render cost
1090        const float renderCostDecr = EvalRenderCostDecrease(splitCandidate.mSplitPlane,
1091                                                                                                                splitCandidate.mParentData,
1092                                                                                                                oldRenderCost);
1093
1094        splitCandidate.mRenderCostDecr = renderCostDecr;
1095
1096        // TODO: geometry could be reused
1097        delete frontData.mGeometry;
1098        delete backData.mGeometry;
1099
1100        // set priority for queue
1101#if 0
1102        const float priority = (float)-data.mDepth;
1103#else   
1104
1105        // take render cost of node into account
1106        // otherwise danger of being stuck in a local minimum!!
1107        const float factor = mRenderCostDecreaseWeight;
1108        const float priority = factor * renderCostDecr + (1.0f - factor) * oldRenderCost;
1109#endif
1110       
1111        splitCandidate.mPriority = priority;
1112}
1113
1114
1115void VspBspTree::EvalSubdivisionStats(const VspBspTraversalData &tData,
1116                                                                          const VspBspTraversalData &tFrontData,
1117                                                                          const VspBspTraversalData &tBackData)
1118{
1119        const float cFront = (float)tFrontData.mPvs * tFrontData.mProbability;
1120        const float cBack = (float)tBackData.mPvs * tBackData.mProbability;
1121        const float cData = (float)tData.mPvs * tData.mProbability;
1122       
1123        const float costDecr =
1124                (cFront + cBack - cData) / mBoundingBox.GetVolume();
1125
1126        mTotalCost += costDecr;
1127        mTotalPvsSize += tFrontData.mPvs + tBackData.mPvs - tData.mPvs;
1128
1129        AddSubdivisionStats(mBspStats.Leaves(),
1130                                                -costDecr,
1131                                                0,
1132                                                mTotalCost,
1133                                                (float)mTotalPvsSize / (float)mBspStats.Leaves());
1134}
1135
1136
1137BspInterior *VspBspTree::SubdivideNode(const Plane3 &splitPlane,
1138                                                                           VspBspTraversalData &tData,
1139                                                                           VspBspTraversalData &frontData,
1140                                                                           VspBspTraversalData &backData,
1141                                                                           PolygonContainer &coincident)
1142{
1143        BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
1144       
1145        //-- the front and back traversal data is filled with the new values
1146        frontData.mDepth = tData.mDepth + 1;
1147        frontData.mPolygons = new PolygonContainer();
1148        frontData.mRays = new RayInfoContainer();
1149       
1150        backData.mDepth = tData.mDepth + 1;
1151        backData.mPolygons = new PolygonContainer();
1152        backData.mRays = new RayInfoContainer();
1153       
1154
1155        //-- subdivide rays
1156        SplitRays(splitPlane,
1157                          *tData.mRays,
1158                          *frontData.mRays,
1159                          *backData.mRays);
1160
1161
1162        // compute pvs
1163        frontData.mPvs = ComputePvsSize(*frontData.mRays);
1164        backData.mPvs = ComputePvsSize(*backData.mRays);
1165
1166        // split front and back node geometry and compute area
1167       
1168        // if geometry was not already computed
1169        if (!frontData.mGeometry && !backData.mGeometry)
1170        {
1171                frontData.mGeometry = new BspNodeGeometry();
1172                backData.mGeometry = new BspNodeGeometry();
1173
1174                tData.mGeometry->SplitGeometry(*frontData.mGeometry,
1175                                                                           *backData.mGeometry,
1176                                                                           splitPlane,
1177                                                                           mBoundingBox,
1178                                                                           //0.0f);
1179                                                                           mEpsilon);
1180               
1181                if (mUseAreaForPvs)
1182                {
1183                        frontData.mProbability = frontData.mGeometry->GetArea();
1184                        backData.mProbability = backData.mGeometry->GetArea();
1185                }
1186                else
1187                {
1188                        frontData.mProbability = frontData.mGeometry->GetVolume();
1189                        backData.mProbability = tData.mProbability - frontData.mProbability;
1190
1191                        // should never come here: wrong volume !!!
1192                        if (0)
1193                        {
1194                                if (frontData.mProbability < -0.00001)
1195                                        Debug << "fatal error f: " << frontData.mProbability << endl;
1196                                if (backData.mProbability < -0.00001)
1197                                        Debug << "fatal error b: " << backData.mProbability << endl;
1198
1199                                // clamp because of precision issues
1200                                if (frontData.mProbability < 0) frontData.mProbability = 0;
1201                                if (backData.mProbability < 0) backData.mProbability = 0;
1202                        }
1203                }
1204        }
1205
1206       
1207    // subdivide polygons
1208        SplitPolygons(splitPlane,
1209                                  *tData.mPolygons,
1210                      *frontData.mPolygons,
1211                                  *backData.mPolygons,
1212                                  coincident);
1213
1214
1215
1216        ///////////////////////////////////////
1217        // subdivide further
1218
1219        // store maximal and minimal depth
1220        if (tData.mDepth > mBspStats.maxDepth)
1221        {
1222                Debug << "max depth increases to " << tData.mDepth << " at " << mBspStats.Leaves() << " leaves" << endl;
1223                mBspStats.maxDepth = tData.mDepth;
1224        }
1225
1226        mBspStats.nodes += 2;
1227
1228   
1229        BspInterior *interior = new BspInterior(splitPlane);
1230
1231#ifdef _DEBUG
1232        Debug << interior << endl;
1233#endif
1234
1235
1236        //-- create front and back leaf
1237
1238        BspInterior *parent = leaf->GetParent();
1239
1240        // replace a link from node's parent
1241        if (parent)
1242        {
1243                parent->ReplaceChildLink(leaf, interior);
1244                interior->SetParent(parent);
1245        }
1246        else // new root
1247        {
1248                mRoot = interior;
1249        }
1250
1251        // and setup child links
1252        interior->SetupChildLinks(new BspLeaf(interior), new BspLeaf(interior));
1253
1254        frontData.mNode = interior->GetFront();
1255        backData.mNode = interior->GetBack();
1256
1257        interior->mTimeStamp = mTimeStamp ++;
1258       
1259
1260        //DEL_PTR(leaf);
1261        return interior;
1262}
1263
1264
1265void VspBspTree::AddToPvs(BspLeaf *leaf,
1266                                                  const RayInfoContainer &rays,
1267                                                  float &sampleContributions,
1268                                                  int &contributingSamples)
1269{
1270        sampleContributions = 0;
1271        contributingSamples = 0;
1272 
1273        RayInfoContainer::const_iterator it, it_end = rays.end();
1274 
1275        ViewCellLeaf *vc = leaf->GetViewCell();
1276 
1277        // add contributions from samples to the PVS
1278        for (it = rays.begin(); it != it_end; ++ it)
1279        {
1280                float sc = 0.0f;
1281                VssRay *ray = (*it).mRay;
1282
1283                bool madeContrib = false;
1284                float contribution;
1285
1286                if (ray->mTerminationObject)
1287                {
1288                        if (vc->AddPvsSample(ray->mTerminationObject, ray->mPdf, contribution))
1289                                madeContrib = true;
1290                        sc += contribution;
1291                }
1292         
1293                // only count termination objects?
1294                if (COUNT_ORIGIN_OBJECTS && ray->mOriginObject)
1295                {
1296                        if (vc->AddPvsSample(ray->mOriginObject, ray->mPdf, contribution))
1297                                madeContrib = true;
1298
1299                        sc += contribution;
1300                }
1301               
1302                sampleContributions += sc;
1303               
1304                if (madeContrib)
1305                        ++ contributingSamples;
1306        }
1307}
1308
1309
1310void VspBspTree::SortSubdivisionCandidates(const RayInfoContainer &rays,
1311                                                                         const int axis,
1312                                                                         float minBand,
1313                                                                         float maxBand)
1314{
1315        mLocalSubdivisionCandidates->clear();
1316
1317        int requestedSize = 2 * (int)(rays.size());
1318        // creates a sorted split candidates array
1319        if (mLocalSubdivisionCandidates->capacity() > 500000 &&
1320                requestedSize < (int)(mLocalSubdivisionCandidates->capacity() / 10) )
1321        {
1322        delete mLocalSubdivisionCandidates;
1323                mLocalSubdivisionCandidates = new vector<SortableEntry>;
1324        }
1325
1326        mLocalSubdivisionCandidates->reserve(requestedSize);
1327
1328        if (0)
1329        {       // float values => don't compare with exact values
1330                minBand += Limits::Small;
1331                maxBand -= Limits::Small;
1332        }
1333
1334        // insert all queries
1335        for (RayInfoContainer::const_iterator ri = rays.begin(); ri < rays.end(); ++ ri)
1336        {
1337                const bool positive = (*ri).mRay->HasPosDir(axis);
1338                float pos = (*ri).ExtrapOrigin(axis);
1339
1340                // clamp to min / max band
1341                if (0) ClipValue(pos, minBand, maxBand);
1342               
1343                mLocalSubdivisionCandidates->push_back(SortableEntry(positive ? SortableEntry::ERayMin : SortableEntry::ERayMax,
1344                                                                        pos, (*ri).mRay));
1345
1346                pos = (*ri).ExtrapTermination(axis);
1347
1348                // clamp to min / max band
1349                if (0) ClipValue(pos, minBand, maxBand);
1350
1351                mLocalSubdivisionCandidates->push_back(SortableEntry(positive ? SortableEntry::ERayMax : SortableEntry::ERayMin,
1352                                                                        pos, (*ri).mRay));
1353        }
1354
1355        stable_sort(mLocalSubdivisionCandidates->begin(), mLocalSubdivisionCandidates->end());
1356}
1357
1358
1359float VspBspTree::BestCostRatioHeuristics(const RayInfoContainer &rays,
1360                                                                                  const AxisAlignedBox3 &box,
1361                                                                                  const int pvsSize,
1362                                                                                  const int axis,
1363                                          float &position)
1364{
1365        RayInfoContainer usedRays;
1366
1367        if (mMaxTests < rays.size())
1368        {
1369                GetRayInfoSets(rays, mMaxTests, usedRays);
1370        }
1371        else
1372        {
1373                usedRays = rays;
1374        }
1375
1376        const float minBox = box.Min(axis);
1377        const float maxBox = box.Max(axis);
1378
1379        const float sizeBox = maxBox - minBox;
1380
1381        const float minBand = minBox + mMinBand * sizeBox;
1382        const float maxBand = minBox + mMaxBand * sizeBox;
1383
1384        SortSubdivisionCandidates(usedRays, axis, minBand, maxBand);
1385
1386        //////////////////
1387        // go through the lists, count the number of objects left and right
1388        // and evaluate the following cost funcion:
1389        // C = ct_div_ci  + (ql*rl + qr*rr)/queries
1390
1391        int pvsl = 0;
1392        int pvsr = pvsSize;
1393
1394        int pvsBack = pvsl;
1395        int pvsFront = pvsr;
1396
1397        float sum = (float)pvsSize * sizeBox;
1398        float minSum = 1e20f;
1399       
1400        // if no border can be found, take mid split
1401        position = minBox + 0.5f * sizeBox;
1402       
1403        // the relative cost ratio
1404        float ratio = 99999999.0f;
1405        bool splitPlaneFound = false;
1406
1407        Intersectable::NewMail();
1408        RayInfoContainer::const_iterator ri, ri_end = usedRays.end();
1409
1410        // set all object as belonging to the front pvs
1411        for(ri = usedRays.begin(); ri != ri_end; ++ ri)
1412        {
1413                Intersectable *oObject = (*ri).mRay->mOriginObject;
1414                Intersectable *tObject = (*ri).mRay->mTerminationObject;
1415
1416                if (COUNT_ORIGIN_OBJECTS && oObject)
1417                {
1418                        if (!oObject->Mailed())
1419                        {
1420                                oObject->Mail();
1421                                oObject->mCounter = 1;
1422                        }
1423                        else
1424                        {
1425                                ++ oObject->mCounter;
1426                        }
1427                }
1428
1429                if (tObject)
1430                {
1431                        if (!tObject->Mailed())
1432                        {
1433                                tObject->Mail();
1434                                tObject->mCounter = 1;
1435                        }
1436                        else
1437                        {
1438                                ++ tObject->mCounter;
1439                        }
1440                }
1441        }
1442
1443        Intersectable::NewMail();
1444        vector<SortableEntry>::const_iterator ci, ci_end = mLocalSubdivisionCandidates->end();
1445
1446        for (ci = mLocalSubdivisionCandidates->begin(); ci != ci_end; ++ ci)
1447        {
1448                VssRay *ray;
1449                ray = (*ci).ray;
1450               
1451                Intersectable *oObject = ray->mOriginObject;
1452                Intersectable *tObject = ray->mTerminationObject;
1453               
1454                switch ((*ci).type)
1455                {
1456                        case SortableEntry::ERayMin:
1457                                {
1458                                        if (COUNT_ORIGIN_OBJECTS && oObject && !oObject->Mailed())
1459                                        {
1460                                                oObject->Mail();
1461                                                ++ pvsl;
1462                                        }
1463
1464                                        if (tObject && !tObject->Mailed())
1465                                        {
1466                                                tObject->Mail();
1467                                                ++ pvsl;
1468                                        }
1469
1470                                        break;
1471                                }
1472                        case SortableEntry::ERayMax:
1473                                {
1474                                        if (COUNT_ORIGIN_OBJECTS && oObject)
1475                                        {
1476                                                if (-- oObject->mCounter == 0)
1477                                                        -- pvsr;
1478                                        }
1479
1480                                        if (tObject)
1481                                        {
1482                                                if (-- tObject->mCounter == 0)
1483                                                        -- pvsr;
1484                                        }
1485
1486                                        break;
1487                                }
1488                }
1489               
1490               
1491                // Note: we compare size of bounding boxes of front and back side because
1492                // of efficiency reasons (otherwise a new geometry would have to be computed
1493                // in each step and incremential evaluation would be difficult.
1494                // but then errors happen if the geometry is not an axis aligned box
1495                // (i.e., if a geometry aligned split was taken before)
1496                // question: is it sufficient to make this approximation?
1497                if (((*ci).value >= minBand) && ((*ci).value <= maxBand))
1498                {
1499                        sum = pvsl * ((*ci).value - minBox) + pvsr * (maxBox - (*ci).value);
1500
1501                        float currentPos;
1502                       
1503                        // HACK: current positition is BETWEEN visibility events
1504                        if (0 && ((ci + 1) != ci_end))
1505                        {
1506                                currentPos = ((*ci).value + (*(ci + 1)).value) * 0.5f;
1507                        }
1508                        else
1509                currentPos = (*ci).value;                       
1510
1511                        //Debug  << "pos=" << (*ci).value << "\t pvs=(" <<  pvsl << "," << pvsr << ")" << endl;
1512                        //Debug << "cost= " << sum << endl;
1513
1514                        if (sum < minSum)
1515                        {
1516                                splitPlaneFound = true;
1517
1518                                minSum = sum;
1519                                position = currentPos;
1520                               
1521                                pvsBack = pvsl;
1522                                pvsFront = pvsr;
1523                        }
1524                }
1525        }
1526       
1527        // -- compute cost
1528        const int lowerPvsLimit = mViewCellsManager->GetMinPvsSize();
1529        const int upperPvsLimit = mViewCellsManager->GetMaxPvsSize();
1530
1531        const float pOverall = sizeBox;
1532
1533        const float pBack = position - minBox;
1534        const float pFront = maxBox - position;
1535       
1536        const float penaltyOld = EvalPvsPenalty(pvsSize, lowerPvsLimit, upperPvsLimit);
1537    const float penaltyFront = EvalPvsPenalty(pvsFront, lowerPvsLimit, upperPvsLimit);
1538        const float penaltyBack = EvalPvsPenalty(pvsBack, lowerPvsLimit, upperPvsLimit);
1539       
1540        const float oldRenderCost = penaltyOld * pOverall;
1541        const float newRenderCost = penaltyFront * pFront + penaltyBack * pBack;
1542
1543        if (splitPlaneFound)
1544        {
1545                ratio = mPvsFactor * newRenderCost / (oldRenderCost + Limits::Small);
1546        }
1547        //if (axis != 1)
1548        //Debug << "axis=" << axis << " costRatio=" << ratio << " pos=" << position << " t=" << (position - minBox) / (maxBox - minBox)
1549         //    <<"\t pb=(" << pvsBack << ")\t pf=(" << pvsFront << ")" << endl;
1550
1551        return ratio;
1552}
1553
1554
1555float VspBspTree::SelectAxisAlignedPlane(Plane3 &plane,
1556                                                                                 const VspBspTraversalData &tData,
1557                                                                                 int &axis,
1558                                                                                 BspNodeGeometry **frontGeom,
1559                                                                                 BspNodeGeometry **backGeom,
1560                                                                                 float &pFront,
1561                                                                                 float &pBack,
1562                                                                                 const bool isKdNode)
1563{
1564        float nPosition[3];
1565        float nCostRatio[3];
1566        float nProbFront[3];
1567        float nProbBack[3];
1568
1569        BspNodeGeometry *nFrontGeom[3];
1570        BspNodeGeometry *nBackGeom[3];
1571
1572        // set to NULL, so I can find out which gemetry was stored
1573        for (int i = 0; i < 3; ++ i)
1574        {
1575                nFrontGeom[i] = NULL;
1576                nBackGeom[i] = NULL;
1577        }
1578
1579        // create bounding box of node geometry
1580        AxisAlignedBox3 box;
1581               
1582        //TODO: for kd split geometry already is box => only take minmax vertices
1583        if (1)
1584        {       // get bounding box from geometry
1585                tData.mGeometry->GetBoundingBox(box);
1586        }
1587        else
1588        {
1589                box.Initialize();
1590                RayInfoContainer::const_iterator ri, ri_end = tData.mRays->end();
1591
1592                for(ri = tData.mRays->begin(); ri < ri_end; ++ ri)
1593                        box.Include((*ri).ExtrapTermination());
1594        }
1595
1596
1597        int sAxis = 0;
1598        int bestAxis;
1599
1600        // if max cost ratio is exceeded, take split along longest axis instead
1601        const float maxCostRatioForArbitraryAxis = 0.9f;
1602
1603        if (mUseDrivingAxisIfMaxCostViolated)
1604                bestAxis = box.Size().DrivingAxis();
1605        else
1606                bestAxis = -1;
1607
1608#if 0
1609        // maximum cost ratio for axis to be valid:
1610        // if exceeded, spatial mid split is used instead
1611        const maxCostRatioForHeur = 0.99f;
1612#endif
1613
1614        // if we use some kind of specialised fixed axis
1615    const bool useSpecialAxis =
1616                mOnlyDrivingAxis || mUseRandomAxis || mCirculatingAxis;
1617
1618        if (mUseRandomAxis)
1619                sAxis = Random(3);
1620        else if (mCirculatingAxis)
1621                sAxis = (tData.mAxis + 1) % 3;
1622        else if (mOnlyDrivingAxis)
1623                sAxis = box.Size().DrivingAxis();
1624
1625               
1626        //Debug << "use special axis: " << useSpecialAxis << endl;
1627        //Debug << "axis: " << sAxis << " drivingaxis: " << box.Size().DrivingAxis();
1628       
1629        for (axis = 0; axis < 3 ; ++ axis)
1630        {
1631                if (!useSpecialAxis || (axis == sAxis))
1632                {
1633                        if (mUseCostHeuristics)
1634                        {
1635                                //-- place split plane using heuristics
1636                                nCostRatio[axis] =
1637                                        BestCostRatioHeuristics(*tData.mRays,
1638                                                                                    box,
1639                                                                                        tData.mPvs,
1640                                                                                        axis,
1641                                                                                        nPosition[axis]);                       
1642                        }
1643                        else
1644                        {       //-- split plane position is spatial median
1645
1646                                nPosition[axis] = (box.Min()[axis] + box.Max()[axis]) * 0.5f;
1647                                Vector3 normal(0,0,0); normal[axis] = 1.0f;
1648                               
1649                                // allows faster split because we have axis aligned kd tree boxes
1650                                if (isKdNode)
1651                                {
1652                                        nCostRatio[axis] = EvalAxisAlignedSplitCost(tData,
1653                                                                                                                                box,
1654                                                                                                                                axis,
1655                                                                                                                                nPosition[axis],
1656                                                                                                                                nProbFront[axis],
1657                                                                                                                                nProbBack[axis]);
1658                                       
1659                                        Vector3 pos;
1660                                       
1661                                        // create back geometry from box
1662                                        // NOTE: the geometry is returned from the function so we
1663                                        // don't have to recompute it when possible
1664                                        pos = box.Max(); pos[axis] = nPosition[axis];
1665                                        AxisAlignedBox3 bBox(box.Min(), pos);
1666                                        PolygonContainer fPolys;
1667                                        bBox.ExtractPolys(fPolys);
1668
1669                                        nBackGeom[axis] = new BspNodeGeometry(fPolys);
1670       
1671                                        //-- create front geometry from box
1672                                        pos = box.Min(); pos[axis] = nPosition[axis];
1673                                        AxisAlignedBox3 fBox(pos, box.Max());
1674
1675                                        PolygonContainer bPolys;
1676                                        fBox.ExtractPolys(bPolys);
1677                                        nFrontGeom[axis] = new BspNodeGeometry(bPolys);
1678                                }
1679                                else
1680                                {
1681                                        nFrontGeom[axis] = new BspNodeGeometry();
1682                                        nBackGeom[axis] = new BspNodeGeometry();
1683
1684                                        nCostRatio[axis] =
1685                                                EvalSplitPlaneCost(Plane3(normal, nPosition[axis]),
1686                                                                                   tData, *nFrontGeom[axis], *nBackGeom[axis],
1687                                                                                   nProbFront[axis], nProbBack[axis]);
1688                                }
1689                        }
1690                                               
1691                       
1692                        if (mUseDrivingAxisIfMaxCostViolated)
1693                        {
1694                                // we take longest axis split if cost ratio exceeds threshold
1695                                if (nCostRatio[axis] < min(maxCostRatioForArbitraryAxis, nCostRatio[bestAxis]))
1696                                {
1697                                        bestAxis = axis;
1698                                }
1699                                /*else if (nCostRatio[axis] < nCostRatio[bestAxis])
1700                                {
1701                                        Debug << "taking split along longest axis (" << bestAxis << ") instead of  (" << axis << ")" << endl;
1702                                }*/
1703
1704                        }
1705                        else
1706                        {
1707                                if (bestAxis == -1)
1708                                {
1709                                        bestAxis = axis;
1710                                }
1711                                else if (nCostRatio[axis] < nCostRatio[bestAxis])
1712                                {
1713                                        bestAxis = axis;
1714                                }
1715                        }
1716                }
1717        }
1718
1719        //-- assign values
1720
1721        axis = bestAxis;
1722        pFront = nProbFront[bestAxis];
1723        pBack = nProbBack[bestAxis];
1724
1725        // assign best split nodes geometry
1726        *frontGeom = nFrontGeom[bestAxis];
1727        *backGeom = nBackGeom[bestAxis];
1728
1729        // and delete other geometry
1730        DEL_PTR(nFrontGeom[(bestAxis + 1) % 3]);
1731        DEL_PTR(nBackGeom[(bestAxis + 2) % 3]);
1732
1733        //-- split plane
1734    Vector3 normal(0,0,0); normal[bestAxis] = 1;
1735        plane = Plane3(normal, nPosition[bestAxis]);
1736
1737        //Debug << "best axis: " << bestAxis << " pos " << nPosition[bestAxis] << endl;
1738
1739        return nCostRatio[bestAxis];
1740}
1741
1742
1743bool VspBspTree::SelectPlane(Plane3 &bestPlane,
1744                                                         BspLeaf *leaf,
1745                                                         VspBspTraversalData &data,                                                     
1746                                                         VspBspTraversalData &frontData,
1747                                                         VspBspTraversalData &backData,
1748                                                         int &splitAxis)
1749{
1750        // HACK matt: subdivide regularily to certain depth
1751        if (data.mDepth < 0)    // question matt: why depth < 0 ?
1752        {
1753                cout << "depth: " << data.mDepth << endl;
1754
1755                // return axis aligned split
1756                AxisAlignedBox3 box;
1757                box.Initialize();
1758       
1759                // create bounding box of region
1760                data.mGeometry->GetBoundingBox(box);
1761       
1762                const int axis = box.Size().DrivingAxis();
1763                const Vector3 position = (box.Min()[axis] + box.Max()[axis]) * 0.5f;
1764
1765                Vector3 norm(0,0,0); norm[axis] = 1.0f;
1766                bestPlane = Plane3(norm, position);
1767                splitAxis = axis;
1768
1769                return true;
1770        }
1771
1772        // simplest strategy: just take next polygon
1773        if (mSplitPlaneStrategy & RANDOM_POLYGON)
1774        {
1775        if (!data.mPolygons->empty())
1776                {
1777                        const int randIdx =
1778                                (int)RandomValue(0, (Real)((int)data.mPolygons->size() - 1));
1779                        Polygon3 *nextPoly = (*data.mPolygons)[randIdx];
1780
1781                        bestPlane = nextPoly->GetSupportingPlane();
1782                        return true;
1783                }
1784        }
1785
1786        //-- use heuristics to find appropriate plane
1787
1788        // intermediate plane
1789        Plane3 plane;
1790        float lowestCost = MAX_FLOAT;
1791       
1792        // decides if the first few splits should be only axisAligned
1793        const bool onlyAxisAligned  =
1794                (mSplitPlaneStrategy & AXIS_ALIGNED) &&
1795                ((int)data.mRays->size() > mTermMinRaysForAxisAligned) &&
1796                ((int)data.GetAvgRayContribution() < mTermMaxRayContriForAxisAligned);
1797       
1798        const int limit = onlyAxisAligned ? 0 :
1799                Min((int)data.mPolygons->size(), mMaxPolyCandidates);
1800
1801        float candidateCost;
1802
1803        int maxIdx = (int)data.mPolygons->size();
1804
1805        for (int i = 0; i < limit; ++ i)
1806        {
1807                // the already taken candidates are stored behind maxIdx
1808                // => assure that no index is taken twice
1809                const int candidateIdx = (int)RandomValue(0, (Real)(-- maxIdx));
1810                Polygon3 *poly = (*data.mPolygons)[candidateIdx];
1811
1812                // swap candidate to the end to avoid testing same plane
1813                std::swap((*data.mPolygons)[maxIdx], (*data.mPolygons)[candidateIdx]);
1814                //Polygon3 *poly = (*data.mPolygons)[(int)RandomValue(0, (int)polys.size() - 1)];
1815
1816                // evaluate current candidate
1817                BspNodeGeometry fGeom, bGeom;
1818                float fArea, bArea;
1819                plane = poly->GetSupportingPlane();
1820                candidateCost = EvalSplitPlaneCost(plane, data, fGeom, bGeom, fArea, bArea);
1821               
1822                if (candidateCost < lowestCost)
1823                {
1824                        bestPlane = plane;
1825                        lowestCost = candidateCost;
1826                }
1827        }
1828
1829
1830        //-- evaluate axis aligned splits
1831       
1832        int axis;
1833        BspNodeGeometry *fGeom, *bGeom;
1834        float pFront, pBack;
1835
1836        candidateCost = 99999999.0f;
1837
1838        // as a variant, we take axis aligned split only if there is
1839        // more polygon available to guide the split
1840        if (!mUsePolygonSplitIfAvailable || data.mPolygons->empty())
1841        {
1842                candidateCost = SelectAxisAlignedPlane(plane,
1843                                                                                           data,
1844                                                                                           axis,
1845                                                                                           &fGeom,
1846                                                                                           &bGeom,
1847                                                                                           pFront,
1848                                                                                           pBack,
1849                                                                                           data.mIsKdNode);     
1850        }
1851
1852        splitAxis = 3;
1853
1854        if (candidateCost < lowestCost)
1855        {       
1856                bestPlane = plane;
1857                lowestCost = candidateCost;
1858                splitAxis = axis;
1859       
1860                // assign already computed values
1861                // we can do this because we always save the
1862                // computed values from the axis aligned splits         
1863
1864                if (fGeom && bGeom)
1865                {
1866                        frontData.mGeometry = fGeom;
1867                        backData.mGeometry = bGeom;
1868       
1869                        frontData.mProbability = pFront;
1870                        backData.mProbability = pBack;
1871                }
1872        }
1873        else
1874        {
1875                DEL_PTR(fGeom);
1876                DEL_PTR(bGeom);
1877        }
1878   
1879#ifdef _DEBUG
1880        Debug << "plane lowest cost: " << lowestCost << endl;
1881#endif
1882
1883        // exeeded relative max cost ratio
1884        if (lowestCost > mTermMaxCostRatio)
1885        {
1886                return false;
1887        }
1888
1889        return true;
1890}
1891
1892
1893Plane3 VspBspTree::ChooseCandidatePlane(const RayInfoContainer &rays) const
1894{
1895        const int candidateIdx = (int)RandomValue(0, (Real)((int)rays.size() - 1));
1896
1897        const Vector3 minPt = rays[candidateIdx].ExtrapOrigin();
1898        const Vector3 maxPt = rays[candidateIdx].ExtrapTermination();
1899
1900        const Vector3 pt = (maxPt + minPt) * 0.5;
1901        const Vector3 normal = Normalize(rays[candidateIdx].mRay->GetDir());
1902
1903        return Plane3(normal, pt);
1904}
1905
1906
1907Plane3 VspBspTree::ChooseCandidatePlane2(const RayInfoContainer &rays) const
1908{
1909        Vector3 pt[3];
1910
1911        int idx[3];
1912        int cmaxT = 0;
1913        int cminT = 0;
1914        bool chooseMin = false;
1915
1916        for (int j = 0; j < 3; ++ j)
1917        {
1918                idx[j] = (int)RandomValue(0, (Real)((int)rays.size() * 2 - 1));
1919
1920                if (idx[j] >= (int)rays.size())
1921                {
1922                        idx[j] -= (int)rays.size();
1923
1924                        chooseMin = (cminT < 2);
1925                }
1926                else
1927                        chooseMin = (cmaxT < 2);
1928
1929                RayInfo rayInf = rays[idx[j]];
1930                pt[j] = chooseMin ? rayInf.ExtrapOrigin() : rayInf.ExtrapTermination();
1931        }
1932
1933        return Plane3(pt[0], pt[1], pt[2]);
1934}
1935
1936
1937Plane3 VspBspTree::ChooseCandidatePlane3(const RayInfoContainer &rays) const
1938{
1939        Vector3 pt[3];
1940
1941        int idx1 = (int)RandomValue(0, (Real)((int)rays.size() - 1));
1942        int idx2 = (int)RandomValue(0, (Real)((int)rays.size() - 1));
1943
1944        // check if rays different
1945        if (idx1 == idx2)
1946                idx2 = (idx2 + 1) % (int)rays.size();
1947
1948        const RayInfo ray1 = rays[idx1];
1949        const RayInfo ray2 = rays[idx2];
1950
1951        // normal vector of the plane parallel to both lines
1952        const Vector3 norm = Normalize(CrossProd(ray1.mRay->GetDir(), ray2.mRay->GetDir()));
1953
1954        // vector from line 1 to line 2
1955        const Vector3 vd = ray2.ExtrapOrigin() - ray1.ExtrapOrigin();
1956
1957        // project vector on normal to get distance
1958        const float dist = DotProd(vd, norm);
1959
1960        // point on plane lies halfway between the two planes
1961        const Vector3 planePt = ray1.ExtrapOrigin() + norm * dist * 0.5;
1962
1963        return Plane3(norm, planePt);
1964}
1965
1966
1967inline void VspBspTree::GenerateUniqueIdsForPvs()
1968{
1969        Intersectable::NewMail(); sBackId = Intersectable::sMailId;
1970        Intersectable::NewMail(); sFrontId = Intersectable::sMailId;
1971        Intersectable::NewMail(); sFrontAndBackId = Intersectable::sMailId;
1972}
1973
1974
1975float VspBspTree::EvalRenderCostDecrease(const Plane3 &candidatePlane,
1976                                                                                 const VspBspTraversalData &data,
1977                                                                                 float &normalizedOldRenderCost) const
1978{
1979        float pvsFront = 0;
1980        float pvsBack = 0;
1981        float totalPvs = 0;
1982
1983        // probability that view point lies in back / front node
1984        float pOverall = data.mProbability;
1985        float pFront = 0;
1986        float pBack = 0;
1987
1988
1989        // create unique ids for pvs heuristics
1990        GenerateUniqueIdsForPvs();
1991       
1992        for (int i = 0; i < data.mRays->size(); ++ i)
1993        {
1994                RayInfo rayInf = (*data.mRays)[i];
1995
1996                float t;
1997                VssRay *ray = rayInf.mRay;
1998                const int cf = rayInf.ComputeRayIntersection(candidatePlane, t);
1999
2000                // find front and back pvs for origing and termination object
2001                AddObjToPvs(ray->mTerminationObject, cf, pvsFront, pvsBack, totalPvs);
2002
2003                if (COUNT_ORIGIN_OBJECTS)
2004                {
2005                        AddObjToPvs(ray->mOriginObject, cf, pvsFront, pvsBack, totalPvs);
2006                }
2007        }
2008
2009
2010        BspNodeGeometry geomFront;
2011        BspNodeGeometry geomBack;
2012
2013        // construct child geometry with regard to the candidate split plane
2014        data.mGeometry->SplitGeometry(geomFront,
2015                                                                  geomBack,
2016                                                                  candidatePlane,
2017                                                                  mBoundingBox,
2018                                                                  //0.0f);
2019                                                                  mEpsilon);
2020
2021        if (!mUseAreaForPvs) // use front and back cell areas to approximate volume
2022        {
2023                pFront = geomFront.GetVolume();
2024                pBack = pOverall - pFront;
2025
2026                // something is wrong with the volume
2027                if (0 && ((pFront < 0.0) || (pBack < 0.0)))
2028                {
2029                        Debug << "ERROR in volume:\n"
2030                                  << "volume f :" << pFront << " b: " << pBack << " p: " << pOverall
2031                                  << ", real volume f: " << pFront << " b: " << geomBack.GetVolume()
2032                                  << ", #polygons f: " << geomFront.Size() << " b: " << geomBack.Size() << " p: " << data.mGeometry->Size() << endl;
2033                }
2034        }
2035        else
2036        {
2037                pFront = geomFront.GetArea();
2038                pBack = geomBack.GetArea();
2039        }
2040       
2041
2042        // -- pvs rendering heuristics
2043
2044        // upper and lower bounds
2045        const int lowerPvsLimit = mViewCellsManager->GetMinPvsSize();
2046        const int upperPvsLimit = mViewCellsManager->GetMaxPvsSize();
2047
2048        const float penaltyOld = EvalPvsPenalty((int)totalPvs, lowerPvsLimit, upperPvsLimit);
2049    const float penaltyFront = EvalPvsPenalty((int)pvsFront, lowerPvsLimit, upperPvsLimit);
2050        const float penaltyBack = EvalPvsPenalty((int)pvsBack, lowerPvsLimit, upperPvsLimit);
2051                       
2052        const float oldRenderCost = pOverall * penaltyOld;
2053        const float newRenderCost = penaltyFront * pFront + penaltyBack * pBack;
2054
2055        const float renderCostDecrease = (oldRenderCost - newRenderCost) / mBoundingBox.GetVolume();
2056       
2057        // take render cost of node into account to avoid being stuck in a local minimum
2058        normalizedOldRenderCost = oldRenderCost / mBoundingBox.GetVolume();
2059       
2060        return renderCostDecrease;
2061}
2062
2063
2064float VspBspTree::EvalSplitPlaneCost(const Plane3 &candidatePlane,
2065                                                                         const VspBspTraversalData &data,
2066                                                                         BspNodeGeometry &geomFront,
2067                                                                         BspNodeGeometry &geomBack,
2068                                                                         float &pFront,
2069                                                                         float &pBack) const
2070{
2071        float totalPvs = 0;
2072        float pvsFront = 0;
2073        float pvsBack = 0;
2074       
2075        // overall probability is used as normalizer
2076        float pOverall = 0;
2077
2078        // probability that view point lies in back / front node
2079        pFront = 0;
2080        pBack = 0;
2081
2082        int numTests; // the number of tests
2083
2084        // if random samples shold be taken instead of testing all the rays
2085        bool useRand;
2086
2087        if ((int)data.mRays->size() > mMaxTests)
2088        {
2089                useRand = true;
2090                numTests = mMaxTests;
2091        }
2092        else
2093        {
2094                useRand = false;
2095                numTests = (int)data.mRays->size();
2096        }
2097       
2098        // create unique ids for pvs heuristics
2099        GenerateUniqueIdsForPvs();
2100
2101        for (int i = 0; i < numTests; ++ i)
2102        {
2103                const int testIdx = useRand ?
2104                        (int)RandomValue(0, (Real)((int)data.mRays->size() - 1)) : i;
2105                RayInfo rayInf = (*data.mRays)[testIdx];
2106
2107                float t;
2108                VssRay *ray = rayInf.mRay;
2109                const int cf = rayInf.ComputeRayIntersection(candidatePlane, t);
2110
2111                // find front and back pvs for origing and termination object
2112                AddObjToPvs(ray->mTerminationObject, cf, pvsFront, pvsBack, totalPvs);
2113
2114                if (COUNT_ORIGIN_OBJECTS)
2115                {
2116                        AddObjToPvs(ray->mOriginObject, cf, pvsFront, pvsBack, totalPvs);
2117                }
2118        }
2119
2120        // construct child geometry with regard to the candidate split plane
2121        bool splitSuccessFull = data.mGeometry->SplitGeometry(geomFront,
2122                                                                                                                  geomBack,
2123                                                                                                                  candidatePlane,
2124                                                                                                                  mBoundingBox,
2125                                                                                                                  //0.0f);
2126                                                                                                                  mEpsilon);
2127
2128        pOverall = data.mProbability;
2129
2130        if (!mUseAreaForPvs) // use front and back cell areas to approximate volume
2131        {
2132                pFront = geomFront.GetVolume();
2133                pBack = pOverall - pFront;
2134               
2135                // HACK: precision issues possible for unbalanced split => don't take this split!
2136                if (1 &&
2137                        (!splitSuccessFull || (pFront <= 0) || (pBack <= 0) ||
2138                        !geomFront.Valid() || !geomBack.Valid()))
2139                {
2140                        //Debug << "error f: " << pFront << " b: " << pBack << endl;
2141
2142                        // high penalty for degenerated / wrong split
2143                        return 99999.9f;
2144                }
2145        }
2146        else
2147        {
2148                pFront = geomFront.GetArea();
2149                pBack = geomBack.GetArea();
2150        }
2151       
2152
2153        // -- pvs rendering heuristics
2154        const int lowerPvsLimit = mViewCellsManager->GetMinPvsSize();
2155        const int upperPvsLimit = mViewCellsManager->GetMaxPvsSize();
2156
2157        // only render cost heuristics or combined with standard deviation
2158        const float penaltyOld = EvalPvsPenalty((int)totalPvs, lowerPvsLimit, upperPvsLimit);
2159    const float penaltyFront = EvalPvsPenalty((int)pvsFront, lowerPvsLimit, upperPvsLimit);
2160        const float penaltyBack = EvalPvsPenalty((int)pvsBack, lowerPvsLimit, upperPvsLimit);
2161                       
2162        const float oldRenderCost = pOverall * penaltyOld;
2163        const float newRenderCost = penaltyFront * pFront + penaltyBack * pBack;
2164
2165        float oldCost, newCost;
2166
2167        // only render cost
2168        if (1)
2169        {
2170                oldCost = oldRenderCost;
2171                newCost = newRenderCost;
2172        }
2173        else // also considering standard deviation
2174        {
2175                // standard deviation is difference of back and front pvs
2176                const float expectedCost = 0.5f * (penaltyFront + penaltyBack);
2177
2178                const float newDeviation = 0.5f *
2179                        fabs(penaltyFront - expectedCost) + fabs(penaltyBack - expectedCost);
2180
2181                const float oldDeviation = penaltyOld;
2182
2183                newCost = mRenderCostWeight * newRenderCost + (1.0f - mRenderCostWeight) * newDeviation;
2184                oldCost = mRenderCostWeight * oldRenderCost + (1.0f - mRenderCostWeight) * oldDeviation;
2185        }
2186
2187        const float cost = mPvsFactor * newCost / (oldCost + Limits::Small);
2188               
2189
2190#ifdef _DEBUG
2191        Debug << "totalpvs: " << data.mPvs << " ptotal: " << pOverall
2192                  << " frontpvs: " << pvsFront << " pFront: " << pFront
2193                  << " backpvs: " << pvsBack << " pBack: " << pBack << endl << endl;
2194        Debug << "cost: " << cost << endl;
2195#endif
2196
2197        return cost;
2198}
2199
2200
2201int VspBspTree::ComputeBoxIntersections(const AxisAlignedBox3 &box,
2202                                                                                ViewCellContainer &viewCells) const
2203{
2204        stack<bspNodePair> nodeStack;
2205        BspNodeGeometry *rgeom = new BspNodeGeometry();
2206
2207        ConstructGeometry(mRoot, *rgeom);
2208
2209        nodeStack.push(bspNodePair(mRoot, rgeom));
2210 
2211        ViewCell::NewMail();
2212
2213        while (!nodeStack.empty())
2214        {
2215                BspNode *node = nodeStack.top().first;
2216                BspNodeGeometry *geom = nodeStack.top().second;
2217                nodeStack.pop();
2218
2219                const int side = geom->ComputeIntersection(box);
2220               
2221                switch (side)
2222                {
2223                case -1:
2224                        // node geometry is contained in box
2225                        CollectViewCells(node, true, viewCells, true);
2226                        break;
2227
2228                case 0:
2229                        if (node->IsLeaf())
2230                        {
2231                                BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
2232                       
2233                                if (!leaf->GetViewCell()->Mailed() && leaf->TreeValid())
2234                                {
2235                                        leaf->GetViewCell()->Mail();
2236                                        viewCells.push_back(leaf->GetViewCell());
2237                                }
2238                        }
2239                        else
2240                        {
2241                                BspInterior *interior = dynamic_cast<BspInterior *>(node);
2242                       
2243                                BspNode *first = interior->GetFront();
2244                                BspNode *second = interior->GetBack();
2245           
2246                                BspNodeGeometry *firstGeom = new BspNodeGeometry();
2247                                BspNodeGeometry *secondGeom = new BspNodeGeometry();
2248
2249                                geom->SplitGeometry(*firstGeom,
2250                                                                        *secondGeom,
2251                                                                        interior->GetPlane(),
2252                                                                        mBoundingBox,
2253                                                                        //0.0000001f);
2254                                                                        mEpsilon);
2255
2256                                nodeStack.push(bspNodePair(first, firstGeom));
2257                                nodeStack.push(bspNodePair(second, secondGeom));
2258                        }
2259                       
2260                        break;
2261                default:
2262                        // default: cull
2263                        break;
2264                }
2265               
2266                DEL_PTR(geom);
2267               
2268        }
2269
2270        return (int)viewCells.size();
2271}
2272
2273
2274float VspBspTree::EvalAxisAlignedSplitCost(const VspBspTraversalData &data,
2275                                                                                   const AxisAlignedBox3 &box,
2276                                                                                   const int axis,
2277                                                                                   const float &position,                                                                                 
2278                                                                                   float &pFront,
2279                                                                                   float &pBack) const
2280{
2281        float pvsTotal = 0;
2282        float pvsFront = 0;
2283        float pvsBack = 0;
2284       
2285        // create unique ids for pvs heuristics
2286        GenerateUniqueIdsForPvs();
2287
2288        const int pvsSize = data.mPvs;
2289
2290        RayInfoContainer::const_iterator rit, rit_end = data.mRays->end();
2291
2292        // this is the main ray classification loop!
2293        for(rit = data.mRays->begin(); rit != rit_end; ++ rit)
2294        {
2295                // determine the side of this ray with respect to the plane
2296                float t;
2297                const int side = (*rit).ComputeRayIntersection(axis, position, t);
2298       
2299                AddObjToPvs((*rit).mRay->mTerminationObject, side, pvsFront, pvsBack, pvsTotal);
2300
2301                if (COUNT_ORIGIN_OBJECTS)
2302                        AddObjToPvs((*rit).mRay->mOriginObject, side, pvsFront, pvsBack, pvsTotal);
2303        }
2304
2305
2306        //-- pvs heuristics
2307
2308        float pOverall = data.mProbability;
2309
2310        // note: we use a simplified computation assuming that we always do a
2311        // spatial mid split   
2312       
2313        if (!mUseAreaForPvs)
2314        {   
2315                // volume
2316                pBack = pFront = pOverall * 0.5f;
2317#if 0
2318                // box length substitute for probability
2319                const float minBox = box.Min(axis);
2320                const float maxBox = box.Max(axis);
2321
2322                pBack = position - minBox;
2323                pFront = maxBox - position;
2324                pOverall = maxBox - minBox;
2325#endif
2326        }
2327        else //-- area substitute for probability
2328        {
2329                const int axis2 = (axis + 1) % 3;
2330                const int axis3 = (axis + 2) % 3;
2331
2332                const float faceArea =
2333                        (box.Max(axis2) - box.Min(axis2)) *
2334                        (box.Max(axis3) - box.Min(axis3));
2335
2336                pBack = pFront = pOverall * 0.5f + faceArea;
2337        }
2338
2339#ifdef _DEBUG
2340        Debug << "axis: " << axis << " " << pvsSize << " " << pvsBack << " " << pvsFront << endl;
2341        Debug << "p: " << pFront << " " << pBack << " " << pOverall << endl;
2342#endif
2343
2344       
2345        const float newCost = pvsBack * pBack + pvsFront * pFront;
2346        const float oldCost = (float)pvsSize * pOverall + Limits::Small;
2347
2348        return  (mCtDivCi + newCost) / oldCost;
2349}
2350
2351
2352inline void VspBspTree::AddObjToPvs(Intersectable *obj,
2353                                                                                 const int cf,
2354                                                                                 float &frontPvs,
2355                                                                                 float &backPvs,
2356                                                                                 float &totalPvs) const
2357{
2358        if (!obj)
2359                return;
2360#if 0
2361        const float renderCost = mViewCellsManager->EvalRenderCost(obj);
2362#else
2363        const int renderCost = 1;
2364#endif
2365        // new object
2366        if ((obj->mMailbox != sFrontId) &&
2367                (obj->mMailbox != sBackId) &&
2368                (obj->mMailbox != sFrontAndBackId))
2369        {
2370                totalPvs += renderCost;
2371        }
2372
2373        // TODO: does this really belong to no pvs?
2374        //if (cf == Ray::COINCIDENT) return;
2375
2376        // object belongs to both PVS
2377        if (cf >= 0)
2378        {
2379                if ((obj->mMailbox != sFrontId) &&
2380                        (obj->mMailbox != sFrontAndBackId))
2381                {
2382                        frontPvs += renderCost;
2383               
2384                        if (obj->mMailbox == sBackId)
2385                                obj->mMailbox = sFrontAndBackId;
2386                        else
2387                                obj->mMailbox = sFrontId;
2388                }
2389        }
2390
2391        if (cf <= 0)
2392        {
2393                if ((obj->mMailbox != sBackId) &&
2394                        (obj->mMailbox != sFrontAndBackId))
2395                {
2396                        backPvs += renderCost;
2397               
2398                        if (obj->mMailbox == sFrontId)
2399                                obj->mMailbox = sFrontAndBackId;
2400                        else
2401                                obj->mMailbox = sBackId;
2402                }
2403        }
2404}
2405
2406
2407void VspBspTree::CollectLeaves(vector<BspLeaf *> &leaves,
2408                                                           const bool onlyUnmailed,
2409                                                           const int maxPvsSize) const
2410{
2411        stack<BspNode *> nodeStack;
2412        nodeStack.push(mRoot);
2413
2414        while (!nodeStack.empty())
2415        {
2416                BspNode *node = nodeStack.top();
2417                nodeStack.pop();
2418               
2419                if (node->IsLeaf())
2420                {
2421                        // test if this leaf is in valid view space
2422                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
2423                        if (leaf->TreeValid() &&
2424                                (!onlyUnmailed || !leaf->Mailed()) &&
2425                                ((maxPvsSize < 0) || (leaf->GetViewCell()->GetPvs().CountObjectsInPvs() <= maxPvsSize)))
2426                        {
2427                                leaves.push_back(leaf);
2428                        }
2429                }
2430                else
2431                {
2432                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2433
2434                        nodeStack.push(interior->GetBack());
2435                        nodeStack.push(interior->GetFront());
2436                }
2437        }
2438}
2439
2440
2441AxisAlignedBox3 VspBspTree::GetBoundingBox() const
2442{
2443        return mBoundingBox;
2444}
2445
2446
2447BspNode *VspBspTree::GetRoot() const
2448{
2449        return mRoot;
2450}
2451
2452
2453void VspBspTree::EvaluateLeafStats(const VspBspTraversalData &data)
2454{
2455        // the node became a leaf -> evaluate stats for leafs
2456        BspLeaf *leaf = dynamic_cast<BspLeaf *>(data.mNode);
2457
2458
2459        if (data.mPvs > mBspStats.maxPvs)
2460        {
2461                mBspStats.maxPvs = data.mPvs;
2462        }
2463
2464        mBspStats.pvs += data.mPvs;
2465
2466        if (data.mDepth < mBspStats.minDepth)
2467        {
2468                mBspStats.minDepth = data.mDepth;
2469        }
2470       
2471        if (data.mDepth >= mTermMaxDepth)
2472        {
2473        ++ mBspStats.maxDepthNodes;
2474                //Debug << "new max depth: " << mBspStats.maxDepthNodes << endl;
2475        }
2476
2477        // accumulate rays to compute rays /  leaf
2478        mBspStats.accumRays += (int)data.mRays->size();
2479
2480        if (data.mPvs < mTermMinPvs)
2481                ++ mBspStats.minPvsNodes;
2482
2483        if ((int)data.mRays->size() < mTermMinRays)
2484                ++ mBspStats.minRaysNodes;
2485
2486        if (data.GetAvgRayContribution() > mTermMaxRayContribution)
2487                ++ mBspStats.maxRayContribNodes;
2488
2489        if (data.mProbability <= mTermMinProbability)
2490                ++ mBspStats.minProbabilityNodes;
2491       
2492        // accumulate depth to compute average depth
2493        mBspStats.accumDepth += data.mDepth;
2494
2495        ++ mCreatedViewCells;
2496
2497#ifdef _DEBUG
2498        Debug << "BSP stats: "
2499                  << "Depth: " << data.mDepth << " (max: " << mTermMaxDepth << "), "
2500                  << "PVS: " << data.mPvs << " (min: " << mTermMinPvs << "), "
2501                  << "#rays: " << (int)data.mRays->size() << " (max: " << mTermMinRays << "), "
2502                  << "#pvs: " << leaf->GetViewCell()->GetPvs().CountObjectsInPvs() << "), "
2503                  << "#avg ray contrib (pvs): " << (float)data.mPvs / (float)data.mRays->size() << endl;
2504#endif
2505}
2506
2507
2508int VspBspTree::CastRay(Ray &ray)
2509{
2510        int hits = 0;
2511
2512        stack<BspRayTraversalData> tQueue;
2513
2514        float maxt, mint;
2515
2516        if (!mBoundingBox.GetRaySegment(ray, mint, maxt))
2517                return 0;
2518
2519        Intersectable::NewMail();
2520        ViewCell::NewMail();
2521
2522        Vector3 entp = ray.Extrap(mint);
2523        Vector3 extp = ray.Extrap(maxt);
2524
2525        BspNode *node = mRoot;
2526        BspNode *farChild = NULL;
2527
2528        while (1)
2529        {
2530                if (!node->IsLeaf())
2531                {
2532                        BspInterior *in = dynamic_cast<BspInterior *>(node);
2533
2534                        Plane3 splitPlane = in->GetPlane();
2535                        const int entSide = splitPlane.Side(entp);
2536                        const int extSide = splitPlane.Side(extp);
2537
2538                        if (entSide < 0)
2539                        {
2540                                node = in->GetBack();
2541
2542                                if(extSide <= 0) // plane does not split ray => no far child
2543                                        continue;
2544
2545                                farChild = in->GetFront(); // plane splits ray
2546
2547                        } else if (entSide > 0)
2548                        {
2549                                node = in->GetFront();
2550
2551                                if (extSide >= 0) // plane does not split ray => no far child
2552                                        continue;
2553
2554                                farChild = in->GetBack(); // plane splits ray
2555                        }
2556                        else // ray and plane are coincident
2557                        {
2558                                // matt: WHAT TO DO IN THIS CASE ?
2559                                //break;
2560                                node = in->GetFront();
2561                                continue;
2562                        }
2563
2564                        // push data for far child
2565                        tQueue.push(BspRayTraversalData(farChild, extp, maxt));
2566
2567                        // find intersection of ray segment with plane
2568                        float t;
2569                        extp = splitPlane.FindIntersection(ray.GetLoc(), extp, &t);
2570                        maxt *= t;
2571                }
2572                else // reached leaf => intersection with view cell
2573                {
2574                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
2575
2576                        if (!leaf->GetViewCell()->Mailed())
2577                        {
2578                                //ray.bspIntersections.push_back(Ray::VspBspIntersection(maxt, leaf));
2579                                leaf->GetViewCell()->Mail();
2580                                ++ hits;
2581                        }
2582
2583                        //-- fetch the next far child from the stack
2584                        if (tQueue.empty())
2585                                break;
2586
2587                        entp = extp;
2588                        mint = maxt; // NOTE: need this?
2589
2590                        if (ray.GetType() == Ray::LINE_SEGMENT && mint > 1.0f)
2591                                break;
2592
2593                        BspRayTraversalData &s = tQueue.top();
2594
2595                        node = s.mNode;
2596                        extp = s.mExitPoint;
2597                        maxt = s.mMaxT;
2598
2599                        tQueue.pop();
2600                }
2601        }
2602
2603        return hits;
2604}
2605
2606
2607void VspBspTree::CollectViewCells(ViewCellContainer &viewCells,
2608                                                                  bool onlyValid) const
2609{
2610        ViewCell::NewMail();
2611        CollectViewCells(mRoot, onlyValid, viewCells, true);
2612}
2613
2614
2615void VspBspTree::CollectViewCells(BspNode *root,
2616                                                                  bool onlyValid,
2617                                                                  ViewCellContainer &viewCells,
2618                                                                  bool onlyUnmailed) const
2619{
2620        stack<BspNode *> nodeStack;
2621
2622        if (!root)
2623                return;
2624
2625        nodeStack.push(root);
2626       
2627        while (!nodeStack.empty())
2628        {
2629                BspNode *node = nodeStack.top();
2630                nodeStack.pop();
2631               
2632                if (node->IsLeaf())
2633                {
2634                        if (!onlyValid || node->TreeValid())
2635                        {
2636                                ViewCellLeaf *leafVc = dynamic_cast<BspLeaf *>(node)->GetViewCell();
2637
2638                                ViewCell *viewCell = mViewCellsTree->GetActiveViewCell(leafVc);
2639                                               
2640                                if (!onlyUnmailed || !viewCell->Mailed())
2641                                {
2642                                        viewCell->Mail();
2643                                        viewCells.push_back(viewCell);
2644                                }
2645                        }
2646                }
2647                else
2648                {
2649                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2650               
2651                        nodeStack.push(interior->GetFront());
2652                        nodeStack.push(interior->GetBack());
2653                }
2654        }
2655}
2656
2657
2658void VspBspTree::CollapseViewCells()
2659{
2660// TODO
2661#if HAS_TO_BE_REDONE
2662        stack<BspNode *> nodeStack;
2663
2664        if (!mRoot)
2665                return;
2666
2667        nodeStack.push(mRoot);
2668       
2669        while (!nodeStack.empty())
2670        {
2671                BspNode *node = nodeStack.top();
2672                nodeStack.pop();
2673               
2674                if (node->IsLeaf())
2675        {
2676                        BspViewCell *viewCell = dynamic_cast<BspLeaf *>(node)->GetViewCell();
2677
2678                        if (!viewCell->GetValid())
2679                        {
2680                                BspViewCell *viewCell = dynamic_cast<BspLeaf *>(node)->GetViewCell();
2681       
2682                                ViewCellContainer leaves;
2683                                mViewCellsTree->CollectLeaves(viewCell, leaves);
2684
2685                                ViewCellContainer::const_iterator it, it_end = leaves.end();
2686
2687                                for (it = leaves.begin(); it != it_end; ++ it)
2688                                {
2689                                        BspLeaf *l = dynamic_cast<BspViewCell *>(*it)->mLeaf;
2690                                        l->SetViewCell(GetOrCreateOutOfBoundsCell());
2691                                        ++ mBspStats.invalidLeaves;
2692                                }
2693
2694                                // add to unbounded view cell
2695                                GetOrCreateOutOfBoundsCell()->GetPvs().AddPvs(viewCell->GetPvs());
2696                                DEL_PTR(viewCell);
2697                        }
2698                }
2699                else
2700                {
2701                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2702               
2703                        nodeStack.push(interior->GetFront());
2704                        nodeStack.push(interior->GetBack());
2705                }
2706        }
2707
2708        Debug << "invalid leaves: " << mBspStats.invalidLeaves << endl;
2709#endif
2710}
2711
2712
2713void VspBspTree::CollectRays(VssRayContainer &rays)
2714{
2715        vector<BspLeaf *> leaves;
2716
2717        vector<BspLeaf *>::const_iterator lit, lit_end = leaves.end();
2718
2719        for (lit = leaves.begin(); lit != lit_end; ++ lit)
2720        {
2721                BspLeaf *leaf = *lit;
2722                VssRayContainer::const_iterator rit, rit_end = leaf->mVssRays.end();
2723
2724                for (rit = leaf->mVssRays.begin(); rit != rit_end; ++ rit)
2725                        rays.push_back(*rit);
2726        }
2727}
2728
2729
2730void VspBspTree::ValidateTree()
2731{
2732        stack<BspNode *> nodeStack;
2733
2734        if (!mRoot)
2735                return;
2736
2737        nodeStack.push(mRoot);
2738       
2739        mBspStats.invalidLeaves = 0;
2740        while (!nodeStack.empty())
2741        {
2742                BspNode *node = nodeStack.top();
2743                nodeStack.pop();
2744               
2745                if (node->IsLeaf())
2746                {
2747                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
2748
2749                        if (!leaf->GetViewCell()->GetValid())
2750                                ++ mBspStats.invalidLeaves;
2751
2752                        // validity flags don't match => repair
2753                        if (leaf->GetViewCell()->GetValid() != leaf->TreeValid())
2754                        {
2755                                leaf->SetTreeValid(leaf->GetViewCell()->GetValid());
2756                                PropagateUpValidity(leaf);
2757                        }
2758                }
2759                else
2760                {
2761                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2762               
2763                        nodeStack.push(interior->GetFront());
2764                        nodeStack.push(interior->GetBack());
2765                }
2766        }
2767
2768        Debug << "invalid leaves: " << mBspStats.invalidLeaves << endl;
2769}
2770
2771
2772void VspBspTree::PreprocessPolygons(PolygonContainer &polys)
2773{
2774        // preprocess: throw out polygons coincident to the view space box (not needed)
2775        PolygonContainer boxPolys;
2776       
2777        mBoundingBox.ExtractPolys(boxPolys);
2778        vector<Plane3> boxPlanes;
2779
2780        PolygonContainer::iterator pit, pit_end = boxPolys.end();
2781
2782        // extract planes of box
2783        // TODO: can be done more elegantly than first extracting polygons
2784        // and take their planes
2785        for (pit = boxPolys.begin(); pit != pit_end; ++ pit)
2786        {
2787                boxPlanes.push_back((*pit)->GetSupportingPlane());
2788        }
2789
2790        pit_end = polys.end();
2791
2792        for (pit = polys.begin(); pit != pit_end; ++ pit)
2793        {
2794                vector<Plane3>::const_iterator bit, bit_end = boxPlanes.end();
2795               
2796                for (bit = boxPlanes.begin(); (bit != bit_end) && (*pit); ++ bit)
2797                {
2798                        const int cf = (*pit)->ClassifyPlane(*bit, mEpsilon);
2799
2800                        if (cf == Polygon3::COINCIDENT)
2801                        {
2802                                DEL_PTR(*pit);
2803                                //Debug << "coincident!!" << endl;
2804                        }
2805                }
2806        }
2807
2808        // remove deleted entries after swapping them to end of vector
2809        for (int i = 0; i < (int)polys.size(); ++ i)
2810        {
2811                while (!polys[i] && (i < (int)polys.size()))
2812                {
2813                        swap(polys[i], polys.back());
2814                        polys.pop_back();
2815                }
2816        }
2817}
2818
2819
2820float VspBspTree::AccumulatedRayLength(const RayInfoContainer &rays) const
2821{
2822        float len = 0;
2823
2824        RayInfoContainer::const_iterator it, it_end = rays.end();
2825
2826        for (it = rays.begin(); it != it_end; ++ it)
2827                len += (*it).SegmentLength();
2828
2829        return len;
2830}
2831
2832
2833int VspBspTree::SplitRays(const Plane3 &plane,
2834                                                  RayInfoContainer &rays,
2835                                                  RayInfoContainer &frontRays,
2836                                                  RayInfoContainer &backRays) const
2837{
2838        int splits = 0;
2839
2840        RayInfoContainer::const_iterator it, it_end = rays.end();
2841
2842        for (it = rays.begin(); it != it_end; ++ it)
2843        {
2844                RayInfo bRay = *it;
2845               
2846                VssRay *ray = bRay.mRay;
2847                float t;
2848
2849                // get classification and receive new t
2850                const int cf = bRay.ComputeRayIntersection(plane, t);
2851
2852                switch (cf)
2853                {
2854                case -1:
2855                        backRays.push_back(bRay);
2856                        break;
2857                case 1:
2858                        frontRays.push_back(bRay);
2859                        break;
2860                case 0:
2861                        {
2862                                //-- split ray
2863                                //   test if start point behind or in front of plane
2864                                const int side = plane.Side(bRay.ExtrapOrigin());
2865
2866                                ++ splits;
2867
2868                                if (side <= 0)
2869                                {
2870                                        backRays.push_back(RayInfo(ray, bRay.GetMinT(), t));
2871                                        frontRays.push_back(RayInfo(ray, t, bRay.GetMaxT()));
2872                                }
2873                                else
2874                                {
2875                                        frontRays.push_back(RayInfo(ray, bRay.GetMinT(), t));
2876                                        backRays.push_back(RayInfo(ray, t, bRay.GetMaxT()));
2877                                }
2878                        }
2879                        break;
2880                default:
2881                        Debug << "Should not come here" << endl;
2882                        break;
2883                }
2884        }
2885
2886        return splits;
2887}
2888
2889
2890void VspBspTree::ExtractHalfSpaces(BspNode *n, vector<Plane3> &halfSpaces) const
2891{
2892        BspNode *lastNode;
2893
2894        do
2895        {
2896                lastNode = n;
2897
2898                // want to get planes defining geometry of this node => don't take
2899                // split plane of node itself
2900                n = n->GetParent();
2901
2902                if (n)
2903                {
2904                        BspInterior *interior = dynamic_cast<BspInterior *>(n);
2905                        Plane3 halfSpace = dynamic_cast<BspInterior *>(interior)->GetPlane();
2906
2907            if (interior->GetBack() != lastNode)
2908                                halfSpace.ReverseOrientation();
2909
2910                        halfSpaces.push_back(halfSpace);
2911                }
2912        }
2913        while (n);
2914}
2915
2916
2917void VspBspTree::ConstructGeometry(BspNode *n,
2918                                                                   BspNodeGeometry &geom) const
2919{
2920        vector<Plane3> halfSpaces;
2921        ExtractHalfSpaces(n, halfSpaces);
2922
2923        PolygonContainer candidatePolys;
2924        vector<Plane3> candidatePlanes;
2925
2926        vector<Plane3>::const_iterator pit, pit_end = halfSpaces.end();
2927
2928        // bounded planes are added to the polygons
2929        for (pit = halfSpaces.begin(); pit != pit_end; ++ pit)
2930        {
2931                Polygon3 *p = GetBoundingBox().CrossSection(*pit);
2932
2933                if (p->Valid(mEpsilon))
2934                {
2935                        candidatePolys.push_back(p);
2936                        candidatePlanes.push_back(*pit);
2937                }
2938        }
2939
2940        // add faces of bounding box (also could be faces of the cell)
2941        for (int i = 0; i < 6; ++ i)
2942        {
2943                VertexContainer vertices;
2944
2945                for (int j = 0; j < 4; ++ j)
2946                {
2947                        vertices.push_back(mBoundingBox.GetFace(i).mVertices[j]);
2948                }
2949
2950                Polygon3 *poly = new Polygon3(vertices);
2951
2952                candidatePolys.push_back(poly);
2953                candidatePlanes.push_back(poly->GetSupportingPlane());
2954        }
2955
2956        for (int i = 0; i < (int)candidatePolys.size(); ++ i)
2957        {
2958                // polygon is split by all other planes
2959                for (int j = 0; (j < (int)halfSpaces.size()) && candidatePolys[i]; ++ j)
2960                {
2961                        if (i == j) // polygon and plane are coincident
2962                                continue;
2963
2964                        VertexContainer splitPts;
2965                        Polygon3 *frontPoly, *backPoly;
2966
2967                        const int cf =
2968                                candidatePolys[i]->ClassifyPlane(halfSpaces[j],
2969                                                                                                 mEpsilon);
2970
2971                        switch (cf)
2972                        {
2973                                case Polygon3::SPLIT:
2974                                        frontPoly = new Polygon3();
2975                                        backPoly = new Polygon3();
2976
2977                                        candidatePolys[i]->Split(halfSpaces[j],
2978                                                                                         *frontPoly,
2979                                                                                         *backPoly,
2980                                                                                         mEpsilon);
2981
2982                                        DEL_PTR(candidatePolys[i]);
2983
2984                                        if (backPoly->Valid(mEpsilon))
2985                                        {
2986                                                candidatePolys[i] = backPoly;
2987                                        }
2988                                        else
2989                                        {
2990                                                DEL_PTR(backPoly);
2991                                        }
2992
2993                                        // outside, don't need this
2994                                        DEL_PTR(frontPoly);
2995                                        break;
2996
2997                                // polygon outside of halfspace
2998                                case Polygon3::FRONT_SIDE:
2999                                        DEL_PTR(candidatePolys[i]);
3000                                        break;
3001
3002                                // just take polygon as it is
3003                                case Polygon3::BACK_SIDE:
3004                                case Polygon3::COINCIDENT:
3005                                default:
3006                                        break;
3007                        }
3008                }
3009
3010                if (candidatePolys[i])
3011                {
3012                        geom.Add(candidatePolys[i], candidatePlanes[i]);
3013                }
3014        }
3015}
3016
3017
3018bool VspBspTree::IsOutOfBounds(ViewCell *vc) const
3019{
3020        return vc->GetId() == OUT_OF_BOUNDS_ID;
3021}
3022
3023
3024void VspBspTree::SetViewCellsTree(ViewCellsTree *viewCellsTree)
3025{
3026        mViewCellsTree = viewCellsTree;
3027}
3028
3029
3030void VspBspTree::ConstructGeometry(ViewCell *vc,
3031                                                                   BspNodeGeometry &vcGeom) const
3032{
3033        // if false, cannot construct geometry for interior leaf
3034        if (!mViewCellsTree)
3035                return;
3036
3037        ViewCellContainer leaves;
3038        mViewCellsTree->CollectLeaves(vc, leaves);
3039
3040        ViewCellContainer::const_iterator it, it_end = leaves.end();
3041
3042        for (it = leaves.begin(); it != it_end; ++ it)
3043        {
3044                if (IsOutOfBounds(*it))
3045                        continue;
3046               
3047                BspViewCell *bspVc = dynamic_cast<BspViewCell *>(*it);
3048                vector<BspLeaf *>::const_iterator bit, bit_end = bspVc->mLeaves.end();
3049
3050                for (bit = bspVc->mLeaves.begin(); bit != bit_end; ++ bit)
3051                {
3052                        BspLeaf *l = *bit;
3053                        ConstructGeometry(l, vcGeom);
3054                }
3055        }
3056}
3057
3058
3059int VspBspTree::FindNeighbors(BspNode *n, vector<BspLeaf *> &neighbors,
3060                                                          const bool onlyUnmailed) const
3061{
3062        stack<bspNodePair> nodeStack;
3063       
3064        BspNodeGeometry nodeGeom;
3065        ConstructGeometry(n, nodeGeom);
3066//      const float eps = 0.5f;
3067        const float eps = 0.01f;
3068        // split planes from the root to this node
3069        // needed to verify that we found neighbor leaf
3070        // TODO: really needed?
3071        vector<Plane3> halfSpaces;
3072        ExtractHalfSpaces(n, halfSpaces);
3073
3074
3075        BspNodeGeometry *rgeom = new BspNodeGeometry();
3076        ConstructGeometry(mRoot, *rgeom);
3077
3078        nodeStack.push(bspNodePair(mRoot, rgeom));
3079
3080        while (!nodeStack.empty())
3081        {
3082                BspNode *node = nodeStack.top().first;
3083                BspNodeGeometry *geom = nodeStack.top().second;
3084       
3085                nodeStack.pop();
3086
3087                if (node->IsLeaf())
3088                {
3089                        // test if this leaf is in valid view space
3090                        if (node->TreeValid() &&
3091                                (node != n) &&
3092                                (!onlyUnmailed || !node->Mailed()))
3093                        {
3094                                bool isAdjacent = true;
3095
3096                                if (1)
3097                                {
3098                                        // test all planes of current node if still adjacent
3099                                        for (int i = 0; (i < halfSpaces.size()) && isAdjacent; ++ i)
3100                                        {
3101                                                const int cf =
3102                                                        Polygon3::ClassifyPlane(geom->GetPolys(),
3103                                                                                                        halfSpaces[i],
3104                                                                                                        eps);
3105
3106                                                if (cf == Polygon3::FRONT_SIDE)
3107                                                {
3108                                                        isAdjacent = false;
3109                                                }
3110                                        }
3111                                }
3112                                else
3113                                {
3114                                        // TODO: why is this wrong??
3115                                        // test all planes of current node if still adjacent
3116                                        for (int i = 0; (i < nodeGeom.Size()) && isAdjacent; ++ i)
3117                                        {
3118                                                Polygon3 *poly = nodeGeom.GetPolys()[i];
3119
3120                                                const int cf =
3121                                                        Polygon3::ClassifyPlane(geom->GetPolys(),
3122                                                                                                        poly->GetSupportingPlane(),
3123                                                                                                        eps);
3124
3125                                                if (cf == Polygon3::FRONT_SIDE)
3126                                                {
3127                                                        isAdjacent = false;
3128                                                }
3129                                        }
3130                                }
3131                                // neighbor was found
3132                                if (isAdjacent)
3133                                {       
3134                                        neighbors.push_back(dynamic_cast<BspLeaf *>(node));
3135                                }
3136                        }
3137                }
3138                else
3139                {
3140                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
3141
3142                        const int cf = Polygon3::ClassifyPlane(nodeGeom.GetPolys(),
3143                                                                                                   interior->GetPlane(),
3144                                                                                                   eps);
3145                       
3146                        BspNode *front = interior->GetFront();
3147                        BspNode *back = interior->GetBack();
3148           
3149                        BspNodeGeometry *fGeom = new BspNodeGeometry();
3150                        BspNodeGeometry *bGeom = new BspNodeGeometry();
3151
3152                        geom->SplitGeometry(*fGeom,
3153                                                                *bGeom,
3154                                                                interior->GetPlane(),
3155                                                                mBoundingBox,
3156                                                                //0.0000001f);
3157                                                                eps);
3158               
3159                        if (cf == Polygon3::BACK_SIDE)
3160                        {
3161                                nodeStack.push(bspNodePair(interior->GetBack(), bGeom));
3162                                DEL_PTR(fGeom);
3163                        }
3164                        else
3165                        {
3166                                if (cf == Polygon3::FRONT_SIDE)
3167                                {
3168                                        nodeStack.push(bspNodePair(interior->GetFront(), fGeom));
3169                                        DEL_PTR(bGeom);
3170                                }
3171                                else
3172                                {       // random decision
3173                                        nodeStack.push(bspNodePair(front, fGeom));
3174                                        nodeStack.push(bspNodePair(back, bGeom));
3175                                }
3176                        }
3177                }
3178       
3179                DEL_PTR(geom);
3180        }
3181
3182        return (int)neighbors.size();
3183}
3184
3185
3186
3187int VspBspTree::FindApproximateNeighbors(BspNode *n,
3188                                                                                 vector<BspLeaf *> &neighbors,
3189                                                                                 const bool onlyUnmailed) const
3190{
3191        stack<bspNodePair> nodeStack;
3192       
3193        BspNodeGeometry nodeGeom;
3194        ConstructGeometry(n, nodeGeom);
3195       
3196        float eps = 0.01f;
3197        // split planes from the root to this node
3198        // needed to verify that we found neighbor leaf
3199        // TODO: really needed?
3200        vector<Plane3> halfSpaces;
3201        ExtractHalfSpaces(n, halfSpaces);
3202
3203
3204        BspNodeGeometry *rgeom = new BspNodeGeometry();
3205        ConstructGeometry(mRoot, *rgeom);
3206
3207        nodeStack.push(bspNodePair(mRoot, rgeom));
3208
3209        while (!nodeStack.empty())
3210        {
3211                BspNode *node = nodeStack.top().first;
3212                BspNodeGeometry *geom = nodeStack.top().second;
3213       
3214                nodeStack.pop();
3215
3216                if (node->IsLeaf())
3217                {
3218                        // test if this leaf is in valid view space
3219                        if (node->TreeValid() &&
3220                                (node != n) &&
3221                                (!onlyUnmailed || !node->Mailed()))
3222                        {
3223                                bool isAdjacent = true;
3224
3225                                // neighbor was found
3226                                if (isAdjacent)
3227                                {       
3228                                        neighbors.push_back(dynamic_cast<BspLeaf *>(node));
3229                                }
3230                        }
3231                }
3232                else
3233                {
3234                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
3235
3236                        const int cf = Polygon3::ClassifyPlane(nodeGeom.GetPolys(),
3237                                                                                                   interior->GetPlane(),
3238                                                                                                   eps);
3239                       
3240                        BspNode *front = interior->GetFront();
3241                        BspNode *back = interior->GetBack();
3242           
3243                        BspNodeGeometry *fGeom = new BspNodeGeometry();
3244                        BspNodeGeometry *bGeom = new BspNodeGeometry();
3245
3246                        geom->SplitGeometry(*fGeom,
3247                                                                *bGeom,
3248                                                                interior->GetPlane(),
3249                                                                mBoundingBox,
3250                                                                //0.0000001f);
3251                                                                eps);
3252               
3253                        if (cf == Polygon3::BACK_SIDE)
3254                        {
3255                                nodeStack.push(bspNodePair(interior->GetBack(), bGeom));
3256                                DEL_PTR(fGeom);
3257                                }
3258                        else
3259                        {
3260                                if (cf == Polygon3::FRONT_SIDE)
3261                                {
3262                                        nodeStack.push(bspNodePair(interior->GetFront(), fGeom));
3263                                        DEL_PTR(bGeom);
3264                                }
3265                                else
3266                                {       // random decision
3267                                        nodeStack.push(bspNodePair(front, fGeom));
3268                                        nodeStack.push(bspNodePair(back, bGeom));
3269                                }
3270                        }
3271                }
3272       
3273                DEL_PTR(geom);
3274        }
3275
3276        return (int)neighbors.size();
3277}
3278
3279
3280
3281BspLeaf *VspBspTree::GetRandomLeaf(const Plane3 &halfspace)
3282{
3283    stack<BspNode *> nodeStack;
3284        nodeStack.push(mRoot);
3285
3286        int mask = rand();
3287
3288        while (!nodeStack.empty())
3289        {
3290                BspNode *node = nodeStack.top();
3291                nodeStack.pop();
3292
3293                if (node->IsLeaf())
3294                {
3295                        return dynamic_cast<BspLeaf *>(node);
3296                }
3297                else
3298                {
3299                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
3300                        BspNode *next;
3301                        BspNodeGeometry geom;
3302
3303                        // todo: not very efficient: constructs full cell everytime
3304                        ConstructGeometry(interior, geom);
3305
3306                        const int cf =
3307                                Polygon3::ClassifyPlane(geom.GetPolys(), halfspace, mEpsilon);
3308
3309                        if (cf == Polygon3::BACK_SIDE)
3310                                next = interior->GetFront();
3311                        else
3312                                if (cf == Polygon3::FRONT_SIDE)
3313                                        next = interior->GetFront();
3314                        else
3315                        {
3316                                // random decision
3317                                if (mask & 1)
3318                                        next = interior->GetBack();
3319                                else
3320                                        next = interior->GetFront();
3321                                mask = mask >> 1;
3322                        }
3323
3324                        nodeStack.push(next);
3325                }
3326        }
3327
3328        return NULL;
3329}
3330
3331
3332BspLeaf *VspBspTree::GetRandomLeaf(const bool onlyUnmailed)
3333{
3334        stack<BspNode *> nodeStack;
3335
3336        nodeStack.push(mRoot);
3337
3338        int mask = rand();
3339
3340        while (!nodeStack.empty())
3341        {
3342                BspNode *node = nodeStack.top();
3343                nodeStack.pop();
3344
3345                if (node->IsLeaf())
3346                {
3347                        if ( (!onlyUnmailed || !node->Mailed()) )
3348                                return dynamic_cast<BspLeaf *>(node);
3349                }
3350                else
3351                {
3352                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
3353
3354                        // random decision
3355                        if (mask & 1)
3356                                nodeStack.push(interior->GetBack());
3357                        else
3358                                nodeStack.push(interior->GetFront());
3359
3360                        mask = mask >> 1;
3361                }
3362        }
3363
3364        return NULL;
3365}
3366
3367
3368int VspBspTree::ComputePvsSize(const RayInfoContainer &rays) const
3369{
3370        int pvsSize = 0;
3371
3372        RayInfoContainer::const_iterator rit, rit_end = rays.end();
3373
3374        Intersectable::NewMail();
3375
3376        for (rit = rays.begin(); rit != rays.end(); ++ rit)
3377        {
3378                VssRay *ray = (*rit).mRay;
3379
3380                if (COUNT_ORIGIN_OBJECTS && ray->mOriginObject)
3381                {
3382                        if (!ray->mOriginObject->Mailed())
3383                        {
3384                                ray->mOriginObject->Mail();
3385                                ++ pvsSize;
3386                        }
3387                }
3388
3389                if (ray->mTerminationObject)
3390                {
3391                        if (!ray->mTerminationObject->Mailed())
3392                        {
3393                                ray->mTerminationObject->Mail();
3394                                ++ pvsSize;
3395                        }
3396                }
3397        }
3398
3399        return pvsSize;
3400}
3401
3402
3403float VspBspTree::GetEpsilon() const
3404{
3405        return mEpsilon;
3406}
3407
3408
3409int VspBspTree::SplitPolygons(const Plane3 &plane,
3410                                                          PolygonContainer &polys,
3411                                                          PolygonContainer &frontPolys,
3412                                                          PolygonContainer &backPolys,
3413                                                          PolygonContainer &coincident) const
3414{
3415        int splits = 0;
3416
3417        PolygonContainer::const_iterator it, it_end = polys.end();
3418
3419        for (it = polys.begin(); it != polys.end(); ++ it)     
3420        {
3421                Polygon3 *poly = *it;
3422
3423                // classify polygon
3424                const int cf = poly->ClassifyPlane(plane, mEpsilon);
3425
3426                switch (cf)
3427                {
3428                        case Polygon3::COINCIDENT:
3429                                coincident.push_back(poly);
3430                                break;
3431                        case Polygon3::FRONT_SIDE:
3432                                frontPolys.push_back(poly);
3433                                break;
3434                        case Polygon3::BACK_SIDE:
3435                                backPolys.push_back(poly);
3436                                break;
3437                        case Polygon3::SPLIT:
3438                                backPolys.push_back(poly);
3439                                frontPolys.push_back(poly);
3440                                ++ splits;
3441                                break;
3442                        default:
3443                Debug << "SHOULD NEVER COME HERE\n";
3444                                break;
3445                }
3446        }
3447
3448        return splits;
3449}
3450
3451
3452int VspBspTree::CastLineSegment(const Vector3 &origin,
3453                                                                const Vector3 &termination,
3454                                                                ViewCellContainer &viewcells)
3455{
3456        int hits = 0;
3457        stack<BspRayTraversalData> tStack;
3458
3459        float mint = 0.0f, maxt = 1.0f;
3460
3461        //ViewCell::NewMail();
3462
3463        Vector3 entp = origin;
3464        Vector3 extp = termination;
3465
3466        BspNode *node = mRoot;
3467        BspNode *farChild = NULL;
3468
3469        float t;
3470        const float thresh = 1e-6f; // matt: change this to adjustable value
3471       
3472        while (1)
3473        {
3474                if (!node->IsLeaf())
3475                {
3476                        BspInterior *in = dynamic_cast<BspInterior *>(node);
3477
3478                        Plane3 splitPlane = in->GetPlane();
3479                       
3480                        const int entSide = splitPlane.Side(entp, thresh);
3481                        const int extSide = splitPlane.Side(extp, thresh);
3482
3483                        if (entSide < 0)
3484                        {
3485                                node = in->GetBack();
3486                               
3487                                // plane does not split ray => no far child
3488                                if (extSide <= 0)
3489                                        continue;
3490 
3491                                farChild = in->GetFront(); // plane splits ray
3492                        }
3493                        else if (entSide > 0)
3494                        {
3495                                node = in->GetFront();
3496
3497                                if (extSide >= 0) // plane does not split ray => no far child
3498                                        continue;
3499
3500                                farChild = in->GetBack(); // plane splits ray
3501                        }
3502                        else // one of the ray end points is on the plane
3503                        {       
3504                                // NOTE: what to do if ray is coincident with plane?
3505                                if (extSide < 0)
3506                                        node = in->GetBack();
3507                                else //if (extSide > 0)
3508                                        node = in->GetFront();
3509                                //else break; // coincident => count no intersections
3510
3511                                continue; // no far child
3512                        }
3513
3514                        // push data for far child
3515                        tStack.push(BspRayTraversalData(farChild, extp));
3516
3517                        // find intersection of ray segment with plane
3518                        extp = splitPlane.FindIntersection(origin, extp, &t);
3519                }
3520                else
3521                {
3522                        // reached leaf => intersection with view cell
3523                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
3524                        ViewCell *viewCell;
3525                       
3526                        // question: always contribute to leaf or to currently active view cell?
3527                        if (0)
3528                                viewCell = mViewCellsTree->GetActiveViewCell(leaf->GetViewCell());
3529                        else
3530                                viewCell = leaf->GetViewCell();
3531
3532                        if (!viewCell->Mailed())
3533                        {
3534                                viewcells.push_back(viewCell);
3535                                viewCell->Mail();
3536                                ++ hits;
3537                        }
3538
3539                        //-- fetch the next far child from the stack
3540                        if (tStack.empty())
3541                                break;
3542
3543                        entp = extp;
3544                       
3545                        const BspRayTraversalData &s = tStack.top();
3546
3547                        node = s.mNode;
3548                        extp = s.mExitPoint;
3549
3550                        tStack.pop();
3551                }
3552        }
3553
3554        return hits;
3555}
3556
3557
3558
3559
3560int VspBspTree::TreeDistance(BspNode *n1, BspNode *n2) const
3561{
3562        std::deque<BspNode *> path1;
3563        BspNode *p1 = n1;
3564
3565        // create path from node 1 to root
3566        while (p1)
3567        {
3568                if (p1 == n2) // second node on path
3569                        return (int)path1.size();
3570
3571                path1.push_front(p1);
3572                p1 = p1->GetParent();
3573        }
3574
3575        int depth = n2->GetDepth();
3576        int d = depth;
3577
3578        BspNode *p2 = n2;
3579
3580        // compare with same depth
3581        while (1)
3582        {
3583                if ((d < (int)path1.size()) && (p2 == path1[d]))
3584                        return (depth - d) + ((int)path1.size() - 1 - d);
3585
3586                -- d;
3587                p2 = p2->GetParent();
3588        }
3589
3590        return 0; // never come here
3591}
3592
3593
3594BspNode *VspBspTree::CollapseTree(BspNode *node, int &collapsed)
3595{
3596// TODO
3597#if HAS_TO_BE_REDONE
3598        if (node->IsLeaf())
3599                return node;
3600
3601        BspInterior *interior = dynamic_cast<BspInterior *>(node);
3602
3603        BspNode *front = CollapseTree(interior->GetFront(), collapsed);
3604        BspNode *back = CollapseTree(interior->GetBack(), collapsed);
3605
3606        if (front->IsLeaf() && back->IsLeaf())
3607        {
3608                BspLeaf *frontLeaf = dynamic_cast<BspLeaf *>(front);
3609                BspLeaf *backLeaf = dynamic_cast<BspLeaf *>(back);
3610
3611                //-- collapse tree
3612                if (frontLeaf->GetViewCell() == backLeaf->GetViewCell())
3613                {
3614                        BspViewCell *vc = frontLeaf->GetViewCell();
3615
3616                        BspLeaf *leaf = new BspLeaf(interior->GetParent(), vc);
3617                        leaf->SetTreeValid(frontLeaf->TreeValid());
3618
3619                        // replace a link from node's parent
3620                        if (leaf->GetParent())
3621                                leaf->GetParent()->ReplaceChildLink(node, leaf);
3622                        else
3623                                mRoot = leaf;
3624
3625                        ++ collapsed;
3626                        delete interior;
3627
3628                        return leaf;
3629                }
3630        }
3631#endif
3632        return node;
3633}
3634
3635
3636int VspBspTree::CollapseTree()
3637{
3638        int collapsed = 0;
3639        //TODO
3640#if HAS_TO_BE_REDONE
3641        (void)CollapseTree(mRoot, collapsed);
3642
3643        // revalidate leaves
3644        RepairViewCellsLeafLists();
3645#endif
3646        return collapsed;
3647}
3648
3649
3650void VspBspTree::RepairViewCellsLeafLists()
3651{
3652// TODO
3653#if HAS_TO_BE_REDONE
3654        // list not valid anymore => clear
3655        stack<BspNode *> nodeStack;
3656        nodeStack.push(mRoot);
3657
3658        ViewCell::NewMail();
3659
3660        while (!nodeStack.empty())
3661        {
3662                BspNode *node = nodeStack.top();
3663                nodeStack.pop();
3664
3665                if (node->IsLeaf())
3666                {
3667                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
3668
3669                        BspViewCell *viewCell = leaf->GetViewCell();
3670
3671                        if (!viewCell->Mailed())
3672                        {
3673                                viewCell->mLeaves.clear();
3674                                viewCell->Mail();
3675                        }
3676       
3677                        viewCell->mLeaves.push_back(leaf);
3678
3679                }
3680                else
3681                {
3682                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
3683
3684                        nodeStack.push(interior->GetFront());
3685                        nodeStack.push(interior->GetBack());
3686                }
3687        }
3688// TODO
3689#endif
3690}
3691
3692
3693int VspBspTree::CastBeam(Beam &beam)
3694{
3695    stack<bspNodePair> nodeStack;
3696        BspNodeGeometry *rgeom = new BspNodeGeometry();
3697        ConstructGeometry(mRoot, *rgeom);
3698
3699        nodeStack.push(bspNodePair(mRoot, rgeom));
3700 
3701        ViewCell::NewMail();
3702
3703        while (!nodeStack.empty())
3704        {
3705                BspNode *node = nodeStack.top().first;
3706                BspNodeGeometry *geom = nodeStack.top().second;
3707                nodeStack.pop();
3708               
3709                AxisAlignedBox3 box;
3710                geom->GetBoundingBox(box);
3711
3712                const int side = beam.ComputeIntersection(box);
3713               
3714                switch (side)
3715                {
3716                case -1:
3717                        CollectViewCells(node, true, beam.mViewCells, true);
3718                        break;
3719                case 0:
3720                       
3721                        if (node->IsLeaf())
3722                        {
3723                                BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
3724                       
3725                                if (!leaf->GetViewCell()->Mailed() && leaf->TreeValid())
3726                                {
3727                                        leaf->GetViewCell()->Mail();
3728                                        beam.mViewCells.push_back(leaf->GetViewCell());
3729                                }
3730                        }
3731                        else
3732                        {
3733                                BspInterior *interior = dynamic_cast<BspInterior *>(node);
3734                       
3735                                BspNode *first = interior->GetFront();
3736                                BspNode *second = interior->GetBack();
3737           
3738                                BspNodeGeometry *firstGeom = new BspNodeGeometry();
3739                                BspNodeGeometry *secondGeom = new BspNodeGeometry();
3740
3741                                geom->SplitGeometry(*firstGeom,
3742                                                                        *secondGeom,
3743                                                                        interior->GetPlane(),
3744                                                                        mBoundingBox,
3745                                                                        //0.0000001f);
3746                                                                        mEpsilon);
3747
3748                                // decide on the order of the nodes
3749                                if (DotProd(beam.mPlanes[0].mNormal,
3750                                        interior->GetPlane().mNormal) > 0)
3751                                {
3752                                        swap(first, second);
3753                                        swap(firstGeom, secondGeom);
3754                                }
3755
3756                                nodeStack.push(bspNodePair(first, firstGeom));
3757                                nodeStack.push(bspNodePair(second, secondGeom));
3758                        }
3759                       
3760                        break;
3761                default:
3762                        // default: cull
3763                        break;
3764                }
3765               
3766                DEL_PTR(geom);
3767               
3768        }
3769
3770        return (int)beam.mViewCells.size();
3771}
3772
3773
3774void VspBspTree::SetViewCellsManager(ViewCellsManager *vcm)
3775{
3776        mViewCellsManager = vcm;
3777}
3778
3779
3780int VspBspTree::CollectMergeCandidates(const vector<BspLeaf *> leaves,
3781                                                                           vector<MergeCandidate> &candidates)
3782{
3783        BspLeaf::NewMail();
3784       
3785        vector<BspLeaf *>::const_iterator it, it_end = leaves.end();
3786
3787        int numCandidates = 0;
3788
3789        // find merge candidates and push them into queue
3790        for (it = leaves.begin(); it != it_end; ++ it)
3791        {
3792                BspLeaf *leaf = *it;
3793               
3794                // the same leaves must not be part of two merge candidates
3795                leaf->Mail();
3796               
3797                vector<BspLeaf *> neighbors;
3798               
3799                // appoximate neighbor search has slightl relaxed constraints
3800                if (1)
3801                        FindNeighbors(leaf, neighbors, true);
3802                else
3803                        FindApproximateNeighbors(leaf, neighbors, true);
3804
3805                vector<BspLeaf *>::const_iterator nit, nit_end = neighbors.end();
3806
3807                // TODO: test if at least one ray goes from one leaf to the other
3808                for (nit = neighbors.begin(); nit != nit_end; ++ nit)
3809                {
3810                        if ((*nit)->GetViewCell() != leaf->GetViewCell())
3811                        {
3812                                MergeCandidate mc(leaf->GetViewCell(), (*nit)->GetViewCell());
3813
3814                                if (!leaf->GetViewCell()->GetPvs().Empty() ||
3815                                        !(*nit)->GetViewCell()->GetPvs().Empty() ||
3816                    leaf->IsSibling(*nit))
3817                                {
3818                                        candidates.push_back(mc);
3819                                }
3820
3821                                ++ numCandidates;
3822                                if ((numCandidates % 1000) == 0)
3823                                {
3824                                        cout << "collected " << numCandidates << " merge candidates" << endl;
3825                                }
3826                        }
3827                }
3828        }
3829
3830        Debug << "merge queue: " << (int)candidates.size() << endl;
3831        Debug << "leaves in queue: " << numCandidates << endl;
3832       
3833
3834        return (int)leaves.size();
3835}
3836
3837
3838int VspBspTree::CollectMergeCandidates(const VssRayContainer &rays,
3839                                                                           vector<MergeCandidate> &candidates)
3840{
3841        ViewCell::NewMail();
3842        long startTime = GetTime();
3843       
3844        map<BspLeaf *, vector<BspLeaf*> > neighborMap;
3845        ViewCellContainer::const_iterator iit;
3846
3847        int numLeaves = 0;
3848       
3849        BspLeaf::NewMail();
3850
3851        for (int i = 0; i < (int)rays.size(); ++ i)
3852        { 
3853                VssRay *ray = rays[i];
3854       
3855                // traverse leaves stored in the rays and compare and
3856                // merge consecutive leaves (i.e., the neighbors in the tree)
3857                if (ray->mViewCells.size() < 2)
3858                        continue;
3859
3860                iit = ray->mViewCells.begin();
3861                BspViewCell *bspVc = dynamic_cast<BspViewCell *>(*(iit ++));
3862                BspLeaf *leaf = bspVc->mLeaves[0];
3863               
3864                // traverse intersections
3865                // consecutive leaves are neighbors => add them to queue
3866                for (; iit != ray->mViewCells.end(); ++ iit)
3867                {
3868                        // next pair
3869                        BspLeaf *prevLeaf = leaf;
3870                        bspVc = dynamic_cast<BspViewCell *>(*iit);
3871            leaf = bspVc->mLeaves[0]; // exactly one leaf
3872
3873                        // view space not valid or same view cell
3874                        if (!leaf->TreeValid() || !prevLeaf->TreeValid() ||
3875                                (leaf->GetViewCell() == prevLeaf->GetViewCell()))
3876                                continue;
3877
3878                vector<BspLeaf *> &neighbors = neighborMap[leaf];
3879                       
3880                        bool found = false;
3881
3882                        // both leaves inserted in queue already =>
3883                        // look if double pair already exists
3884                        if (leaf->Mailed() && prevLeaf->Mailed())
3885                        {
3886                                vector<BspLeaf *>::const_iterator it, it_end = neighbors.end();
3887                               
3888                for (it = neighbors.begin(); !found && (it != it_end); ++ it)
3889                                        if (*it == prevLeaf)
3890                                                found = true; // already in queue
3891                        }
3892               
3893                        if (!found)
3894                        {
3895                                // this pair is not in map yet
3896                                // => insert into the neighbor map and the queue
3897                                neighbors.push_back(prevLeaf);
3898                                neighborMap[prevLeaf].push_back(leaf);
3899
3900                                leaf->Mail();
3901                                prevLeaf->Mail();
3902               
3903                                MergeCandidate mc(leaf->GetViewCell(), prevLeaf->GetViewCell());
3904                               
3905                                candidates.push_back(mc);
3906
3907                                if (((int)candidates.size() % 1000) == 0)
3908                                {
3909                                        cout << "collected " << (int)candidates.size() << " merge candidates" << endl;
3910                                }
3911                        }
3912        }
3913        }
3914
3915        Debug << "neighbormap size: " << (int)neighborMap.size() << endl;
3916        Debug << "merge queue: " << (int)candidates.size() << endl;
3917        Debug << "leaves in queue: " << numLeaves << endl;
3918
3919
3920        //-- collect the leaves which haven't been found by ray casting
3921        if (0)
3922        {
3923                cout << "finding additional merge candidates using geometry" << endl;
3924                vector<BspLeaf *> leaves;
3925                CollectLeaves(leaves, true);
3926                Debug << "found " << (int)leaves.size() << " new leaves" << endl << endl;
3927                CollectMergeCandidates(leaves, candidates);
3928        }
3929
3930        return numLeaves;
3931}
3932
3933
3934
3935
3936ViewCell *VspBspTree::GetViewCell(const Vector3 &point, const bool active)
3937{
3938        if (mRoot == NULL)
3939                return NULL;
3940
3941        stack<BspNode *> nodeStack;
3942        nodeStack.push(mRoot);
3943 
3944        ViewCellLeaf *viewcell = NULL;
3945 
3946        while (!nodeStack.empty()) 
3947        {
3948                BspNode *node = nodeStack.top();
3949                nodeStack.pop();
3950       
3951                if (node->IsLeaf())
3952                {
3953                        viewcell = dynamic_cast<BspLeaf *>(node)->GetViewCell();
3954                        break;
3955                }
3956                else   
3957                {       
3958                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
3959       
3960                        // random decision
3961                        if (interior->GetPlane().Side(point) < 0)
3962                                nodeStack.push(interior->GetBack());
3963                        else
3964                                nodeStack.push(interior->GetFront());
3965                }
3966        }
3967 
3968        if (active)
3969                return mViewCellsTree->GetActiveViewCell(viewcell);
3970        else
3971                return viewcell;
3972}
3973
3974
3975bool VspBspTree::ViewPointValid(const Vector3 &viewPoint) const
3976{
3977        BspNode *node = mRoot;
3978
3979        while (1)
3980        {
3981                // early exit
3982                if (node->TreeValid())
3983                        return true;
3984
3985                if (node->IsLeaf())
3986                        return false;
3987                       
3988                BspInterior *in = dynamic_cast<BspInterior *>(node);
3989                                       
3990                if (in->GetPlane().Side(viewPoint) <= 0)
3991                {
3992                        node = in->GetBack();
3993                }
3994                else
3995                {
3996                        node = in->GetFront();
3997                }
3998        }
3999
4000        // should never come here
4001        return false;
4002}
4003
4004
4005void VspBspTree::PropagateUpValidity(BspNode *node)
4006{
4007        const bool isValid = node->TreeValid();
4008
4009        // propagative up invalid flag until only invalid nodes exist over this node
4010        if (!isValid)
4011        {
4012                while (!node->IsRoot() && node->GetParent()->TreeValid())
4013                {
4014                        node = node->GetParent();
4015                        node->SetTreeValid(false);
4016                }
4017        }
4018        else
4019        {
4020                // propagative up valid flag until one of the subtrees is invalid
4021                while (!node->IsRoot() && !node->TreeValid())
4022                {
4023            node = node->GetParent();
4024                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
4025                       
4026                        // the parent is valid iff both leaves are valid
4027                        node->SetTreeValid(interior->GetBack()->TreeValid() &&
4028                                                           interior->GetFront()->TreeValid());
4029                }
4030        }
4031}
4032
4033
4034bool VspBspTree::Export(OUT_STREAM &stream)
4035{
4036        ExportNode(mRoot, stream);
4037        return true;
4038}
4039
4040
4041void VspBspTree::ExportNode(BspNode *node, OUT_STREAM &stream)
4042{
4043        if (node->IsLeaf())
4044        {
4045                BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
4046                ViewCell *viewCell = mViewCellsTree->GetActiveViewCell(leaf->GetViewCell());
4047
4048                int id = -1;
4049                if (viewCell != mOutOfBoundsCell)
4050                        id = viewCell->GetId();
4051
4052                stream << "<Leaf viewCellId=\"" << id << "\" />" << endl;
4053        }
4054        else
4055        {
4056                BspInterior *interior = dynamic_cast<BspInterior *>(node);
4057       
4058                Plane3 plane = interior->GetPlane();
4059                stream << "<Interior plane=\"" << plane.mNormal.x << " "
4060                           << plane.mNormal.y << " " << plane.mNormal.z << " "
4061                           << plane.mD << "\">" << endl;
4062
4063                ExportNode(interior->GetBack(), stream);
4064                ExportNode(interior->GetFront(), stream);
4065
4066                stream << "</Interior>" << endl;
4067        }
4068}
4069
4070}
Note: See TracBrowser for help on using the repository browser.