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

Revision 1016, 95.3 KB checked in by mattausch, 18 years ago (diff)

worked on view space / object space partition

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