source: GTP/trunk/Lib/Vis/Preprocessing/src/VspOspTree.cpp @ 1006

Revision 1006, 47.5 KB checked in by mattausch, 18 years ago (diff)

started viewspace-objectspace subdivision
removed memory leaks

Line 
1#include <stack>
2#include <time.h>
3#include <iomanip>
4
5#include "Plane3.h"
6#include "VspOspTree.h"
7#include "Mesh.h"
8#include "common.h"
9#include "ViewCell.h"
10#include "Environment.h"
11#include "Polygon3.h"
12#include "Ray.h"
13#include "AxisAlignedBox3.h"
14#include "Exporter.h"
15#include "Plane3.h"
16#include "ViewCellBsp.h"
17#include "ViewCellsManager.h"
18#include "Beam.h"
19
20namespace GtpVisibilityPreprocessor {
21
22#define USE_FIXEDPOINT_T 0
23
24
25//-- static members
26
27int VspOspTree::sFrontId = 0;
28int VspOspTree::sBackId = 0;
29int VspOspTree::sFrontAndBackId = 0;
30
31
32
33// pvs penalty can be different from pvs size
34inline static float EvalPvsPenalty(const int pvs,
35                                                                   const int lower,
36                                                                   const int upper)
37{
38        // clamp to minmax values
39        if (pvs < lower)
40                return (float)lower;
41        if (pvs > upper)
42                return (float)upper;
43
44        return (float)pvs;
45}
46
47
48
49
50/******************************************************************************/
51/*                       class VspOspTree implementation                      */
52/******************************************************************************/
53
54
55VspOspTree::VspOspTree():
56mRoot(NULL),
57mOutOfBoundsCell(NULL),
58mStoreRays(false),
59mUseRandomAxis(false),
60mTimeStamp(1)
61{
62        bool randomize = false;
63        Environment::GetSingleton()->GetBoolValue("VspOspTree.Construction.randomize", randomize);
64        if (randomize)
65                Randomize(); // initialise random generator for heuristics
66
67        //-- termination criteria for autopartition
68        Environment::GetSingleton()->GetIntValue("VspOspTree.Termination.maxDepth", mTermMaxDepth);
69        Environment::GetSingleton()->GetIntValue("VspOspTree.Termination.minPvs", mTermMinPvs);
70        Environment::GetSingleton()->GetIntValue("VspOspTree.Termination.minRays", mTermMinRays);
71        Environment::GetSingleton()->GetFloatValue("VspOspTree.Termination.minProbability", mTermMinProbability);
72        Environment::GetSingleton()->GetFloatValue("VspOspTree.Termination.maxRayContribution", mTermMaxRayContribution);
73        Environment::GetSingleton()->GetFloatValue("VspOspTree.Termination.maxCostRatio", mTermMaxCostRatio);
74        Environment::GetSingleton()->GetIntValue("VspOspTree.Termination.missTolerance", mTermMissTolerance);
75        Environment::GetSingleton()->GetIntValue("VspOspTree.Termination.maxViewCells", mMaxViewCells);
76
77        //-- max cost ratio for early tree termination
78        Environment::GetSingleton()->GetFloatValue("VspOspTree.Termination.maxCostRatio", mTermMaxCostRatio);
79
80        Environment::GetSingleton()->GetFloatValue("VspOspTree.Termination.minGlobalCostRatio", mTermMinGlobalCostRatio);
81        Environment::GetSingleton()->GetIntValue("VspOspTree.Termination.globalCostMissTolerance", mTermGlobalCostMissTolerance);
82
83        // HACK//mTermMinPolygons = 25;
84
85        //-- factors for bsp tree split plane heuristics
86        Environment::GetSingleton()->GetFloatValue("VspOspTree.Termination.ct_div_ci", mCtDivCi);
87
88        //-- partition criteria
89        Environment::GetSingleton()->GetFloatValue("VspOspTree.Construction.epsilon", mEpsilon);
90
91        // if only the driving axis is used for axis aligned split
92        Environment::GetSingleton()->GetBoolValue("VspOspTree.splitUseOnlyDrivingAxis", mOnlyDrivingAxis);
93       
94        //Environment::GetSingleton()->GetFloatValue("VspOspTree.maxTotalMemory", mMaxTotalMemory);
95        Environment::GetSingleton()->GetFloatValue("VspOspTree.maxStaticMemory", mMaxMemory);
96
97        Environment::GetSingleton()->GetBoolValue("VspOspTree.useCostHeuristics", mUseCostHeuristics);
98        Environment::GetSingleton()->GetBoolValue("VspOspTree.simulateOctree", mCirculatingAxis);
99        Environment::GetSingleton()->GetBoolValue("VspOspTree.useRandomAxis", mUseRandomAxis);
100        Environment::GetSingleton()->GetIntValue("VspOspTree.nodePriorityQueueType", mNodePriorityQueueType);
101       
102        char subdivisionStatsLog[100];
103        Environment::GetSingleton()->GetStringValue("VspOspTree.subdivisionStats", subdivisionStatsLog);
104        mSubdivisionStats.open(subdivisionStatsLog);
105
106        Environment::GetSingleton()->GetFloatValue("VspOspTree.Construction.minBand", mMinBand);
107        Environment::GetSingleton()->GetFloatValue("VspOspTree.Construction.maxBand", mMaxBand);
108       
109
110        //-- debug output
111
112        Debug << "******* VSP BSP options ******** " << endl;
113    Debug << "max depth: " << mTermMaxDepth << endl;
114        Debug << "min PVS: " << mTermMinPvs << endl;
115        Debug << "min probabiliy: " << mTermMinProbability << endl;
116        Debug << "min rays: " << mTermMinRays << endl;
117        Debug << "max ray contri: " << mTermMaxRayContribution << endl;
118        Debug << "max cost ratio: " << mTermMaxCostRatio << endl;
119        Debug << "miss tolerance: " << mTermMissTolerance << endl;
120        Debug << "max view cells: " << mMaxViewCells << endl;
121        Debug << "randomize: " << randomize << endl;
122
123        Debug << "min global cost ratio: " << mTermMinGlobalCostRatio << endl;
124        Debug << "global cost miss tolerance: " << mTermGlobalCostMissTolerance << endl;
125        Debug << "only driving axis: " << mOnlyDrivingAxis << endl;
126        Debug << "max memory: " << mMaxMemory << endl;
127        Debug << "use cost heuristics: " << mUseCostHeuristics << endl;
128        Debug << "subdivision stats log: " << subdivisionStatsLog << endl;
129        Debug << "use random axis: " << mUseRandomAxis << endl;
130        Debug << "priority queue type: " << mNodePriorityQueueType << endl;
131        Debug << "circulating axis: " << mCirculatingAxis << endl;
132        Debug << "minband: " << mMinBand << endl;
133        Debug << "maxband: " << mMaxBand << endl;
134       
135
136        mSplitCandidates = new vector<SortableEntry>;
137
138        Debug << endl;
139}
140
141
142BspViewCell *VspOspTree::GetOutOfBoundsCell()
143{
144        return mOutOfBoundsCell;
145}
146
147
148BspViewCell *VspOspTree::GetOrCreateOutOfBoundsCell()
149{
150        if (!mOutOfBoundsCell)
151        {
152                mOutOfBoundsCell = new BspViewCell();
153                mOutOfBoundsCell->SetId(-1);
154                mOutOfBoundsCell->SetValid(false);
155        }
156
157        return mOutOfBoundsCell;
158}
159
160
161const BspTreeStatistics &VspOspTree::GetStatistics() const
162{
163        return mBspStats;
164}
165
166
167VspOspTree::~VspOspTree()
168{
169        DEL_PTR(mRoot);
170        DEL_PTR(mSplitCandidates);
171}
172
173void VspOspTree::Construct(const VssRayContainer &sampleRays,
174                                                   AxisAlignedBox3 *forcedBoundingBox)
175{
176        mBspStats.nodes = 1;
177        mBox.Initialize();      // initialise BSP tree bounding box
178
179        if (forcedBoundingBox)
180                mBox = *forcedBoundingBox;
181       
182        PolygonContainer polys;
183        RayInfoContainer *rays = new RayInfoContainer();
184
185        VssRayContainer::const_iterator rit, rit_end = sampleRays.end();
186
187        long startTime = GetTime();
188
189        cout << "Extracting polygons from rays ... ";
190
191        Intersectable::NewMail();
192
193        int numObj = 0;
194
195        //-- store rays
196        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
197        {
198                VssRay *ray = *rit;
199
200                float minT, maxT;
201
202                static Ray hray;
203                hray.Init(*ray);
204
205                // TODO: not very efficient to implictly cast between rays types
206                if (mBox.GetRaySegment(hray, minT, maxT))
207                {
208                        float len = ray->Length();
209
210                        if (!len)
211                                len = Limits::Small;
212
213                        rays->push_back(RayInfo(ray, minT / len, maxT / len));
214                }
215        }
216
217        mTermMinProbability *= mBox.GetVolume();
218
219        mGlobalCostMisses = 0;
220
221        cout << "finished" << endl;
222
223        // use split cost priority queue
224        Construct(rays);
225}
226
227
228// TODO: return memory usage in MB
229float VspOspTree::GetMemUsage() const
230{
231        return (float)
232                 (sizeof(VspOspTree) +
233                  mBspStats.Leaves() * sizeof(BspLeaf) +
234                  mCreatedViewCells * sizeof(BspViewCell) +
235                  mBspStats.pvs * sizeof(ObjectPvsData) +
236                  mBspStats.Interior() * sizeof(BspInterior) +
237                  mBspStats.accumRays * sizeof(RayInfo)) / (1024.0f * 1024.0f);
238}
239
240
241void VspOspTree::Construct(RayInfoContainer *rays)
242{
243        VspOspSplitQueue tQueue;
244
245        mRoot = new BspLeaf();
246
247        const float prop = mBox.GetVolume();
248
249        VspOspTraversalData tData(mRoot,
250                                                          0,
251                                                          rays,
252                              ComputePvsSize(*rays),
253                                                          prop,
254                                                          mBox);
255
256
257        // compute first split candidate
258        VspOspSplitCandidate splitCandidate;
259        EvalSplitCandidate(tData, splitCandidate);
260
261        tQueue.push(splitCandidate);
262
263        mTotalCost = tData.mPvs * tData.mProbability / mBox.GetVolume();
264        mTotalPvsSize = tData.mPvs;
265       
266        mSubdivisionStats
267                        << "#ViewCells\n1\n" <<  endl
268                        << "#RenderCostDecrease\n0\n" << endl
269                        << "#SplitCandidateCost\n0\n" << endl
270                        << "#TotalRenderCost\n" << mTotalCost << endl
271                        << "#AvgRenderCost\n" << mTotalPvsSize << endl;
272
273        Debug << "total cost: " << mTotalCost << endl;
274       
275       
276        mBspStats.Start();
277        cout << "Constructing vsp bsp tree ... \n";
278
279        long startTime = GetTime();     
280        int nLeaves = 500;
281        int nViewCells = 500;
282
283        // used for intermediate time measurements and progress
284        long interTime = GetTime();     
285
286        mOutOfMemory = false;
287
288        mCreatedViewCells = 0;
289       
290        while (!tQueue.empty())
291        {
292                splitCandidate = tQueue.top();
293            tQueue.pop();               
294
295                // cost ratio of cost decrease / totalCost
296                float costRatio = splitCandidate.GetCost() / mTotalCost;
297
298                //Debug << "cost ratio: " << costRatio << endl;
299
300                if (costRatio < mTermMinGlobalCostRatio)
301                        ++ mGlobalCostMisses;
302               
303                if (0 && !mOutOfMemory)
304                {
305                        float mem = GetMemUsage();
306
307                        if (mem > mMaxMemory)
308                        {
309                                mOutOfMemory = true;
310                                Debug << "memory limit reached: " << mem << endl;
311                        }
312                }
313
314                // subdivide leaf node
315                BspNode *r = Subdivide(tQueue, splitCandidate);
316
317                if (r == mRoot)
318                        Debug << "VSP BSP tree construction time spent at root: "
319                                  << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
320
321                if (mBspStats.Leaves() >= nLeaves)
322                {
323                        nLeaves += 500;
324
325                        cout << "leaves=" << mBspStats.Leaves() << endl;
326                        Debug << "needed "
327                                  << TimeDiff(interTime, GetTime())*1e-3
328                                  << " secs to create 500 view cells" << endl;
329                        interTime = GetTime();
330                }
331
332                if (mCreatedViewCells == nViewCells)
333                {
334                        nViewCells += 500;
335
336                        cout << "generated " << mCreatedViewCells << " viewcells" << endl;
337                }
338        }
339
340        Debug << "Used Memory: " << GetMemUsage() << " MB" << endl << endl;
341        cout << "finished\n";
342
343        mBspStats.Stop();
344}
345
346
347bool VspOspTree::LocalTerminationCriteriaMet(const VspOspTraversalData &data) const
348{
349        return
350                (((int)data.mRays->size() <= mTermMinRays) ||
351                 (data.mPvs <= mTermMinPvs)   ||
352                 (data.mProbability <= mTermMinProbability) ||
353                 (data.GetAvgRayContribution() > mTermMaxRayContribution) ||
354                 (data.mDepth >= mTermMaxDepth));
355}
356
357
358bool VspOspTree::GlobalTerminationCriteriaMet(const VspOspTraversalData &data) const
359{
360        return
361                (mOutOfMemory
362                || (mBspStats.Leaves() >= mMaxViewCells)
363                || (mGlobalCostMisses >= mTermGlobalCostMissTolerance)
364                 );
365}
366
367
368// subdivide using a split plane queue
369BspNode *VspOspTree::Subdivide(VspOspSplitQueue &tQueue,
370                                                           VspOspSplitCandidate &splitCandidate)
371{
372        VspOspTraversalData &tData = splitCandidate.mParentData;
373
374        BspNode *newNode = tData.mNode;
375
376        if (!LocalTerminationCriteriaMet(tData) && !GlobalTerminationCriteriaMet(tData))
377        {       
378                VspOspTraversalData tFrontData;
379                VspOspTraversalData tBackData;
380
381                //-- continue subdivision
382               
383                // create new interior node and two leaf node
384                //TODO
385                const Plane3 splitPlane;// = splitCandidate.mSplitPlane;
386                               
387                newNode = SubdivideNode(splitPlane, tData, tFrontData, tBackData);
388       
389                const int maxCostMisses = splitCandidate.mMaxCostMisses;
390
391
392                // how often was max cost ratio missed in this branch?
393                tFrontData.mMaxCostMisses = maxCostMisses;
394                tBackData.mMaxCostMisses = maxCostMisses;
395                       
396               
397                if (1)
398                {
399                        float cFront = (float)tFrontData.mPvs * tFrontData.mProbability;
400                        float cBack = (float)tBackData.mPvs * tBackData.mProbability;
401                        float cData = (float)tData.mPvs * tData.mProbability;
402
403                       
404                        float costDecr =
405                                (cFront + cBack - cData) / mBox.GetVolume();
406
407                        mTotalCost += costDecr;
408                        mTotalPvsSize += tFrontData.mPvs + tBackData.mPvs - tData.mPvs;
409
410                        mSubdivisionStats
411                                        << "#ViewCells\n" << mBspStats.Leaves() << endl
412                                        << "#RenderCostDecrease\n" << -costDecr << endl
413                                        << "#SplitCandidateCost\n" << splitCandidate.GetCost() << endl
414                                        << "#TotalRenderCost\n" << mTotalCost << endl
415                                        << "#AvgRenderCost\n" << (float)mTotalPvsSize / (float)mBspStats.Leaves() << endl;
416                }
417
418       
419                //-- push the new split candidates on the stack
420                VspOspSplitCandidate frontCandidate;
421                VspOspSplitCandidate backCandidate;
422
423                EvalSplitCandidate(tFrontData, frontCandidate);
424                EvalSplitCandidate(tBackData, backCandidate);
425       
426                tQueue.push(frontCandidate);
427                tQueue.push(backCandidate);
428       
429                // delete old leaf node
430                DEL_PTR(tData.mNode);
431        }
432
433
434        //-- terminate traversal and create new view cell
435        if (newNode->IsLeaf())
436        {
437                BspLeaf *leaf = dynamic_cast<BspLeaf *>(newNode);
438                BspViewCell *viewCell = new BspViewCell();
439
440        leaf->SetViewCell(viewCell);
441               
442                //-- update pvs
443                int conSamp = 0;
444                float sampCon = 0.0f;
445                AddToPvs(leaf, *tData.mRays, sampCon, conSamp);
446
447                // update scalar pvs size value
448                mViewCellsManager->SetScalarPvsSize(viewCell, viewCell->GetPvs().GetSize());
449
450                mBspStats.contributingSamples += conSamp;
451                mBspStats.sampleContributions +=(int) sampCon;
452
453                //-- store additional info
454                if (mStoreRays)
455                {
456                        RayInfoContainer::const_iterator it, it_end = tData.mRays->end();
457                        for (it = tData.mRays->begin(); it != it_end; ++ it)
458                        {
459                                (*it).mRay->Ref();                     
460                                leaf->mVssRays.push_back((*it).mRay);
461                        }
462                }
463
464                // should I check here?
465                viewCell->mLeaf = leaf;
466
467                viewCell->SetVolume(tData.mProbability);
468        leaf->mProbability = tData.mProbability;
469
470                EvaluateLeafStats(tData);               
471        }
472
473        //-- cleanup
474        tData.Clear();
475
476        return newNode;
477}
478
479
480void VspOspTree::EvalSplitCandidate(VspOspTraversalData &tData,
481                                                                        VspOspSplitCandidate &splitData)
482{
483        VspOspTraversalData frontData;
484        VspOspTraversalData backData;
485
486        BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
487
488        // compute locally best split plane
489        // TODO
490    const bool success =0;/// SelectPlane(splitData.mSplitPlane, tData,
491//                                                                       frontData, backData);
492        //TODO
493        // compute global decrease in render cost
494        splitData.mRenderCost = 0;//EvalRenderCostDecrease(splitData.mSplitPlane, tData);
495        splitData.mParentData = tData;
496        splitData.mMaxCostMisses = success ? tData.mMaxCostMisses : tData.mMaxCostMisses + 1;
497}
498
499
500BspInterior *VspOspTree::SubdivideNode(const Plane3 &splitPlane,
501                                                                           VspOspTraversalData &tData,
502                                                                           VspOspTraversalData &frontData,
503                                                                           VspOspTraversalData &backData)
504{
505        BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
506       
507        //-- the front and back traversal data is filled with the new values
508        frontData.mDepth = tData.mDepth + 1;
509        frontData.mRays = new RayInfoContainer();
510       
511        backData.mDepth = tData.mDepth + 1;
512        backData.mRays = new RayInfoContainer();
513       
514
515        //-- subdivide rays
516        SplitRays(splitPlane,
517                          *tData.mRays,
518                          *frontData.mRays,
519                          *backData.mRays);
520
521
522        // compute pvs
523        frontData.mPvs = ComputePvsSize(*frontData.mRays);
524        backData.mPvs = ComputePvsSize(*backData.mRays);
525
526        // split front and back node geometry and compute area
527       
528        // if geometry was not already computed
529        // TODO
530
531#if TODO
532        tData.mBoundingBox.Split(splitPlane.mAxis, splitPlane.mPosition,
533                                                         frontData.mBoundingBox, backData.mBoundingBox);
534
535#endif
536
537        frontData.mProbability = frontData.mBoundingBox.GetVolume();
538        backData.mProbability = tData.mProbability - frontData.mProbability;
539
540       
541    ///////////////////////////////////////////
542        // subdivide further
543
544        // store maximal and minimal depth
545        if (tData.mDepth > mBspStats.maxDepth)
546        {
547                Debug << "max depth increases to " << tData.mDepth << " at " << mBspStats.Leaves() << " leaves" << endl;
548                mBspStats.maxDepth = tData.mDepth;
549        }
550
551        mBspStats.nodes += 2;
552
553   
554        BspInterior *interior = new BspInterior(splitPlane);
555
556#ifdef _DEBUG
557        Debug << interior << endl;
558#endif
559
560
561        //-- create front and back leaf
562
563        BspInterior *parent = leaf->GetParent();
564
565        // replace a link from node's parent
566        if (parent)
567        {
568                parent->ReplaceChildLink(leaf, interior);
569                interior->SetParent(parent);
570        }
571        else // new root
572        {
573                mRoot = interior;
574        }
575
576        // and setup child links
577        interior->SetupChildLinks(new BspLeaf(interior), new BspLeaf(interior));
578
579        frontData.mNode = interior->GetFront();
580        backData.mNode = interior->GetBack();
581
582        interior->mTimeStamp = mTimeStamp ++;
583       
584        return interior;
585}
586
587
588void VspOspTree::AddToPvs(BspLeaf *leaf,
589                                                  const RayInfoContainer &rays,
590                                                  float &sampleContributions,
591                                                  int &contributingSamples)
592{
593        sampleContributions = 0;
594        contributingSamples = 0;
595 
596        RayInfoContainer::const_iterator it, it_end = rays.end();
597 
598        ViewCellLeaf *vc = leaf->GetViewCell();
599 
600        // add contributions from samples to the PVS
601        for (it = rays.begin(); it != it_end; ++ it)
602        {
603                float sc = 0.0f;
604                VssRay *ray = (*it).mRay;
605
606                bool madeContrib = false;
607                float contribution;
608
609                if (ray->mTerminationObject)
610                {
611                        if (vc->AddPvsSample(ray->mTerminationObject, ray->mPdf, contribution))
612                                madeContrib = true;
613                        sc += contribution;
614                }
615         
616                if (ray->mOriginObject)
617                {
618                        if (vc->AddPvsSample(ray->mOriginObject, ray->mPdf, contribution))
619                                madeContrib = true;
620                        sc += contribution;
621                }
622         
623          sampleContributions += sc;
624
625          if (madeContrib)
626                  ++ contributingSamples;
627               
628          //leaf->mVssRays.push_back(ray);
629        }
630}
631
632
633void VspOspTree::SortSplitCandidates(const RayInfoContainer &rays,
634                                                                         const int axis,
635                                                                         float minBand,
636                                                                         float maxBand)
637{
638        mSplitCandidates->clear();
639
640        int requestedSize = 2 * (int)(rays.size());
641        // creates a sorted split candidates array
642        if (mSplitCandidates->capacity() > 500000 &&
643                requestedSize < (int)(mSplitCandidates->capacity() / 10) )
644        {
645        delete mSplitCandidates;
646                mSplitCandidates = new vector<SortableEntry>;
647        }
648
649        mSplitCandidates->reserve(requestedSize);
650
651        float pos;
652
653        // float values => don't compare with exact values
654        if (0)
655        {
656                minBand += Limits::Small;
657                maxBand -= Limits::Small;
658        }
659
660        // insert all queries
661        for (RayInfoContainer::const_iterator ri = rays.begin(); ri < rays.end(); ++ ri)
662        {
663                const bool positive = (*ri).mRay->HasPosDir(axis);
664                               
665                pos = (*ri).ExtrapOrigin(axis);
666                // clamp to min / max band
667                if (0) ClipValue(pos, minBand, maxBand);
668               
669                mSplitCandidates->push_back(SortableEntry(positive ? SortableEntry::ERayMin : SortableEntry::ERayMax,
670                                                                        pos, (*ri).mRay));
671
672                pos = (*ri).ExtrapTermination(axis);
673                // clamp to min / max band
674                if (0) ClipValue(pos, minBand, maxBand);
675
676                mSplitCandidates->push_back(SortableEntry(positive ? SortableEntry::ERayMax : SortableEntry::ERayMin,
677                                                                        pos, (*ri).mRay));
678        }
679
680        stable_sort(mSplitCandidates->begin(), mSplitCandidates->end());
681}
682
683
684float VspOspTree::BestCostRatioHeuristics(const RayInfoContainer &rays,
685                                                                                  const AxisAlignedBox3 &box,
686                                                                                  const int pvsSize,
687                                                                                  const int axis,
688                                          float &position)
689{
690        const float minBox = box.Min(axis);
691        const float maxBox = box.Max(axis);
692
693        const float sizeBox = maxBox - minBox;
694
695        const float minBand = minBox + mMinBand * sizeBox;
696        const float maxBand = minBox + mMaxBand * sizeBox;
697
698        SortSplitCandidates(rays, axis, minBand, maxBand);
699
700        // go through the lists, count the number of objects left and right
701        // and evaluate the following cost funcion:
702        // C = ct_div_ci  + (ql*rl + qr*rr)/queries
703
704        int pvsl = 0;
705        int pvsr = pvsSize;
706
707        int pvsBack = pvsl;
708        int pvsFront = pvsr;
709
710        float sum = (float)pvsSize * sizeBox;
711        float minSum = 1e20f;
712
713       
714        // if no border can be found, take mid split
715        position = minBox + 0.5f * sizeBox;
716       
717        // the relative cost ratio
718        float ratio = /*Limits::Infinity;*/99999999.0f;
719        bool splitPlaneFound = false;
720
721        Intersectable::NewMail();
722
723        RayInfoContainer::const_iterator ri, ri_end = rays.end();
724
725        // set all object as belonging to the front pvs
726        for(ri = rays.begin(); ri != ri_end; ++ ri)
727        {
728                Intersectable *oObject = (*ri).mRay->mOriginObject;
729                Intersectable *tObject = (*ri).mRay->mTerminationObject;
730
731                if (oObject)
732                {
733                        if (!oObject->Mailed())
734                        {
735                                oObject->Mail();
736                                oObject->mCounter = 1;
737                        }
738                        else
739                        {
740                                ++ oObject->mCounter;
741                        }
742                }
743                if (tObject)
744                {
745                        if (!tObject->Mailed())
746                        {
747                                tObject->Mail();
748                                tObject->mCounter = 1;
749                        }
750                        else
751                        {
752                                ++ tObject->mCounter;
753                        }
754                }
755        }
756
757        Intersectable::NewMail();
758
759        vector<SortableEntry>::const_iterator ci, ci_end = mSplitCandidates->end();
760
761        for (ci = mSplitCandidates->begin(); ci != ci_end; ++ ci)
762        {
763                VssRay *ray;
764                ray = (*ci).ray;
765               
766                Intersectable *oObject = ray->mOriginObject;
767                Intersectable *tObject = ray->mTerminationObject;
768               
769
770                switch ((*ci).type)
771                {
772                        case SortableEntry::ERayMin:
773                                {
774                                        if (oObject && !oObject->Mailed())
775                                        {
776                                                oObject->Mail();
777                                                ++ pvsl;
778                                        }
779                                        if (tObject && !tObject->Mailed())
780                                        {
781                                                tObject->Mail();
782                                                ++ pvsl;
783                                        }
784                                        break;
785                                }
786                        case SortableEntry::ERayMax:
787                                {
788                                        if (oObject)
789                                        {
790                                                if (-- oObject->mCounter == 0)
791                                                        -- pvsr;
792                                        }
793
794                                        if (tObject)
795                                        {
796                                                if (-- tObject->mCounter == 0)
797                                                        -- pvsr;
798                                        }
799
800                                        break;
801                                }
802                }
803
804               
805               
806                // Note: sufficient to compare size of bounding boxes of front and back side?
807                if (((*ci).value >= minBand) && ((*ci).value <= maxBand))
808                {
809                        sum = pvsl * ((*ci).value - minBox) + pvsr * (maxBox - (*ci).value);
810
811                        //Debug  << "pos=" << (*ci).value << "\t pvs=(" <<  pvsl << "," << pvsr << ")" << endl;
812                        //Debug << "cost= " << sum << endl;
813
814                        if (sum < minSum)
815                        {
816                                splitPlaneFound = true;
817
818                                minSum = sum;
819                                position = (*ci).value;
820                               
821                                pvsBack = pvsl;
822                                pvsFront = pvsr;
823                        }
824                }
825        }
826       
827       
828        // -- compute cost
829        const int lowerPvsLimit = mViewCellsManager->GetMinPvsSize();
830        const int upperPvsLimit = mViewCellsManager->GetMaxPvsSize();
831
832        const float pOverall = sizeBox;
833
834        const float pBack = position - minBox;
835        const float pFront = maxBox - position;
836       
837        const float penaltyOld = EvalPvsPenalty(pvsSize, lowerPvsLimit, upperPvsLimit);
838    const float penaltyFront = EvalPvsPenalty(pvsFront, lowerPvsLimit, upperPvsLimit);
839        const float penaltyBack = EvalPvsPenalty(pvsBack, lowerPvsLimit, upperPvsLimit);
840       
841        const float oldRenderCost = penaltyOld * pOverall;
842        const float newRenderCost = penaltyFront * pFront + penaltyBack * pBack;
843
844        if (splitPlaneFound)
845        {
846                ratio = newRenderCost / (oldRenderCost + Limits::Small);
847        }
848        //if (axis != 1)
849        //Debug << "axis=" << axis << " costRatio=" << ratio << " pos=" << position << " t=" << (position - minBox) / (maxBox - minBox)
850         //    <<"\t pb=(" << pvsBack << ")\t pf=(" << pvsFront << ")" << endl;
851
852        return ratio;
853}
854
855
856float VspOspTree::SelectPlane(const VspOspTraversalData &tData,
857                                                          AxisAlignedPlane &plane,
858                                                          float &pFront,
859                                                          float &pBack)
860{
861        float nPosition[3];
862        float nCostRatio[3];
863        float nProbFront[3];
864        float nProbBack[3];
865
866        // create bounding box of node geometry
867        AxisAlignedBox3 box = tData.mBoundingBox;
868               
869        int sAxis = 0;
870        int bestAxis = -1;
871
872#if 0
873        // maximum cost ratio for axis to be valid:
874        // if exceeded, spatial mid split is used instead
875        const maxCostRatioForHeur = 0.99f;
876#endif
877
878        // if we use some kind of specialised fixed axis
879    const bool useSpecialAxis =
880                mOnlyDrivingAxis || mUseRandomAxis || mCirculatingAxis;
881
882        if (mUseRandomAxis)
883                sAxis = Random(3);
884        else if (mCirculatingAxis)
885                sAxis = (tData.mAxis + 1) % 3;
886        else if (mOnlyDrivingAxis)
887                sAxis = box.Size().DrivingAxis();
888
889
890        for (int axis = 0; axis < 3 ; ++ axis)
891        {
892                if (!useSpecialAxis || (axis == sAxis))
893                {
894                        //-- place split plane using heuristics
895
896                        if (mUseCostHeuristics)
897                        {
898                                nCostRatio[axis] =
899                                        BestCostRatioHeuristics(*tData.mRays,
900                                                                                    box,
901                                                                                        tData.mPvs,
902                                                                                        axis,
903                                                                                        nPosition[axis]);                       
904                        }
905                        else //-- split plane position is spatial median
906                        {
907                                nPosition[axis] = (box.Min()[axis] + box.Max()[axis]) * 0.5f;
908
909                                nCostRatio[axis] = EvalSplitCost(tData,
910                                                                                                 box,
911                                                                                                 axis,
912                                                                                                 nPosition[axis],
913                                                                                                 nProbFront[axis],
914                                                                                                 nProbBack[axis]);
915                        }
916                                               
917                        if (bestAxis == -1)
918                        {
919                                bestAxis = axis;
920                        }
921                        else if (nCostRatio[axis] < nCostRatio[bestAxis])
922                        {
923                                bestAxis = axis;
924                        }
925                }
926        }
927
928        //-- assign values
929        plane.mAxis = bestAxis;
930        pFront = nProbFront[bestAxis];
931        pBack = nProbBack[bestAxis];
932
933        //-- split plane position
934    plane.mPosition = nPosition[bestAxis];
935
936        return nCostRatio[bestAxis];
937}
938
939
940inline void VspOspTree::GenerateUniqueIdsForPvs()
941{
942        Intersectable::NewMail(); sBackId = Intersectable::sMailId;
943        Intersectable::NewMail(); sFrontId = Intersectable::sMailId;
944        Intersectable::NewMail(); sFrontAndBackId = Intersectable::sMailId;
945}
946
947
948float VspOspTree::EvalRenderCostDecrease(const Plane3 &candidatePlane,
949                                                                                 const VspOspTraversalData &data) const
950{
951        float pvsFront = 0;
952        float pvsBack = 0;
953        float totalPvs = 0;
954
955        // probability that view point lies in back / front node
956        float pOverall = data.mProbability;
957        float pFront = 0;
958        float pBack = 0;
959
960
961        // create unique ids for pvs heuristics
962        GenerateUniqueIdsForPvs();
963       
964        for (int i = 0; i < data.mRays->size(); ++ i)
965        {
966                RayInfo rayInf = (*data.mRays)[i];
967
968                float t;
969                VssRay *ray = rayInf.mRay;
970                const int cf = rayInf.ComputeRayIntersection(candidatePlane, t);
971
972                // find front and back pvs for origing and termination object
973                AddObjToPvs(ray->mTerminationObject, cf, pvsFront, pvsBack, totalPvs);
974                AddObjToPvs(ray->mOriginObject, cf, pvsFront, pvsBack, totalPvs);
975        }
976
977
978        BspNodeGeometry geomFront;
979        BspNodeGeometry geomBack;
980       
981        pFront = geomFront.GetVolume();
982        pBack = pOverall - pFront;
983
984               
985
986        // -- pvs rendering heuristics
987        const int lowerPvsLimit = mViewCellsManager->GetMinPvsSize();
988        const int upperPvsLimit = mViewCellsManager->GetMaxPvsSize();
989
990        // only render cost heuristics or combined with standard deviation
991        const float penaltyOld = EvalPvsPenalty(totalPvs, lowerPvsLimit, upperPvsLimit);
992    const float penaltyFront = EvalPvsPenalty(pvsFront, lowerPvsLimit, upperPvsLimit);
993        const float penaltyBack = EvalPvsPenalty(pvsBack, lowerPvsLimit, upperPvsLimit);
994                       
995        const float oldRenderCost = pOverall * penaltyOld;
996        const float newRenderCost = penaltyFront * pFront + penaltyBack * pBack;
997
998        //Debug << "decrease: " << oldRenderCost - newRenderCost << endl;
999        const float renderCostDecrease = (oldRenderCost - newRenderCost) / mBox.GetVolume();
1000       
1001
1002#if 1
1003        // take render cost of node into account to avoid being stuck in a local minimum
1004        const float normalizedOldRenderCost = oldRenderCost / mBox.GetVolume();
1005        return 0.99f * renderCostDecrease + 0.01f * normalizedOldRenderCost;
1006#else
1007        return renderCostDecrease;
1008#endif
1009}
1010
1011
1012
1013float VspOspTree::EvalSplitCost(const VspOspTraversalData &data,
1014                                                                const AxisAlignedBox3 &box,
1015                                                                const int axis,
1016                                                                const float &position,                                                                           
1017                                                                float &pFront,
1018                                                                float &pBack) const
1019{
1020        float pvsTotal = 0;
1021        float pvsFront = 0;
1022        float pvsBack = 0;
1023       
1024        // create unique ids for pvs heuristics
1025        GenerateUniqueIdsForPvs();
1026
1027        const int pvsSize = data.mPvs;
1028
1029        RayInfoContainer::const_iterator rit, rit_end = data.mRays->end();
1030
1031        // this is the main ray classification loop!
1032        for(rit = data.mRays->begin(); rit != rit_end; ++ rit)
1033        {
1034                // determine the side of this ray with respect to the plane
1035                float t;
1036                const int side = (*rit).ComputeRayIntersection(axis, position, t);
1037       
1038                AddObjToPvs((*rit).mRay->mTerminationObject, side, pvsFront, pvsBack, pvsTotal);
1039                AddObjToPvs((*rit).mRay->mOriginObject, side, pvsFront, pvsBack, pvsTotal);
1040        }
1041
1042        //-- pvs heuristics
1043        float pOverall;
1044
1045        //-- compute heurstics
1046        //-- we take simplified computation for mid split
1047               
1048        pOverall = data.mProbability;
1049        pBack = pFront = pOverall * 0.5f;
1050       
1051       
1052#ifdef _DEBUG
1053        Debug << axis << " " << pvsSize << " " << pvsBack << " " << pvsFront << endl;
1054        Debug << pFront << " " << pBack << " " << pOverall << endl;
1055#endif
1056
1057       
1058        const float newCost = pvsBack * pBack + pvsFront * pFront;
1059        const float oldCost = (float)pvsSize * pOverall + Limits::Small;
1060
1061        return  (mCtDivCi + newCost) / oldCost;
1062}
1063
1064
1065void VspOspTree::AddObjToPvs(Intersectable *obj,
1066                                                         const int cf,
1067                                                         float &frontPvs,
1068                                                         float &backPvs,
1069                                                         float &totalPvs) const
1070{
1071        if (!obj)
1072                return;
1073
1074        const float renderCost = mViewCellsManager->EvalRenderCost(obj);
1075
1076        // new object
1077        if ((obj->mMailbox != sFrontId) &&
1078                (obj->mMailbox != sBackId) &&
1079                (obj->mMailbox != sFrontAndBackId))
1080        {
1081                totalPvs += renderCost;
1082        }
1083
1084        // TODO: does this really belong to no pvs?
1085        //if (cf == Ray::COINCIDENT) return;
1086
1087        // object belongs to both PVS
1088        if (cf >= 0)
1089        {
1090                if ((obj->mMailbox != sFrontId) &&
1091                        (obj->mMailbox != sFrontAndBackId))
1092                {
1093                        frontPvs += renderCost;
1094               
1095                        if (obj->mMailbox == sBackId)
1096                                obj->mMailbox = sFrontAndBackId;
1097                        else
1098                                obj->mMailbox = sFrontId;
1099                }
1100        }
1101
1102        if (cf <= 0)
1103        {
1104                if ((obj->mMailbox != sBackId) &&
1105                        (obj->mMailbox != sFrontAndBackId))
1106                {
1107                        backPvs += renderCost;
1108               
1109                        if (obj->mMailbox == sFrontId)
1110                                obj->mMailbox = sFrontAndBackId;
1111                        else
1112                                obj->mMailbox = sBackId;
1113                }
1114        }
1115}
1116
1117
1118void VspOspTree::CollectLeaves(vector<BspLeaf *> &leaves,
1119                                                           const bool onlyUnmailed,
1120                                                           const int maxPvsSize) const
1121{
1122        stack<BspNode *> nodeStack;
1123        nodeStack.push(mRoot);
1124
1125        while (!nodeStack.empty())
1126        {
1127                BspNode *node = nodeStack.top();
1128                nodeStack.pop();
1129               
1130                if (node->IsLeaf())
1131                {
1132                        // test if this leaf is in valid view space
1133                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
1134                        if (leaf->TreeValid() &&
1135                                (!onlyUnmailed || !leaf->Mailed()) &&
1136                                ((maxPvsSize < 0) || (leaf->GetViewCell()->GetPvs().GetSize() <= maxPvsSize)))
1137                        {
1138                                leaves.push_back(leaf);
1139                        }
1140                }
1141                else
1142                {
1143                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1144
1145                        nodeStack.push(interior->GetBack());
1146                        nodeStack.push(interior->GetFront());
1147                }
1148        }
1149}
1150
1151
1152AxisAlignedBox3 VspOspTree::GetBoundingBox() const
1153{
1154        return mBox;
1155}
1156
1157
1158BspNode *VspOspTree::GetRoot() const
1159{
1160        return mRoot;
1161}
1162
1163
1164void VspOspTree::EvaluateLeafStats(const VspOspTraversalData &data)
1165{
1166        // the node became a leaf -> evaluate stats for leafs
1167        BspLeaf *leaf = dynamic_cast<BspLeaf *>(data.mNode);
1168
1169
1170        if (data.mPvs > mBspStats.maxPvs)
1171        {
1172                mBspStats.maxPvs = data.mPvs;
1173        }
1174
1175        mBspStats.pvs += data.mPvs;
1176
1177        if (data.mDepth < mBspStats.minDepth)
1178        {
1179                mBspStats.minDepth = data.mDepth;
1180        }
1181       
1182        if (data.mDepth >= mTermMaxDepth)
1183        {
1184        ++ mBspStats.maxDepthNodes;
1185                //Debug << "new max depth: " << mBspStats.maxDepthNodes << endl;
1186        }
1187
1188        // accumulate rays to compute rays /  leaf
1189        mBspStats.accumRays += (int)data.mRays->size();
1190
1191        if (data.mPvs < mTermMinPvs)
1192                ++ mBspStats.minPvsNodes;
1193
1194        if ((int)data.mRays->size() < mTermMinRays)
1195                ++ mBspStats.minRaysNodes;
1196
1197        if (data.GetAvgRayContribution() > mTermMaxRayContribution)
1198                ++ mBspStats.maxRayContribNodes;
1199
1200        if (data.mProbability <= mTermMinProbability)
1201                ++ mBspStats.minProbabilityNodes;
1202       
1203        // accumulate depth to compute average depth
1204        mBspStats.accumDepth += data.mDepth;
1205
1206        ++ mCreatedViewCells;
1207
1208#ifdef _DEBUG
1209        Debug << "BSP stats: "
1210                  << "Depth: " << data.mDepth << " (max: " << mTermMaxDepth << "), "
1211                  << "PVS: " << data.mPvs << " (min: " << mTermMinPvs << "), "
1212          //              << "Area: " << data.mProbability << " (min: " << mTermMinProbability << "), "
1213                  << "#rays: " << (int)data.mRays->size() << " (max: " << mTermMinRays << "), "
1214                  << "#pvs: " << leaf->GetViewCell()->GetPvs().GetSize() << "=, "
1215                  << "#avg ray contrib (pvs): " << (float)data.mPvs / (float)data.mRays->size() << endl;
1216#endif
1217}
1218
1219
1220int VspOspTree::CastRay(Ray &ray)
1221{
1222        int hits = 0;
1223
1224        stack<BspRayTraversalData> tQueue;
1225
1226        float maxt, mint;
1227
1228        if (!mBox.GetRaySegment(ray, mint, maxt))
1229                return 0;
1230
1231        Intersectable::NewMail();
1232        ViewCell::NewMail();
1233        Vector3 entp = ray.Extrap(mint);
1234        Vector3 extp = ray.Extrap(maxt);
1235
1236        BspNode *node = mRoot;
1237        BspNode *farChild = NULL;
1238
1239        while (1)
1240        {
1241                if (!node->IsLeaf())
1242                {
1243                        BspInterior *in = dynamic_cast<BspInterior *>(node);
1244
1245                        Plane3 splitPlane = in->GetPlane();
1246                        const int entSide = splitPlane.Side(entp);
1247                        const int extSide = splitPlane.Side(extp);
1248
1249                        if (entSide < 0)
1250                        {
1251                                node = in->GetBack();
1252
1253                                if(extSide <= 0) // plane does not split ray => no far child
1254                                        continue;
1255
1256                                farChild = in->GetFront(); // plane splits ray
1257
1258                        } else if (entSide > 0)
1259                        {
1260                                node = in->GetFront();
1261
1262                                if (extSide >= 0) // plane does not split ray => no far child
1263                                        continue;
1264
1265                                farChild = in->GetBack(); // plane splits ray
1266                        }
1267                        else // ray and plane are coincident
1268                        {
1269                                // WHAT TO DO IN THIS CASE ?
1270                                //break;
1271                                node = in->GetFront();
1272                                continue;
1273                        }
1274
1275                        // push data for far child
1276                        tQueue.push(BspRayTraversalData(farChild, extp, maxt));
1277
1278                        // find intersection of ray segment with plane
1279                        float t;
1280                        extp = splitPlane.FindIntersection(ray.GetLoc(), extp, &t);
1281                        maxt *= t;
1282
1283                } else // reached leaf => intersection with view cell
1284                {
1285                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
1286
1287                        if (!leaf->GetViewCell()->Mailed())
1288                        {
1289                                //ray.bspIntersections.push_back(Ray::VspOspIntersection(maxt, leaf));
1290                                leaf->GetViewCell()->Mail();
1291                                ++ hits;
1292                        }
1293
1294                        //-- fetch the next far child from the stack
1295                        if (tQueue.empty())
1296                                break;
1297
1298                        entp = extp;
1299                        mint = maxt; // NOTE: need this?
1300
1301                        if (ray.GetType() == Ray::LINE_SEGMENT && mint > 1.0f)
1302                                break;
1303
1304                        BspRayTraversalData &s = tQueue.top();
1305
1306                        node = s.mNode;
1307                        extp = s.mExitPoint;
1308                        maxt = s.mMaxT;
1309
1310                        tQueue.pop();
1311                }
1312        }
1313
1314        return hits;
1315}
1316
1317
1318void VspOspTree::CollectViewCells(ViewCellContainer &viewCells, bool onlyValid) const
1319{
1320        ViewCell::NewMail();
1321       
1322        CollectViewCells(mRoot, onlyValid, viewCells, true);
1323}
1324
1325
1326void VspOspTree::CollapseViewCells()
1327{
1328// TODO
1329#if HAS_TO_BE_REDONE
1330        stack<BspNode *> nodeStack;
1331
1332        if (!mRoot)
1333                return;
1334
1335        nodeStack.push(mRoot);
1336       
1337        while (!nodeStack.empty())
1338        {
1339                BspNode *node = nodeStack.top();
1340                nodeStack.pop();
1341               
1342                if (node->IsLeaf())
1343        {
1344                        BspViewCell *viewCell = dynamic_cast<BspLeaf *>(node)->GetViewCell();
1345
1346                        if (!viewCell->GetValid())
1347                        {
1348                                BspViewCell *viewCell = dynamic_cast<BspLeaf *>(node)->GetViewCell();
1349       
1350                                ViewCellContainer leaves;
1351                                mViewCellsTree->CollectLeaves(viewCell, leaves);
1352
1353                                ViewCellContainer::const_iterator it, it_end = leaves.end();
1354
1355                                for (it = leaves.begin(); it != it_end; ++ it)
1356                                {
1357                                        BspLeaf *l = dynamic_cast<BspViewCell *>(*it)->mLeaf;
1358                                        l->SetViewCell(GetOrCreateOutOfBoundsCell());
1359                                        ++ mBspStats.invalidLeaves;
1360                                }
1361
1362                                // add to unbounded view cell
1363                                GetOrCreateOutOfBoundsCell()->GetPvs().AddPvs(viewCell->GetPvs());
1364                                DEL_PTR(viewCell);
1365                        }
1366                }
1367                else
1368                {
1369                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1370               
1371                        nodeStack.push(interior->GetFront());
1372                        nodeStack.push(interior->GetBack());
1373                }
1374        }
1375
1376        Debug << "invalid leaves: " << mBspStats.invalidLeaves << endl;
1377#endif
1378}
1379
1380
1381void VspOspTree::CollectRays(VssRayContainer &rays)
1382{
1383        vector<BspLeaf *> leaves;
1384
1385        vector<BspLeaf *>::const_iterator lit, lit_end = leaves.end();
1386
1387        for (lit = leaves.begin(); lit != lit_end; ++ lit)
1388        {
1389                BspLeaf *leaf = *lit;
1390                VssRayContainer::const_iterator rit, rit_end = leaf->mVssRays.end();
1391
1392                for (rit = leaf->mVssRays.begin(); rit != rit_end; ++ rit)
1393                        rays.push_back(*rit);
1394        }
1395}
1396
1397
1398void VspOspTree::ValidateTree()
1399{
1400        stack<BspNode *> nodeStack;
1401
1402        if (!mRoot)
1403                return;
1404
1405        nodeStack.push(mRoot);
1406       
1407        mBspStats.invalidLeaves = 0;
1408        while (!nodeStack.empty())
1409        {
1410                BspNode *node = nodeStack.top();
1411                nodeStack.pop();
1412               
1413                if (node->IsLeaf())
1414                {
1415                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
1416
1417                        if (!leaf->GetViewCell()->GetValid())
1418                                ++ mBspStats.invalidLeaves;
1419
1420                        // validity flags don't match => repair
1421                        if (leaf->GetViewCell()->GetValid() != leaf->TreeValid())
1422                        {
1423                                leaf->SetTreeValid(leaf->GetViewCell()->GetValid());
1424                                PropagateUpValidity(leaf);
1425                        }
1426                }
1427                else
1428                {
1429                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1430               
1431                        nodeStack.push(interior->GetFront());
1432                        nodeStack.push(interior->GetBack());
1433                }
1434        }
1435
1436        Debug << "invalid leaves: " << mBspStats.invalidLeaves << endl;
1437}
1438
1439
1440
1441void VspOspTree::CollectViewCells(BspNode *root,
1442                                                                  bool onlyValid,
1443                                                                  ViewCellContainer &viewCells,
1444                                                                  bool onlyUnmailed) const
1445{
1446        stack<BspNode *> nodeStack;
1447
1448        if (!root)
1449                return;
1450
1451        nodeStack.push(root);
1452       
1453        while (!nodeStack.empty())
1454        {
1455                BspNode *node = nodeStack.top();
1456                nodeStack.pop();
1457               
1458                if (node->IsLeaf())
1459                {
1460                        if (!onlyValid || node->TreeValid())
1461                        {
1462                                ViewCellLeaf *leafVc = dynamic_cast<BspLeaf *>(node)->GetViewCell();
1463
1464                                ViewCell *viewCell = mViewCellsTree->GetActiveViewCell(leafVc);
1465                                               
1466                                if (!onlyUnmailed || !viewCell->Mailed())
1467                                {
1468                                        viewCell->Mail();
1469                                        viewCells.push_back(viewCell);
1470                                }
1471                        }
1472                }
1473                else
1474                {
1475                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1476               
1477                        nodeStack.push(interior->GetFront());
1478                        nodeStack.push(interior->GetBack());
1479                }
1480        }
1481
1482}
1483
1484
1485int VspOspTree::SplitRays(const Plane3 &plane,
1486                                                  RayInfoContainer &rays,
1487                                                  RayInfoContainer &frontRays,
1488                                                  RayInfoContainer &backRays) const
1489{
1490        int splits = 0;
1491
1492        RayInfoContainer::const_iterator it, it_end = rays.end();
1493
1494        for (it = rays.begin(); it != it_end; ++ it)
1495        {
1496                RayInfo bRay = *it;
1497               
1498                VssRay *ray = bRay.mRay;
1499                float t;
1500
1501                // get classification and receive new t
1502                const int cf = bRay.ComputeRayIntersection(plane, t);
1503
1504                switch (cf)
1505                {
1506                case -1:
1507                        backRays.push_back(bRay);
1508                        break;
1509                case 1:
1510                        frontRays.push_back(bRay);
1511                        break;
1512                case 0:
1513                        {
1514                                //-- split ray
1515                                //-- test if start point behind or in front of plane
1516                                const int side = plane.Side(bRay.ExtrapOrigin());
1517
1518                                if (side <= 0)
1519                                {
1520                                        backRays.push_back(RayInfo(ray, bRay.GetMinT(), t));
1521                                        frontRays.push_back(RayInfo(ray, t, bRay.GetMaxT()));
1522                                }
1523                                else
1524                                {
1525                                        frontRays.push_back(RayInfo(ray, bRay.GetMinT(), t));
1526                                        backRays.push_back(RayInfo(ray, t, bRay.GetMaxT()));
1527                                }
1528                        }
1529                        break;
1530                default:
1531                        Debug << "Should not come here" << endl;
1532                        break;
1533                }
1534        }
1535
1536        return splits;
1537}
1538
1539
1540int VspOspTree::FindNeighbors(BspNode *n, vector<BspLeaf *> &neighbors,
1541                                                          const bool onlyUnmailed) const
1542{
1543        // TODO
1544        return 0;
1545}
1546
1547
1548BspLeaf *VspOspTree::GetRandomLeaf(const Plane3 &halfspace)
1549{
1550#if TODO
1551    stack<BspNode *> nodeStack;
1552        nodeStack.push(mRoot);
1553
1554        int mask = rand();
1555
1556        while (!nodeStack.empty())
1557        {
1558                BspNode *node = nodeStack.top();
1559                nodeStack.pop();
1560
1561                if (node->IsLeaf())
1562                {
1563                        return dynamic_cast<BspLeaf *>(node);
1564                }
1565                else
1566                {
1567                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1568                        BspNode *next;
1569                        BspNodeGeometry geom;
1570
1571                        // todo: not very efficient: constructs full cell everytime
1572                        ConstructGeometry(interior, geom);
1573
1574                        const int cf =
1575                                Polygon3::ClassifyPlane(geom.GetPolys(), halfspace, mEpsilon);
1576
1577                        if (cf == Polygon3::BACK_SIDE)
1578                                next = interior->GetFront();
1579                        else
1580                                if (cf == Polygon3::FRONT_SIDE)
1581                                        next = interior->GetFront();
1582                        else
1583                        {
1584                                // random decision
1585                                if (mask & 1)
1586                                        next = interior->GetBack();
1587                                else
1588                                        next = interior->GetFront();
1589                                mask = mask >> 1;
1590                        }
1591
1592                        nodeStack.push(next);
1593                }
1594        }
1595#endif
1596        return NULL;
1597}
1598
1599
1600BspLeaf *VspOspTree::GetRandomLeaf(const bool onlyUnmailed)
1601{
1602        stack<BspNode *> nodeStack;
1603
1604        nodeStack.push(mRoot);
1605
1606        int mask = rand();
1607
1608        while (!nodeStack.empty())
1609        {
1610                BspNode *node = nodeStack.top();
1611                nodeStack.pop();
1612
1613                if (node->IsLeaf())
1614                {
1615                        if ( (!onlyUnmailed || !node->Mailed()) )
1616                                return dynamic_cast<BspLeaf *>(node);
1617                }
1618                else
1619                {
1620                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1621
1622                        // random decision
1623                        if (mask & 1)
1624                                nodeStack.push(interior->GetBack());
1625                        else
1626                                nodeStack.push(interior->GetFront());
1627
1628                        mask = mask >> 1;
1629                }
1630        }
1631
1632        return NULL;
1633}
1634
1635
1636int VspOspTree::ComputePvsSize(const RayInfoContainer &rays) const
1637{
1638        int pvsSize = 0;
1639
1640        RayInfoContainer::const_iterator rit, rit_end = rays.end();
1641
1642        Intersectable::NewMail();
1643
1644        for (rit = rays.begin(); rit != rays.end(); ++ rit)
1645        {
1646                VssRay *ray = (*rit).mRay;
1647
1648                if (ray->mOriginObject)
1649                {
1650                        if (!ray->mOriginObject->Mailed())
1651                        {
1652                                ray->mOriginObject->Mail();
1653                                ++ pvsSize;
1654                        }
1655                }
1656                if (ray->mTerminationObject)
1657                {
1658                        if (!ray->mTerminationObject->Mailed())
1659                        {
1660                                ray->mTerminationObject->Mail();
1661                                ++ pvsSize;
1662                        }
1663                }
1664        }
1665
1666        return pvsSize;
1667}
1668
1669
1670float VspOspTree::GetEpsilon() const
1671{
1672        return mEpsilon;
1673}
1674
1675
1676
1677int VspOspTree::CastLineSegment(const Vector3 &origin,
1678                                                                const Vector3 &termination,
1679                                                                ViewCellContainer &viewcells)
1680{
1681        int hits = 0;
1682        stack<BspRayTraversalData> tStack;
1683
1684        float mint = 0.0f, maxt = 1.0f;
1685
1686        Intersectable::NewMail();
1687        ViewCell::NewMail();
1688
1689        Vector3 entp = origin;
1690        Vector3 extp = termination;
1691
1692        BspNode *node = mRoot;
1693        BspNode *farChild = NULL;
1694
1695        float t;
1696        const float thresh = 1e-6f; // matt: change this to adjustable value
1697       
1698        while (1)
1699        {
1700                if (!node->IsLeaf())
1701                {
1702                        BspInterior *in = dynamic_cast<BspInterior *>(node);
1703
1704                        Plane3 splitPlane = in->GetPlane();
1705                       
1706                        const int entSide = splitPlane.Side(entp, thresh);
1707                        const int extSide = splitPlane.Side(extp, thresh);
1708
1709                        if (entSide < 0)
1710                        {
1711                                node = in->GetBack();
1712                               
1713                                // plane does not split ray => no far child
1714                                if (extSide <= 0)
1715                                        continue;
1716 
1717                                farChild = in->GetFront(); // plane splits ray
1718                        }
1719                        else if (entSide > 0)
1720                        {
1721                                node = in->GetFront();
1722
1723                                if (extSide >= 0) // plane does not split ray => no far child
1724                                        continue;
1725
1726                                farChild = in->GetBack(); // plane splits ray
1727                        }
1728                        else // one of the ray end points is on the plane
1729                        {       // NOTE: what to do if ray is coincident with plane?
1730                                if (extSide < 0)
1731                                        node = in->GetBack();
1732                                else //if (extSide > 0)
1733                                        node = in->GetFront();
1734                                //else break; // coincident => count no intersections
1735
1736                                continue; // no far child
1737                        }
1738
1739                        // push data for far child
1740                        tStack.push(BspRayTraversalData(farChild, extp));
1741
1742                        // find intersection of ray segment with plane
1743                        extp = splitPlane.FindIntersection(origin, extp, &t);
1744                }
1745                else
1746                {
1747                        // reached leaf => intersection with view cell
1748                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
1749                        ViewCell *viewCell;
1750                       
1751                        if (0)
1752                                viewCell = mViewCellsTree->GetActiveViewCell(leaf->GetViewCell());
1753                        else
1754                                viewCell = leaf->GetViewCell();
1755
1756                        if (!viewCell->Mailed())
1757                        {
1758                                viewcells.push_back(viewCell);
1759                                viewCell->Mail();
1760                                ++ hits;
1761                        }
1762
1763                        //-- fetch the next far child from the stack
1764                        if (tStack.empty())
1765                                break;
1766
1767                        entp = extp;
1768                       
1769                        const BspRayTraversalData &s = tStack.top();
1770
1771                        node = s.mNode;
1772                        extp = s.mExitPoint;
1773
1774                        tStack.pop();
1775                }
1776        }
1777
1778        return hits;
1779}
1780
1781
1782
1783BspNode *VspOspTree::CollapseTree(BspNode *node, int &collapsed)
1784{
1785// TODO
1786#if HAS_TO_BE_REDONE
1787        if (node->IsLeaf())
1788                return node;
1789
1790        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1791
1792        BspNode *front = CollapseTree(interior->GetFront(), collapsed);
1793        BspNode *back = CollapseTree(interior->GetBack(), collapsed);
1794
1795        if (front->IsLeaf() && back->IsLeaf())
1796        {
1797                BspLeaf *frontLeaf = dynamic_cast<BspLeaf *>(front);
1798                BspLeaf *backLeaf = dynamic_cast<BspLeaf *>(back);
1799
1800                //-- collapse tree
1801                if (frontLeaf->GetViewCell() == backLeaf->GetViewCell())
1802                {
1803                        BspViewCell *vc = frontLeaf->GetViewCell();
1804
1805                        BspLeaf *leaf = new BspLeaf(interior->GetParent(), vc);
1806                        leaf->SetTreeValid(frontLeaf->TreeValid());
1807
1808                        // replace a link from node's parent
1809                        if (leaf->GetParent())
1810                                leaf->GetParent()->ReplaceChildLink(node, leaf);
1811                        else
1812                                mRoot = leaf;
1813
1814                        ++ collapsed;
1815                        delete interior;
1816
1817                        return leaf;
1818                }
1819        }
1820#endif
1821        return node;
1822}
1823
1824
1825int VspOspTree::CollapseTree()
1826{
1827        int collapsed = 0;
1828        //TODO
1829#if HAS_TO_BE_REDONE
1830        (void)CollapseTree(mRoot, collapsed);
1831
1832        // revalidate leaves
1833        RepairViewCellsLeafLists();
1834#endif
1835        return collapsed;
1836}
1837
1838
1839void VspOspTree::RepairViewCellsLeafLists()
1840{
1841// TODO
1842#if HAS_TO_BE_REDONE
1843        // list not valid anymore => clear
1844        stack<BspNode *> nodeStack;
1845        nodeStack.push(mRoot);
1846
1847        ViewCell::NewMail();
1848
1849        while (!nodeStack.empty())
1850        {
1851                BspNode *node = nodeStack.top();
1852                nodeStack.pop();
1853
1854                if (node->IsLeaf())
1855                {
1856                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
1857
1858                        BspViewCell *viewCell = leaf->GetViewCell();
1859
1860                        if (!viewCell->Mailed())
1861                        {
1862                                viewCell->mLeaves.clear();
1863                                viewCell->Mail();
1864                        }
1865       
1866                        viewCell->mLeaves.push_back(leaf);
1867
1868                }
1869                else
1870                {
1871                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1872
1873                        nodeStack.push(interior->GetFront());
1874                        nodeStack.push(interior->GetBack());
1875                }
1876        }
1877// TODO
1878#endif
1879}
1880
1881
1882
1883ViewCell *VspOspTree::GetViewCell(const Vector3 &point, const bool active)
1884{
1885        if (mRoot == NULL)
1886                return NULL;
1887
1888        stack<BspNode *> nodeStack;
1889        nodeStack.push(mRoot);
1890 
1891        ViewCellLeaf *viewcell = NULL;
1892 
1893        while (!nodeStack.empty()) 
1894        {
1895                BspNode *node = nodeStack.top();
1896                nodeStack.pop();
1897       
1898                if (node->IsLeaf())
1899                {
1900                        viewcell = dynamic_cast<BspLeaf *>(node)->GetViewCell();
1901                        break;
1902                }
1903                else   
1904                {       
1905                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1906       
1907                        // random decision
1908                        if (interior->GetPlane().Side(point) < 0)
1909                                nodeStack.push(interior->GetBack());
1910                        else
1911                                nodeStack.push(interior->GetFront());
1912                }
1913        }
1914 
1915        if (active)
1916                return mViewCellsTree->GetActiveViewCell(viewcell);
1917        else
1918                return viewcell;
1919}
1920
1921
1922bool VspOspTree::ViewPointValid(const Vector3 &viewPoint) const
1923{
1924        BspNode *node = mRoot;
1925
1926        while (1)
1927        {
1928                // early exit
1929                if (node->TreeValid())
1930                        return true;
1931
1932                if (node->IsLeaf())
1933                        return false;
1934                       
1935                BspInterior *in = dynamic_cast<BspInterior *>(node);
1936                                       
1937                if (in->GetPlane().Side(viewPoint) <= 0)
1938                {
1939                        node = in->GetBack();
1940                }
1941                else
1942                {
1943                        node = in->GetFront();
1944                }
1945        }
1946
1947        // should never come here
1948        return false;
1949}
1950
1951
1952void VspOspTree::PropagateUpValidity(BspNode *node)
1953{
1954        const bool isValid = node->TreeValid();
1955
1956        // propagative up invalid flag until only invalid nodes exist over this node
1957        if (!isValid)
1958        {
1959                while (!node->IsRoot() && node->GetParent()->TreeValid())
1960                {
1961                        node = node->GetParent();
1962                        node->SetTreeValid(false);
1963                }
1964        }
1965        else
1966        {
1967                // propagative up valid flag until one of the subtrees is invalid
1968                while (!node->IsRoot() && !node->TreeValid())
1969                {
1970            node = node->GetParent();
1971                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
1972                       
1973                        // the parent is valid iff both leaves are valid
1974                        node->SetTreeValid(interior->GetBack()->TreeValid() &&
1975                                                           interior->GetFront()->TreeValid());
1976                }
1977        }
1978}
1979
1980#if ZIPPED_VIEWCELLS
1981bool VspOspTree::Export(ogzstream &stream)
1982#else
1983bool VspOspTree::Export(ofstream &stream)
1984#endif
1985{
1986        ExportNode(mRoot, stream);
1987
1988        return true;
1989}
1990
1991
1992#if ZIPPED_VIEWCELLS
1993void VspOspTree::ExportNode(BspNode *node, ogzstream &stream)
1994#else
1995void VspOspTree::ExportNode(BspNode *node, ofstream &stream)
1996#endif
1997{
1998        if (node->IsLeaf())
1999        {
2000                BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
2001                ViewCell *viewCell = mViewCellsTree->GetActiveViewCell(leaf->GetViewCell());
2002
2003                int id = -1;
2004                if (viewCell != mOutOfBoundsCell)
2005                        id = viewCell->GetId();
2006
2007                stream << "<Leaf viewCellId=\"" << id << "\" />" << endl;
2008        }
2009        else
2010        {
2011                BspInterior *interior = dynamic_cast<BspInterior *>(node);
2012       
2013                Plane3 plane = interior->GetPlane();
2014                stream << "<Interior plane=\"" << plane.mNormal.x << " "
2015                           << plane.mNormal.y << " " << plane.mNormal.z << " "
2016                           << plane.mD << "\">" << endl;
2017
2018                ExportNode(interior->GetBack(), stream);
2019                ExportNode(interior->GetFront(), stream);
2020
2021                stream << "</Interior>" << endl;
2022        }
2023}
2024
2025}
Note: See TracBrowser for help on using the repository browser.