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

Revision 1008, 50.4 KB checked in by mattausch, 18 years ago (diff)

worked on vsp osp tree. warning: does not compile

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