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

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