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

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