source: GTP/trunk/Lib/Vis/Preprocessing/src/OspTree.cpp @ 2116

Revision 2116, 60.6 KB checked in by mattausch, 17 years ago (diff)

implemented hashpvs

Line 
1#include <stack>
2#include <time.h>
3#include <iomanip>
4
5#include "ViewCell.h"
6#include "Plane3.h"
7#include "OspTree.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#include "KdTree.h"
19#include "IntersectableWrapper.h"
20#include "VspTree.h"
21
22
23namespace GtpVisibilityPreprocessor {
24
25
26#define USE_FIXEDPOINT_T 0
27
28
29int MailablePvsData::sMailId = 1;
30int MailablePvsData::sReservedMailboxes = 1;
31
32
33        ////////////
34//-- static members
35
36OspTree *OspTree::OspSubdivisionCandidate::sOspTree = NULL;
37
38// variable for debugging volume contribution for heuristics
39static float debugVol;
40
41static bool ViewCellHasMultipleReferences(Intersectable *obj,
42                                                                                  ViewCell *vc,
43                                                                                  bool checkOnlyMailed)
44{
45        // no view cell pvs!!
46/*      MailablePvsData *vdata = obj->mViewCellPvs.Find(vc);
47
48        if (vdata)
49        {
50                // more than one view cell sees this object inside different kd cells
51                if (!checkOnlyMailed || !vdata->Mailed())
52                {
53                        if (checkOnlyMailed)
54                                vdata->Mail();
55                        //Debug << "sumpdf: " << vdata->mSumPdf << endl;
56                        if (vdata->mSumPdf > 1.5f)
57                                return true;
58                }
59        }*/
60
61        return false;
62}
63
64
65void OspTreeStatistics::Print(ostream &app) const
66{
67        app << "=========== OspTree statistics ===============\n";
68
69        app << setprecision(4);
70
71        app << "#N_CTIME  ( Construction time [s] )\n" << Time() << " \n";
72
73        app << "#N_NODES ( Number of nodes )\n" << nodes << "\n";
74
75        app << "#N_INTERIORS ( Number of interior nodes )\n" << Interior() << "\n";
76
77        app << "#N_LEAVES ( Number of leaves )\n" << Leaves() << "\n";
78
79        app << "#AXIS_ALIGNED_SPLITS (number of axis aligned splits)\n" << splits[0] + splits[1] + splits[2] << endl;
80
81        app << "#N_SPLITS ( Number of splits in axes x y z)\n";
82
83        for (int i = 0; i < 3; ++ i)
84                app << splits[i] << " ";
85        app << endl;
86
87        app << "#N_PMAXDEPTHLEAVES ( Percentage of leaves at maximum depth )\n"
88                <<      maxDepthNodes * 100 / (double)Leaves() << endl;
89
90        app << "#N_PMINPVSLEAVES  ( Percentage of leaves with mininimal PVS )\n"
91                << minPvsNodes * 100 / (double)Leaves() << endl;
92
93        //app << "#N_PMINOBJECTREFLEAVES  ( Percentage of leaves with minimal number of object ref)\n"
94                //<< minObjectNodes * 100 / (double)Leaves() << endl;
95
96        app << "#N_MAXCOSTNODES  ( Percentage of leaves with terminated because of max cost ratio )\n"
97                << maxCostNodes * 100 / (double)Leaves() << endl;
98
99        app << "#N_PMINPROBABILITYLEAVES  ( Percentage of leaves with mininum probability )\n"
100                << minProbabilityNodes * 100 / (double)Leaves() << endl;
101
102        app << "#N_PMAXDEPTH ( Maximal reached depth )\n" << maxDepth << endl;
103
104        app << "#N_PMINDEPTH ( Minimal reached depth )\n" << minDepth << endl;
105
106        app << "#AVGDEPTH ( average depth )\n" << AvgDepth() << endl;
107
108        app << "#N_INVALIDLEAVES (number of invalid leaves )\n" << invalidLeaves << endl;
109
110        app << "#N_MAXOBJECTREFS  ( Max number of object refs / leaf )\n" <<
111                 maxObjectRefs << "\n";
112
113//      app << "#N_RAYS (number of rays / leaf)\n" << AvgRays() << endl;
114        //app << "#N_PVS: " << pvs << endl;
115
116        app << "========== END OF VspTree statistics ==========\n";
117}
118
119
120/******************************************************************/
121/*                  class VspNode implementation                  */
122/******************************************************************/
123
124
125/*******************************************************************/
126/*                  class OspTree implementation                   */
127/*******************************************************************/
128
129
130OspTree::OspTree():
131mRoot(NULL),
132mTimeStamp(1),
133mCopyFromKdTree(false)
134{
135        ReadEnvironment();
136        mSubdivisionCandidates = new vector<SortableEntry>;
137}
138
139
140OspTree::OspTree(const KdTree &kdTree)
141{
142        ReadEnvironment();
143
144        // copy values from kd tree
145        mCopyFromKdTree = true;
146        mBoundingBox = kdTree.GetBox();
147        mRoot = kdTree.GetRoot();
148
149        mSubdivisionCandidates = new vector<SortableEntry>;
150}
151
152
153OspTree::~OspTree()
154{
155        // delete kd intersectables
156        KdIntersectableMap::iterator it, it_end = mKdIntersectables.end();
157
158        for (it = mKdIntersectables.begin(); it != mKdIntersectables.end(); ++ it)
159        {
160                DEL_PTR((*it).second);
161        }
162
163        // delete hierarchy only if not using the hierarchy from
164        // some other kd tree (otherwise the other kd tree has to do the job)
165        if (!mCopyFromKdTree)
166                DEL_PTR(mRoot);
167
168        DEL_PTR(mSubdivisionCandidates);
169        mSubdivisionStats.close();
170}
171
172
173void OspTree::ReadEnvironment()
174{
175        bool randomize = false;
176        Environment::GetSingleton()->GetBoolValue("VspTree.Construction.randomize", randomize);
177        if (randomize)
178                Randomize(); // initialise random generator for heuristics
179
180        //-- termination criteria for autopartition
181        Environment::GetSingleton()->GetIntValue("OspTree.Termination.maxDepth", mTermMaxDepth);
182        Environment::GetSingleton()->GetIntValue("OspTree.Termination.maxLeaves", mTermMaxLeaves);
183        Environment::GetSingleton()->GetIntValue("OspTree.Termination.minObjects", mTermMinObjects);
184        Environment::GetSingleton()->GetFloatValue("OspTree.Termination.minProbability", mTermMinProbability);
185       
186        Environment::GetSingleton()->GetIntValue("OspTree.Termination.missTolerance", mTermMissTolerance);
187       
188        //-- max cost ratio for early tree termination
189        Environment::GetSingleton()->GetFloatValue("OspTree.Termination.maxCostRatio", mTermMaxCostRatio);
190
191        Environment::GetSingleton()->GetFloatValue("OspTree.Termination.minGlobalCostRatio",
192                mTermMinGlobalCostRatio);
193       
194
195        //-- factors for bsp tree split plane heuristics
196        Environment::GetSingleton()->GetFloatValue("OspTree.Termination.ct_div_ci", mCtDivCi);
197
198        //-- partition criteria
199        Environment::GetSingleton()->GetFloatValue("OspTree.Construction.epsilon", mEpsilon);
200
201        // if only the driving axis is used for axis aligned split
202        Environment::GetSingleton()->GetBoolValue("OspTree.splitUseOnlyDrivingAxis", mOnlyDrivingAxis);
203        Environment::GetSingleton()->GetFloatValue("OspTree.maxStaticMemory", mMaxMemory);
204        Environment::GetSingleton()->GetBoolValue("OspTree.useCostHeuristics", mUseCostHeuristics);
205
206
207        char subdivisionStatsLog[100];
208        Environment::GetSingleton()->GetStringValue("OspTree.subdivisionStats", subdivisionStatsLog);
209        mSubdivisionStats.open(subdivisionStatsLog);
210
211        Environment::GetSingleton()->GetFloatValue("OspTree.Construction.splitBorder", mSplitBorder);
212        Environment::GetSingleton()->GetFloatValue(
213                "OspTree.Construction.renderCostDecreaseWeight", mRenderCostDecreaseWeight);
214       
215
216        //-- debug output
217
218        Debug << "******* OSP tree options ******** " << endl;
219
220    Debug << "max depth: " << mTermMaxDepth << endl;
221        Debug << "min probabiliy: " << mTermMinProbability << endl;
222        Debug << "min objects: " << mTermMinObjects << endl;
223        Debug << "max cost ratio: " << mTermMaxCostRatio << endl;
224        Debug << "miss tolerance: " << mTermMissTolerance << endl;
225        Debug << "max leaves: " << mTermMaxLeaves << endl;
226
227        Debug << "randomize: " << randomize << endl;
228
229        Debug << "min global cost ratio: " << mTermMinGlobalCostRatio << endl;
230        Debug << "global cost miss tolerance: " << mTermGlobalCostMissTolerance << endl;
231        Debug << "only driving axis: " << mOnlyDrivingAxis << endl;
232        Debug << "max memory: " << mMaxMemory << endl;
233        Debug << "use cost heuristics: " << mUseCostHeuristics << endl;
234        Debug << "subdivision stats log: " << subdivisionStatsLog << endl;
235       
236        Debug << "split borders: " << mSplitBorder << endl;
237        Debug << "render cost decrease weight: " << mRenderCostDecreaseWeight << endl;
238        Debug << endl;
239}
240
241
242void OspTree::SplitObjects(KdLeaf *parent,
243                                                   const AxisAlignedPlane& splitPlane,
244                                                   const ObjectContainer &objects,
245                                                   ObjectContainer &front,
246                                                   ObjectContainer &back)
247{
248        ObjectContainer::const_iterator oit, oit_end = objects.end();
249
250    for (oit = objects.begin(); oit != oit_end; ++ oit)
251        {
252                Intersectable *object = *oit;
253               
254                // initialise leaf references of objects
255                if (parent->IsRoot())
256                {
257                        // matt: no more parent ref
258                        //object->mReferences = 1;
259                }
260
261                // remove parent ref
262                // matt: no more parent ref
263                //-- object->mReferences;
264
265                // determine the side of this ray with respect to the plane
266                const AxisAlignedBox3 box = object->GetBox();
267
268                if (box.Max(splitPlane.mAxis) >= splitPlane.mPosition)
269                {
270            front.push_back(object);
271                        // matt: no more ref
272                        //++ object->mReferences;
273                }
274
275                if (box.Min(splitPlane.mAxis) < splitPlane.mPosition)
276                {
277                        back.push_back(object);
278                        // matt: no more ref
279                        //++ object->mReferences;
280                }
281        }
282
283        mOspStats.objectRefs -= (int)objects.size();
284        mOspStats.objectRefs += (int)(back.size() + front.size());
285}
286
287
288KdInterior *OspTree::SubdivideNode(
289                                                                   const AxisAlignedPlane &splitPlane,
290                                                                   const OspTraversalData &tData,
291                                                                   OspTraversalData &frontData,
292                                                                   OspTraversalData &backData
293                                                                   )
294{
295        KdLeaf *leaf = tData.mNode;
296       
297        // two new leaves
298    mOspStats.nodes += 2;
299
300        // add the new nodes to the tree
301        KdInterior *node = new KdInterior(leaf->mParent);
302
303        const int axis = splitPlane.mAxis;
304        const float position = splitPlane.mPosition;
305
306        node->mAxis = axis;
307        node->mPosition = position;
308        node->mBox = tData.mBoundingBox;
309
310
311        //-- the front and back traversal data is filled with the new values
312
313        // bounding boxes: split front and back node geometry
314        tData.mBoundingBox.Split(splitPlane.mAxis, splitPlane.mPosition,
315                frontData.mBoundingBox, backData.mBoundingBox);
316
317        frontData.mDepth = backData.mDepth = tData.mDepth + 1;
318               
319        //-- subdivide rays
320        frontData.mRays = new RayInfoContainer();
321        backData.mRays = new RayInfoContainer();
322
323/*      SplitRays(splitPlane,
324                          *tData.mRays,
325                          *frontData.mRays,
326                          *backData.mRays);
327*/
328
329        //-- classify objects
330
331        int objectsBack = 0;
332        int objectsFront = 0;
333
334    ObjectContainer::const_iterator mi, mi_end = leaf->mObjects.end();
335
336        for ( mi = leaf->mObjects.begin(); mi != mi_end; ++ mi)
337        {
338                // determine the side of this ray with respect to the plane
339                const AxisAlignedBox3 box = (*mi)->GetBox();
340               
341                if (box.Max(axis) >= position)
342                        ++ objectsFront;
343   
344                if (box.Min(axis) < position)
345                        ++ objectsBack;
346        }
347
348
349        // TODO matt: compute pvs
350        //frontData.mPvs = objectsFront;
351        //backData.mPvs = objectsBack;
352
353        //CheckViewCellsPvs(leaf, *tData.mRays);
354        RemoveParentViewCellsPvs(leaf, *tData.mRays);
355
356
357        /////////////
358        //-- create front and back leaf
359
360        KdLeaf *back = new KdLeaf(node, objectsBack);
361        KdLeaf *front = new KdLeaf(node, objectsFront);
362
363        KdInterior *parent = leaf->mParent;
364
365        // replace a link from node's parent
366        if (parent)
367        {
368                parent->ReplaceChildLink(leaf, node);
369                node->mParent = parent;
370        }
371        else // new root
372        {
373                mRoot = node;
374        }
375
376        // and setup child links
377        node->SetupChildLinks(back, front);
378
379        SplitObjects(leaf, splitPlane, leaf->mObjects, front->mObjects, back->mObjects);
380       
381        FilterRays(front, *tData.mRays, *frontData.mRays);
382        FilterRays(back, *tData.mRays, *backData.mRays);
383
384        ++ mOspStats.splits[splitPlane.mAxis];
385
386        //-- eval view cells pvs
387       
388        // remove parent pvs update pvs of left and right leaves
389        // Note: It is necessary to update first left and then right pvs.
390        // We need to store the view cells seen by each object,
391        // but also if the view cells are seen as part of two different
392        // kd leaves, which is stored in the pdf component of the pvs entry.
393        // Because if an object is part of a view cell more than once,
394        // it cannot be removed from the pvs by splitting a kd node where
395        // the view cell sees only the other child of the node.
396        // This is important during the subdivision
397
398        //MailablePvsData::NewMail();
399        UpdateViewCellsPvs(front, *frontData.mRays);
400        UpdateViewCellsPvs(back, *backData.mRays);
401
402        ////////////////////////////////////
403
404
405        ProcessMultipleRefs(front);
406    ProcessMultipleRefs(back);
407
408        frontData.mNode = front;
409        backData.mNode = back;
410
411        // compute probability, i.e., volume of seen view cells
412        frontData.mProbability = EvalViewCellsVolume(front, *frontData.mRays);
413        backData.mProbability =  EvalViewCellsVolume(back, *backData.mRays);
414
415        //delete leaf;
416        return node;
417}
418
419
420KdNode *OspTree::Subdivide(SplitQueue &tQueue,
421                                                   SubdivisionCandidate *splitCandidate,
422                                                   const bool globalCriteriaMet)
423{
424        OspSubdivisionCandidate *sc = static_cast<OspSubdivisionCandidate *>(splitCandidate);
425        OspTraversalData &tData = sc->mParentData;
426
427        KdNode *newNode = tData.mNode;
428
429        if (!LocalTerminationCriteriaMet(tData) && !globalCriteriaMet)
430        {       
431                OspTraversalData tFrontData;
432                OspTraversalData tBackData;
433
434                //-- continue subdivision
435               
436                // create new interior node and two leaf node
437                const AxisAlignedPlane splitPlane = sc->mSplitPlane;
438               
439                newNode = SubdivideNode(splitPlane,
440                                                                tData,
441                                                                tFrontData,
442                                                                tBackData);
443       
444                const int maxCostMisses = sc->GetMaxCostMisses();
445
446        // how often was max cost ratio missed in this branch?
447                tFrontData.mMaxCostMisses = maxCostMisses;
448                tBackData.mMaxCostMisses = maxCostMisses;
449               
450                mTotalCost -= sc->GetRenderCostDecrease();
451
452                // subdivision statistics
453                if (1) EvalSubdivisionStats(*sc);
454
455                //-- push the new split candidates on the queue
456               
457                OspSubdivisionCandidate *frontCandidate = new OspSubdivisionCandidate(tFrontData);
458                OspSubdivisionCandidate *backCandidate = new OspSubdivisionCandidate(tBackData);
459
460                EvalSubdivisionCandidate(*frontCandidate);
461                EvalSubdivisionCandidate(*backCandidate);
462
463                tQueue.Push(frontCandidate);
464                tQueue.Push(backCandidate);
465
466                // delete old leaf node
467                DEL_PTR(tData.mNode);
468        }
469
470
471        //-- terminate traversal
472        if (newNode->IsLeaf())
473        {
474                EvaluateLeafStats(tData);
475       
476                const bool mStoreRays= true;
477
478                //-- store additional info
479                if (mStoreRays)
480                {
481                        KdLeaf *leaf = static_cast<KdLeaf *>(newNode);
482
483                        RayInfoContainer::const_iterator it, it_end = tData.mRays->end();
484
485                        for (it = tData.mRays->begin(); it != it_end; ++ it)
486                        {
487                                (*it).mRay->Ref();                     
488                                leaf->mVssRays.push_back((*it).mRay);
489                        }
490                }
491        }
492       
493        //-- cleanup
494        tData.Clear();
495       
496        return newNode;
497}
498
499
500void OspTree::EvalSubdivisionCandidate(OspSubdivisionCandidate &splitCandidate)
501{
502        // compute locally best split plane
503        const float ratio = SelectSplitPlane(splitCandidate.mParentData,
504                                                                                 splitCandidate.mSplitPlane);
505
506        const bool success = ratio < mTermMaxCostRatio;
507        float oldRenderCost;
508
509        // compute global decrease in render cost
510        const float renderCostDecr = EvalRenderCostDecrease(splitCandidate.mSplitPlane,
511                                                                                                                splitCandidate.mParentData,
512                                                                                                                oldRenderCost);
513
514        splitCandidate.SetRenderCostDecrease(renderCostDecr);
515
516        const float pvsSizeIncr = 0; // todo
517#if 0
518        const float priority = (float)-data.mDepth;
519#else   
520        // take render cost of node into account
521        // otherwise danger of being stuck in a local minimum!!
522        const float factor = mRenderCostDecreaseWeight;
523        const float priority = factor * renderCostDecr + (1.0f - factor) * oldRenderCost;
524
525#endif
526
527        // compute global decrease in render cost
528        splitCandidate.SetPriority(priority);
529
530        splitCandidate.SetMaxCostMisses(success ?
531                splitCandidate.mParentData.mMaxCostMisses :
532                splitCandidate.mParentData.mMaxCostMisses + 1);
533}
534
535
536inline bool OspTree::LocalTerminationCriteriaMet(const OspTraversalData &data) const
537{
538        // matt: TODO
539        return (
540                //(data.mNode->mObjects.size() < mTermMinObjects) ||
541                //(data.mProbability <= mTermMinProbability) ||
542                (data.mDepth >= mTermMaxDepth)
543                 );
544}
545
546
547inline  bool OspTree::GlobalTerminationCriteriaMet(const OspTraversalData &data) const
548{
549        // matt: TODO
550        return (0
551                || (mOspStats.Leaves() >= mTermMaxLeaves)
552                //|| mOutOfMemory
553                || (mGlobalCostMisses >= mTermGlobalCostMissTolerance)
554                );
555}
556
557
558void OspTree::EvaluateLeafStats(const OspTraversalData &data)
559{
560        // the node became a leaf -> evaluate stats for leafs
561        KdLeaf *leaf = data.mNode;
562       
563        ++ mCreatedLeaves;
564
565        /*if (data.mPvs > mOspStats.maxPvs)
566        {
567                mOspStats.maxPvs = data.mPvs;
568        }
569
570        mOspStats.pvs += data.mPvs;
571
572        if (data.mDepth < mOspStats.minDepth)
573        {
574                mOspStats.minDepth = data.mDepth;
575        }*/
576       
577        if (data.mDepth >= mTermMaxDepth)
578        {
579        ++ mOspStats.maxDepthNodes;
580                //Debug << "new max depth: " << mVspStats.maxDepthNodes << endl;
581        }
582
583        if (data.mProbability <= mTermMinProbability)
584                ++ mOspStats.minProbabilityNodes;
585       
586        // accumulate depth to compute average depth
587        mOspStats.accumDepth += data.mDepth;
588 
589        //      if ((int)(leaf->mObjects.size()) < mTermMinCost)
590        //     ++ mOspStats.minCostNodes;
591 
592        if ((int)(leaf->mObjects.size()) > mOspStats.maxObjectRefs)
593                mOspStats.maxObjectRefs = (int)leaf->mObjects.size();
594
595#ifdef GTP_DEBUG
596        Debug << "BSP stats: "
597                  << "Depth: " << data.mDepth << " (max: " << mTermMaxDepth << "), "
598                  << "Prob: " << data.mProbability << " (min: " << mTermMinProbability << ")\n";
599#endif
600}
601
602
603float OspTree::EvalLocalCostHeuristics(const OspTraversalData &tData,
604                                                                           const AxisAlignedBox3 &box,
605                                                                           const int axis,
606                                                                           float &position,
607                                                                           int &objectsFront,
608                                                                           int &objectsBack)
609{
610        RayInfoContainer usedRays;
611        int mMaxTests = 500000; // HACK
612
613        if (mMaxTests < (int)tData.mRays->size())
614        {
615                GetRayInfoSets(*tData.mRays, mMaxTests, usedRays);
616        }
617        else
618        {
619                usedRays = *tData.mRays;
620        }
621
622        // go through the lists, count the number of objects left and right
623        // and evaluate the following cost funcion:
624        // C = ct_div_ci  + (ol + or)/queries
625       
626        const float minBox = box.Min(axis);
627        const float maxBox = box.Max(axis);
628        Debug << "min: " << minBox << " max: " << maxBox << endl;
629
630        const float sizeBox = maxBox - minBox;
631
632        float minBand = minBox + mSplitBorder * (maxBox - minBox);
633        float maxBand = minBox + (1.0f - mSplitBorder) * (maxBox - minBox);
634
635        const float viewSpaceVol = mVspTree->GetBoundingBox().GetVolume();
636
637        //-- sort so we can use a sweep
638        SortSubdivisionCandidates(tData, axis, minBand, maxBand);
639
640        float totalVol = 0;
641        float voll = 0;
642        float volr = totalVol;
643
644        ViewCellContainer touchedViewCells;
645       
646        const float totalRenderCost = PrepareHeuristics(tData, touchedViewCells);
647        float renderCost = totalRenderCost;
648
649        /// this is kind of a reverse pvs
650        const int totalPvs = (int)tData.mNode->mObjects.size();
651       
652        int pvsl = 0;
653        int pvsr = totalPvs;
654
655        float sum = (float)totalVol * sizeBox;
656
657        Debug << "total render cost: " << renderCost / viewSpaceVol << endl;
658
659        /////////////////////////////////
660
661        // note: initialised to take mid split
662        // if no good split can be found,
663        position = minBox + 0.5f * sizeBox;
664       
665        // the relative cost ratio
666        float ratio = 99999999.0f;
667        bool splitPlaneFound = false;
668
669        float volBack = voll;
670        float volFront = volr;
671
672        int pvsBack = pvsl;
673        int pvsFront = pvsr;
674       
675        float minRenderCost = 1e20f;
676
677        debugVol = 0;
678
679
680
681        /////////////////////////////
682        // the sweep heuristics
683
684       
685        //-- traverse through events and find best split plane
686       
687        vector<SortableEntry>::const_iterator ci, ci_end = mSubdivisionCandidates->end();
688        //minRenderCost = RandomValue(0,viewSpaceVol);
689
690        for (ci = mSubdivisionCandidates->begin(); ci != ci_end; ++ ci)
691        {
692                Intersectable *object = (*ci).mObject;
693
694                EvalHeuristicsContribution(tData.mNode,
695                                                                   *ci,
696                                                                   renderCost,
697                                                                   touchedViewCells
698                                                                  );
699
700                // Note: sufficient to compare size of bounding boxes of front and back side?
701                if (((*ci).mPos >= minBand) && ((*ci).mPos <= maxBand))
702                {
703                        float currentPos;
704                        Debug << "current min: " << minRenderCost / viewSpaceVol << endl;
705
706                        // HACK: current positition is BETWEEN visibility events
707                        if (1 && /*((*ci).mType == SortableEntry::BOX_INTERSECT) &&*/ ((ci + 1) != ci_end))
708                                currentPos = ((*ci).mPos + (*(ci + 1)).mPos) * 0.5f;
709                        else
710                                currentPos = (*ci).mPos;                       
711
712                        if (renderCost < minRenderCost)
713                        {
714                                splitPlaneFound = true;
715                                minRenderCost = renderCost;
716                                position = currentPos;
717                                Debug << "pos: " << position << endl;
718                        }
719                }
720        }
721//splitPlaneFound = true;
722        if (splitPlaneFound)
723        {
724                ratio = minRenderCost / totalRenderCost;
725        }
726#if GTP_DEBUG
727        Debug << "\n§§§§ eval local cost §§§§" << endl
728                  << "old rc: " << totalRenderCost / viewSpaceVol << " new rc: " << minRenderCost / viewSpaceVol << endl
729                  << "render cost decrease: " << (totalRenderCost - minRenderCost) / viewSpaceVol  << endl;
730#endif
731        return ratio;
732}
733
734
735void OspTree::SortSubdivisionCandidates(const OspTraversalData &tData,
736                                                                  const int axis,
737                                                                  float minBand,
738                                                                  float maxBand)
739
740{
741        mSubdivisionCandidates->clear();
742
743        RayInfoContainer *rays = tData.mRays;
744        KdLeaf *leaf = tData.mNode;
745
746        int requestedSize = 2 * (int)rays->size() + 2 * (int)leaf->mObjects.size();
747
748        // creates a sorted split candidates array
749        if (mSubdivisionCandidates->capacity() > 500000 &&
750                requestedSize < (int)(mSubdivisionCandidates->capacity() / 10) )
751        {
752        delete mSubdivisionCandidates;
753                mSubdivisionCandidates = new vector<SortableEntry>;
754        }
755
756        mSubdivisionCandidates->reserve(requestedSize);
757
758        float pos;
759
760        //-- insert ray queries
761        //-- we are intersested only in rays which intersect an object that
762        //-- is part of the kd node because they can induce a change in view cell
763        //-- volume on the left and the right part.
764        //-- Note that they cannot induce a change in pvs size!!
765
766        RayInfoContainer::const_iterator rit, rit_end = rays->end();
767
768        for (rit = rays->begin(); rit < rit_end; ++ rit)
769        {
770                VssRay *ray = (*rit).mRay;
771
772                const bool positive = ray->HasPosDir(axis);
773       
774                if (EndPointInsideNode(leaf, *ray, true))
775                {
776                        pos = ray->mTermination[axis];
777
778                        mSubdivisionCandidates->push_back(
779                                SortableEntry(SortableEntry::BOX_INTERSECT,
780                                                          pos,
781                                                          ray->mTerminationObject,
782                                                          ray)
783                                                          );
784                }
785
786                // if hitpoint with object is inside this node
787                if (EndPointInsideNode(leaf, *ray, false))
788                {
789                        pos = ray->mOrigin[axis];
790       
791                        mSubdivisionCandidates->push_back(
792                                SortableEntry(SortableEntry::BOX_INTERSECT,
793                                                          pos,
794                                                          ray->mOriginObject,
795                                                          ray)
796                                                          );
797                }
798        }
799
800
801        //-- insert object queries
802        //-- These queries can induce a change in pvs size.
803        //-- Note that they cannot induce a change in view cell volume, as
804        //-- there is no ray associated with these events!!
805
806        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
807
808    for (oit = leaf->mObjects.begin(); oit != leaf->mObjects.end(); ++ oit )
809        {
810                Intersectable *object = *oit;
811                const AxisAlignedBox3 box = object->GetBox();
812
813                mSubdivisionCandidates->push_back(
814                        SortableEntry(SortableEntry::BOX_MIN,
815                                                  box.Min(axis),
816                                                  object,
817                                                  NULL)
818                                                  );
819   
820   
821                mSubdivisionCandidates->push_back(
822                        SortableEntry(SortableEntry::BOX_MAX,
823                                                  box.Max(axis),
824                                                  object,
825                                                  NULL)
826                                                  );
827        }
828
829        stable_sort(mSubdivisionCandidates->begin(), mSubdivisionCandidates->end());
830}
831
832
833const OspTreeStatistics &OspTree::GetStatistics() const
834{
835        return mOspStats;
836}
837
838
839void OspTree::PrepareHeuristics(const VssRay &ray,
840                                                                ViewCellContainer &touchedViewCells)
841{
842        // collect view cells and set mail + counter
843        ViewCellContainer viewCells;
844        mVspTree->GetViewCells(ray, viewCells);
845       
846        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
847
848        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
849        {
850                ViewCell *vc = (*vit);
851
852                if (!vc->Mailed())
853                {
854                        vc->Mail(); // set as belonging to front leaf
855                        vc->mCounter = 0;
856                        touchedViewCells.push_back(vc);
857                }
858               
859                // view cell volume already added => just increase counter
860                ++ vc->mCounter;
861        }
862}
863
864
865float OspTree::PrepareHeuristics(const OspTraversalData &tData,
866                                                                 ViewCellContainer &touchedViewCells)
867{       
868        float renderCost = 0;
869
870        Intersectable::NewMail(3);
871        ViewCell::NewMail(3);
872        MailablePvsData::NewMail();
873
874        KdLeaf *leaf = tData.mNode;
875
876        RayInfoContainer::const_iterator rit, rit_end = tData.mRays->end();
877
878        for (rit = tData.mRays->begin(); rit < rit_end; ++ rit)
879        {
880                VssRay *ray = (*rit).mRay;
881        PrepareHeuristics(*ray, touchedViewCells);
882        }
883
884        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
885
886        for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
887        {
888                Intersectable *obj = *oit;
889                obj->Mail(); // set as belonging to front leaf
890               
891                ViewCellContainer::const_iterator vit, vit_end = touchedViewCells.end();
892
893                for (vit = touchedViewCells.begin(); vit != vit_end; ++ vit)
894                {
895                        ViewCell *vc = *vit;
896                        // no view cel pvs!!
897                        /*MailablePvsData *vdata = obj->mViewCellPvs.Find(vc);
898
899                        if (!vdata) // should never happen
900                                continue;
901
902                        if (!vdata->Mailed())
903                        {
904                                vdata->Mail();
905                                renderCost += vc->GetVolume();
906                        }*/
907                }
908        }
909
910        return renderCost;
911}
912
913
914void OspTree::AddObjectContribution(KdLeaf *leaf,
915                                                  Intersectable *obj,
916                                                  ViewCellContainer &touchedViewCells,
917                                                  float &renderCost)
918{
919        //Debug << "add contri to obj: " << obj->mMailbox - Intersectable::sMailId << endl;
920        obj->Mail(2); // set as belonging to both leafs
921
922        ViewCellContainer::const_iterator vit, vit_end = touchedViewCells.end();
923       
924        for (vit = touchedViewCells.begin(); vit != vit_end; ++ vit)
925        {
926                ViewCell *vc = *vit;
927       
928                // if obj not previously associated with this view cell => increase render cost
929                if (vc->Mailed(1) && !ViewCellHasMultipleReferences(obj, vc, false))
930                {       
931                        //Debug << "add to rendercost: " << vc->GetVolume() / mVspTree->GetBoundingBox().GetVolume() << endl;
932                        renderCost += vc->GetVolume();
933                }
934        }
935}
936
937
938void OspTree::SubtractObjectContribution(KdLeaf *leaf,
939                                                                Intersectable * obj,
940                                                                ViewCellContainer &touchedViewCells,
941                                                                float &renderCost)
942{
943        //Debug << "subtract contri from obj: " << obj->mMailbox - Intersectable::sMailId << endl;
944    obj->Mail(1); // set as belonging to back leaf
945        ViewCellContainer::const_iterator vit, vit_end = touchedViewCells.end();
946       
947        for (vit = touchedViewCells.begin(); vit != vit_end; ++ vit)
948        {
949                ViewCell *vc = *vit;
950
951                // if obj was previously associated with this view cell but is not now
952                // => decrease render cost
953                if (vc->Mailed() &&     !ViewCellHasMultipleReferences(obj, vc, false))
954                {
955                        //Debug << "subtract from rendercost: " << vc->GetVolume() / mVspTree->GetBoundingBox().GetVolume() << endl;
956                        renderCost -= vc->GetVolume();
957                }
958        }
959}
960
961
962void OspTree::EvalRayContribution(KdLeaf *leaf,
963                                                                  const VssRay &ray,
964                                                                  float &renderCost)
965{
966        ViewCellContainer viewCells;
967
968        mVspTree->GetViewCells(ray, viewCells);
969
970        // classify view cells and compute volume contri accordingly
971        // possible view cell classifications:
972        // view cell mailed => view cell can be seen from left child node
973        // view cell counter > 0 view cell can be seen from right child node
974        // combined: view cell volume belongs to both nodes
975        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
976       
977        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
978        {
979                EvalViewCellContribution(leaf, *vit, renderCost);
980        }
981}
982
983
984void OspTree::EvalViewCellContribution(KdLeaf *leaf,
985                                                                           ViewCell *viewCell,
986                                                                           float &renderCost)
987{
988        //Debug << "**************" << endl;
989        //Debug << "vc contri: " << renderCost / mVspTree->GetBoundingBox().GetVolume() << " " << viewCell->mMailbox - ViewCell::sMailId << " counter: " << viewCell->mCounter << endl;
990
991        const float vol = viewCell->GetVolume();
992
993        if (viewCell->Mailed())
994        {
995                viewCell->Mail(2); // view cell can be seen from both nodes
996
997        // we now see view cell from both nodes => add contri
998                ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
999
1000                for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
1001                {
1002                        Intersectable *obj = *oit;
1003
1004                        // was render cost already added?
1005                        if (!ViewCellHasMultipleReferences(obj, viewCell, false) &&
1006                                obj->Mailed(1))
1007                        {
1008                                //Debug << "obj mail 1!! " << vol / mVspTree->GetBoundingBox().GetVolume() << endl;
1009                                renderCost += vol;
1010                        }
1011                }
1012        }
1013
1014        if (-- viewCell->mCounter == 0)
1015        {
1016                viewCell->Mail(1); // view cell can be seen from back node only
1017
1018                //MailablePvsData::NewMail();
1019                ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
1020
1021                for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
1022                {
1023                        Intersectable *obj = *oit;
1024
1025                        // can render cost be be reduced?
1026                        if (!ViewCellHasMultipleReferences(obj, viewCell, false) &&     obj->Mailed())
1027                        {
1028                                renderCost -= vol;
1029                        }
1030                }
1031        }
1032        //Debug << "new rc: " << renderCost / mVspTree->GetBoundingBox().GetVolume() << " counter2: " << viewCell->mCounter << endl;
1033        //Debug << "**************"<<endl;
1034}
1035
1036
1037void OspTree::EvalHeuristicsContribution(KdLeaf *leaf,
1038                                                                                 const SortableEntry &ci,
1039                                                                                 float &renderCost,
1040                                                                                 ViewCellContainer &touchedViewCells)
1041{
1042        Intersectable *obj = ci.mObject;
1043        VssRay *ray = ci.mRay;
1044
1045        // switch between different types of events
1046        switch (ci.mType)
1047        {
1048                case SortableEntry::BOX_MIN:
1049                        cout << "<";
1050                        AddObjectContribution(leaf, ci.mObject, touchedViewCells, renderCost); 
1051                        break;
1052                       
1053                case SortableEntry::BOX_MAX:
1054                        cout << ">";
1055                        SubtractObjectContribution(leaf, ci.mObject, touchedViewCells, renderCost);
1056                        break;
1057
1058                // compute volume contribution from view cells
1059                case SortableEntry::BOX_INTERSECT:
1060                        cout << "i";
1061                        // process ray if the hit point with termination / origin object
1062                        // is inside this kd leaf
1063                        EvalRayContribution(leaf, *ray, renderCost);
1064                        break;
1065
1066                default:
1067                        cout << "should not come here" << endl;
1068                        break;
1069        }
1070
1071        //cout << "vol left: " << volLeft << " vol right " << volRight << endl;
1072}
1073
1074
1075void OspTree::SetViewCellsManager(ViewCellsManager *vcm)
1076{
1077        mViewCellsManager = vcm;
1078}
1079
1080
1081AxisAlignedBox3 OspTree::GetBoundingBox() const
1082{
1083        return mBoundingBox;
1084}
1085
1086
1087float OspTree::SelectSplitPlane(const OspTraversalData &tData,
1088                                                                AxisAlignedPlane &plane)
1089{
1090        float nPosition[3];
1091        float nCostRatio[3];
1092
1093        // create bounding box of node geometry
1094        AxisAlignedBox3 box = tData.mBoundingBox;
1095               
1096        int sAxis = 0;
1097        int bestAxis = -1;
1098
1099        if (mOnlyDrivingAxis)
1100        {
1101                sAxis = box.Size().DrivingAxis();
1102        }
1103       
1104
1105        // -- evaluate split cost for all three axis
1106        for (int axis = 0; axis < 3; ++ axis)
1107        {
1108                if (!mOnlyDrivingAxis || (axis == sAxis))
1109                {
1110                        if (1 || mUseCostHeuristics)
1111                        {
1112                                //-- place split plane using heuristics
1113                                int objectsFront, objectsBack;
1114
1115                                nCostRatio[axis] =
1116                                        EvalLocalCostHeuristics(tData,
1117                                                                           tData.mBoundingBox,
1118                                                                           axis,
1119                                                                           nPosition[axis],
1120                                                                           objectsFront,
1121                                                                           objectsBack);                       
1122                        }
1123                        /*      else
1124                        {
1125                                //-- split plane position is spatial median
1126
1127                                nPosition[axis] = (box.Min()[axis] + box.Max()[axis]) * 0.5f;
1128
1129                                nCostRatio[axis] = EvalLocalSplitCost(tData,
1130                                                                                                          box,
1131                                                                                                          axis,
1132                                                                                                          nPosition[axis],
1133                                                                                                          nProbFront[axis],
1134                                                                                                          nProbBack[axis]);
1135                        }*/
1136                                               
1137                        if (bestAxis == -1)
1138                        {
1139                                bestAxis = axis;
1140                        }
1141                        else if (nCostRatio[axis] < nCostRatio[bestAxis])
1142                        {
1143                                bestAxis = axis;
1144                        }
1145                }
1146        }
1147
1148        //-- assign values
1149
1150        plane.mAxis = bestAxis;
1151        // split plane position
1152    plane.mPosition = nPosition[bestAxis];
1153
1154        Debug << "val: " << nCostRatio[bestAxis] << " axis: " << bestAxis << endl;
1155        return nCostRatio[bestAxis];
1156}
1157
1158
1159bool OspTree::EndPointInsideNode(KdLeaf *leaf,
1160                                                                 VssRay &ray,
1161                                                                 bool isTermination) const
1162{
1163        // test if the leaf where the hitpoint is located is the current leaf
1164        if (isTermination)
1165        {
1166                 return ray.mTerminationObject && (GetLeaf(ray.mTermination, ray.mTerminationNode) == leaf);
1167        }
1168        else
1169        {
1170                return false; // no origin object!
1171                return ray.mOriginObject && (GetLeaf(ray.mOrigin, ray.mOriginNode) == leaf);
1172        }
1173}
1174
1175
1176void OspTree::EvalSubdivisionStats(const SubdivisionCandidate &sc)
1177{
1178        const float costDecr = sc.GetRenderCostDecrease();
1179
1180        AddSubdivisionStats(mOspStats.Leaves(),
1181                                                costDecr,
1182                                                mTotalCost
1183                                                );
1184}
1185
1186
1187void OspTree::AddSubdivisionStats(const int leaves,
1188                                                                  const float renderCostDecr,
1189                                                                  const float totalRenderCost)
1190{
1191        mSubdivisionStats
1192                        << "#Leaves\n" << leaves << endl
1193                        << "#RenderCostDecrease\n" << renderCostDecr << endl
1194                        << "#TotalRenderCost\n" << totalRenderCost << endl;
1195                        //<< "#AvgRenderCost\n" << avgRenderCost << endl;
1196}
1197
1198
1199int OspTree::ClassifyRay(VssRay *ray,
1200                                                 KdLeaf *leaf,
1201                                                 const AxisAlignedPlane &plane) const
1202{
1203        const bool originInside = EndPointInsideNode(leaf, *ray, false);
1204    const bool terminationInside = EndPointInsideNode(leaf, *ray, true);
1205
1206        const bool originGt = (ray->mOrigin[plane.mAxis] >= plane.mPosition);
1207        const bool originLt = (ray->mOrigin[plane.mAxis] <= plane.mPosition);
1208
1209        const bool terminationGt = (ray->mTermination[plane.mAxis] >= plane.mPosition);
1210        const bool terminationLt = (ray->mTermination[plane.mAxis] <= plane.mPosition);
1211
1212        // add view cell volume to front volume
1213        const bool addToFront =
1214                ((originInside && originGt) || (terminationInside && terminationGt));
1215
1216        // add view cell volume to back volume
1217        const bool addToBack =
1218                ((originInside && originLt/*!originGt*/) || (terminationInside && terminationLt/*terminationGt*/));
1219
1220        // classify ray with respect to the child nodes the view cells contribute
1221        if (addToFront && addToBack)
1222                return 0;
1223        else if (addToBack)
1224                return -1;
1225        else if (addToFront)
1226                return 1;
1227
1228        return -2;
1229}
1230
1231
1232int OspTree::ClassifyRays(const RayInfoContainer &rays,
1233                                                  KdLeaf *leaf,
1234                                                  const AxisAlignedPlane &plane,
1235                                                  RayInfoContainer &frontRays,
1236                                                  RayInfoContainer &backRays) const
1237{
1238        RayInfoContainer::const_iterator rit, rit_end = rays.end();
1239
1240        for (rit = rays.begin(); rit < rit_end; ++ rit)
1241        {
1242                VssRay *ray = (*rit).mRay;
1243
1244                bool originGt = false;
1245                bool terminationGt = false;
1246               
1247                Intersectable *obj = ray->mOriginObject;
1248
1249                if (0 && obj)
1250                {
1251                        originGt = ray->mOrigin[plane.mAxis] >= plane.mPosition;
1252                }
1253
1254                obj = ray->mTerminationObject;
1255               
1256                if (obj)
1257                {
1258                        terminationGt = ray->mTermination[plane.mAxis] >= plane.mPosition;
1259                }
1260
1261                // either begin or end point on front side
1262                const bool addToFront = originGt || terminationGt;
1263
1264                // add view cell volume to back volume
1265                const bool addToBack = !originGt || !terminationGt;
1266       
1267                // classify ray with respect to the child nodes the view cells contribute
1268                if (addToFront)
1269                        frontRays.push_back(*rit);
1270                if (addToBack)
1271                        backRays.push_back(*rit);
1272        }
1273
1274        return 0;
1275}
1276
1277
1278float OspTree::EvalRenderCostDecrease(const AxisAlignedPlane &candidatePlane,
1279                                                                          const OspTraversalData &tData,
1280                                                                          float &normalizedOldRenderCost) const
1281{
1282        float pvsFront = 0;
1283        float pvsBack = 0;
1284
1285        // probability that view point lies in back / front node
1286        float pOverall = 0;
1287        float pFront = 0;
1288        float pBack = 0;
1289        float pFrontAndBack = 0;
1290
1291        Intersectable::NewMail(3);
1292        KdLeaf *leaf = tData.mNode;
1293
1294        const float viewSpaceVol = mVspTree->GetBoundingBox().GetVolume();
1295        const int totalPvs = (int)leaf->mObjects.size();
1296       
1297        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
1298
1299        // evaluate reverse pvs and view cell volume on left and right cell
1300        // note: should I take all leaf objects or rather the objects hit by rays?
1301        for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
1302        {
1303                int pvsContri = 0;
1304
1305                Intersectable *obj = *oit;
1306                const AxisAlignedBox3 box = obj->GetBox();
1307
1308                // test if box falls in left / right child node
1309                if (box.Max(candidatePlane.mAxis) >= candidatePlane.mPosition)
1310                {
1311                        ++ pvsFront;
1312                        obj->Mail();           
1313                }
1314
1315                if (box.Min(candidatePlane.mAxis) < candidatePlane.mPosition)
1316                {
1317                        ++ pvsBack;
1318
1319                        if (obj->Mailed())
1320                                obj->Mail(2);
1321                        else
1322                                obj->Mail(1);
1323                }
1324        }
1325
1326        ViewCellContainer touchedViewCells;
1327
1328        // sum up volume seen from the objects of left and right children
1329        // => the volume is the weight for the render cost equation
1330        ViewCell::NewMail(3);
1331
1332        RayInfoContainer::const_iterator rit, rit_end = tData.mRays->end();
1333        //map<Intersectable *, ViewCellContainer> objectsMap;
1334
1335        for (rit = tData.mRays->begin(); rit < rit_end; ++ rit)
1336        {
1337                VssRay *ray = (*rit).mRay;
1338
1339                // add volume to volumes of left and / or right children
1340                // if one of the ray end points is inside
1341                const int classification = ClassifyRay(ray, leaf, candidatePlane);
1342
1343                ViewCellContainer viewCells;
1344                mVspTree->GetViewCells(*ray, viewCells);
1345                       
1346                ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
1347
1348                // traverse through view cells and classify them according
1349                // to them being seen from to back / front / front and back node
1350                for (vit = viewCells.begin(); vit != vit_end; ++ vit)
1351                {
1352                        ViewCell *vc = *vit;
1353
1354                        // if not previously mailed
1355                        if (!vc->Mailed() && !vc->Mailed(1) && !vc->Mailed(2))
1356                        {
1357                                touchedViewCells.push_back(vc);
1358                        }
1359
1360                        // classify / mail the view cell
1361                        MailViewCell(vc, classification);
1362                }
1363        }
1364
1365        // evaluate view cells volume contribution
1366        // with respect to the mail box classification
1367        ViewCellContainer::const_iterator vit, vit_end = touchedViewCells.end();
1368
1369        for (vit = touchedViewCells.begin(); vit != vit_end; ++ vit)
1370        {
1371                AddViewCellVolumeContri(*vit, pFront, pBack, pFrontAndBack);
1372        }
1373
1374        //////////////////////////////////////////////
1375        //
1376        // evaluate contribution of objects which are part of other kd nodes
1377        // which are seen by the same view cell
1378        // These contributions cannot be reduced by splitting, because
1379        // the object would still be part of the pvs
1380
1381        float newRc = 0;
1382        float rc = 0;
1383
1384        MailablePvsData::NewMail();
1385        //ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
1386
1387        for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
1388        {
1389                Intersectable *obj = *oit;
1390                ViewCellContainer::const_iterator vit, vit_end = touchedViewCells.end();
1391
1392                for (vit = touchedViewCells.begin(); vit != vit_end; ++ vit)
1393                {
1394                        ViewCell *vc = *vit;
1395                        // no more view cell pvs!!
1396                        /*MailablePvsData *vdata = obj->mViewCellPvs.Find(vc);
1397                        if (!vdata)
1398                        {
1399                                Debug << "error! should not come here" << endl;
1400                                continue;
1401                        }
1402
1403                        if (!vdata->Mailed())
1404                        {
1405                                vdata->Mail();
1406                                rc += vc->GetVolume();
1407
1408                                if ((vdata->mSumPdf > 1.5) ||
1409                                        vc->Mailed(2) ||
1410                                        obj->Mailed(2) ||
1411                                        (obj->Mailed() && vc->Mailed()) ||
1412                                        (obj->Mailed(1) && vc->Mailed(1))
1413                                        )
1414                                {
1415                                        newRc += vc->GetVolume();
1416                                }
1417                        }*/
1418                }
1419        }
1420
1421
1422        /////////////////////////////
1423        //-- pvs rendering heuristics
1424
1425        const float oldRenderCost = rc;
1426       
1427        // sum up the terms:
1428        // the view cells seeing
1429        // a) the left node are weighted by the #left node objects
1430        // b) the right node are weighted by the #right node objects
1431        // c) both nodes are weighted by the #parent node objects
1432        const float newRenderCost = newRc;
1433
1434
1435        // normalize volume with view space volume
1436        const float renderCostDecrease = (oldRenderCost - newRenderCost) / viewSpaceVol;
1437
1438        Debug << "\nrender cost decrease: " << endl
1439                  << "old rc: " << oldRenderCost / viewSpaceVol << " new rc: " << newRenderCost / viewSpaceVol << endl
1440                  << "render cost decrease: " << renderCostDecrease << endl;
1441
1442        normalizedOldRenderCost = oldRenderCost / viewSpaceVol;
1443
1444               
1445        return renderCostDecrease;
1446}
1447
1448
1449void OspTree::ComputeBoundingBox(const ObjectContainer &objects)
1450{
1451        mBoundingBox.Initialize();
1452
1453        ObjectContainer::const_iterator oit, oit_end = objects.end();
1454
1455        //-- compute bounding box
1456        for (oit = objects.begin(); oit != oit_end; ++ oit)
1457        {
1458                Intersectable *obj = *oit;
1459
1460                // compute bounding box of view space
1461                mBoundingBox.Include(obj->GetBox());
1462        }
1463}
1464
1465
1466void OspTree::ProcessMultipleRefs(KdLeaf *leaf) const
1467{
1468        // find objects from multiple kd-leaves
1469        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
1470
1471        for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
1472        {
1473                Intersectable *object = *oit;
1474               
1475                // matt: no more ref
1476                /*if (object->mReferences > 1)
1477                {
1478                        leaf->mMultipleObjects.push_back(object);
1479                }*/
1480        }
1481}
1482
1483
1484void OspTree::CollectLeaves(vector<KdLeaf *> &leaves) const
1485{
1486        stack<KdNode *> nodeStack;
1487        nodeStack.push(mRoot);
1488
1489        while (!nodeStack.empty())
1490        {
1491                KdNode *node = nodeStack.top();
1492                nodeStack.pop();
1493                if (node->IsLeaf())
1494                {
1495                        KdLeaf *leaf = (KdLeaf *)node;
1496                        leaves.push_back(leaf);
1497                }
1498                else
1499                {
1500                        KdInterior *interior = (KdInterior *)node;
1501                        nodeStack.push(interior->mBack);
1502                        nodeStack.push(interior->mFront);
1503                }
1504        }
1505}
1506
1507
1508AxisAlignedBox3 OspTree::GetBoundingBox(KdNode *node) const
1509{
1510        if (!node->mParent)
1511                return mBoundingBox;
1512
1513        if (!node->IsLeaf())
1514        {
1515                return (static_cast<KdInterior *>(node))->mBox;         
1516        }
1517
1518        KdInterior *parent = static_cast<KdInterior *>(node->mParent);
1519
1520        AxisAlignedBox3 box(parent->mBox);
1521
1522        if (parent->mFront == node)
1523                box.SetMin(parent->mAxis, parent->mPosition);
1524    else
1525                box.SetMax(parent->mAxis, parent->mPosition);
1526
1527        return box;
1528}
1529
1530
1531void OspTree::CollectViewCells(KdLeaf *leaf, ViewCellContainer &viewCells)
1532{
1533        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
1534
1535        ViewCell::NewMail();
1536
1537        // loop through all object and collect view cell pvs of this node
1538        for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
1539        {
1540                Intersectable *obj = *oit;
1541                // no more view cell pvs!!
1542                /*ViewCellPvsMap::const_iterator vit, vit_end = obj->mViewCellPvs.mEntries.end();
1543
1544                for (vit = obj->mViewCellPvs.mEntries.begin(); vit != vit_end; ++ vit)
1545                {
1546            ViewCell *vc = (*vit).first;
1547
1548                        if (!vc->Mailed())
1549                        {
1550                                vc->Mail();
1551                                viewCells.push_back(vc);
1552                        }
1553                }*/
1554        }
1555}
1556
1557
1558void OspTree::CollectDirtyCandidates(OspSubdivisionCandidate *sc,
1559                                                                         vector<SubdivisionCandidate *> &dirtyList,
1560                                                                         const bool onlyUnmailed)
1561{
1562        OspTraversalData &tData = sc->mParentData;
1563        KdLeaf *node = tData.mNode;
1564       
1565        ViewCell::NewMail();
1566        ViewCellContainer viewCells;
1567        ViewCellContainer tmpViewCells;
1568
1569        RayInfoContainer::const_iterator rit, rit_end = tData.mRays->end();
1570
1571        // find all view cells associated with the rays, add them to view cells
1572        for (rit = tData.mRays->begin(); rit != rit_end; ++ rit)
1573        {
1574                VssRay *ray = (*rit).mRay;
1575                mVspTree->GetViewCells(*ray, tmpViewCells);
1576
1577                ViewCellContainer::const_iterator vit, vit_end = tmpViewCells.end();
1578
1579                for (vit = tmpViewCells.begin(); vit != vit_end; ++ vit)
1580                {
1581                        VspViewCell *vc = static_cast<VspViewCell *>(*vit);
1582
1583                        if (!vc->Mailed())
1584                        {
1585                                vc->Mail();
1586                                viewCells.push_back(vc);
1587                        }
1588                }
1589        }
1590
1591        // andidates holding this view cells are thrown into dirty list
1592        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
1593
1594        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
1595        {
1596                VspViewCell *vc = static_cast<VspViewCell *>(*vit);
1597
1598                VspLeaf *leaf = vc->mLeaves[0];
1599
1600                SubdivisionCandidate *dsc = leaf->GetSubdivisionCandidate();
1601                if (dsc && (!onlyUnmailed || !dsc->Mailed()))
1602                {
1603                        dsc->Mail();
1604                        dirtyList.push_back(dsc);
1605                }
1606        }
1607}
1608
1609
1610KdNode *OspTree::GetRoot() const
1611{
1612        return mRoot;
1613}
1614
1615
1616KdLeaf *OspTree::GetLeaf(const Vector3 &pt, KdNode *node) const
1617{
1618        // start from root of tree
1619        if (node == NULL)
1620        {
1621                node = mRoot;
1622        }
1623
1624        stack<KdNode *> nodeStack;
1625        nodeStack.push(node);
1626 
1627        KdLeaf *leaf = NULL;
1628 
1629        while (!nodeStack.empty()) 
1630        {
1631                KdNode *node = nodeStack.top();
1632                nodeStack.pop();
1633       
1634                if (node->IsLeaf())
1635                {
1636                        leaf = static_cast<KdLeaf *>(node);
1637                }
1638                else   
1639                {       
1640                        // find point
1641                        KdInterior *interior = static_cast<KdInterior *>(node);
1642       
1643                        if (interior->mPosition > pt[interior->mAxis])
1644                        {
1645                                nodeStack.push(interior->mBack);
1646                        }
1647                        else
1648                        {
1649                                nodeStack.push(interior->mFront);
1650                        }
1651                }
1652        }
1653 
1654        return leaf;
1655}
1656
1657
1658void OspTree::PreprocessRays(KdLeaf *root,
1659                                                         const VssRayContainer &sampleRays,
1660                                                         RayInfoContainer &rays)
1661{
1662        VssRayContainer::const_iterator rit, rit_end = sampleRays.end();
1663        RayInfoContainer clippedRays;
1664
1665        long startTime = GetTime();
1666
1667        cout << "storing rays ... ";
1668
1669        Intersectable::NewMail();
1670
1671        //-- store rays and objects
1672        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
1673        {
1674                VssRay *ray = *rit;
1675
1676                float minT, maxT;
1677                static Ray hray;
1678
1679                hray.Init(*ray);
1680               
1681                // TODO: not very efficient to implictly cast between rays types
1682                if (GetBoundingBox().GetRaySegment(hray, minT, maxT))
1683                {
1684                        float len = ray->Length();
1685                        if (!len)
1686                                len = Limits::Small;
1687
1688                        clippedRays.push_back(RayInfo(ray, minT / len, maxT / len));
1689
1690                        // HACK: reset nodes for the case we have used object kd tree for
1691                        // tree building.
1692                        ray->mOriginNode = NULL;
1693                        ray->mTerminationNode = NULL;
1694                }
1695        }
1696
1697        FilterRays(root, clippedRays, rays);
1698
1699        cout << "finished in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
1700}
1701
1702
1703
1704int OspTree::SplitRays(const AxisAlignedPlane &plane,
1705                                           RayInfoContainer &rays,
1706                                           RayInfoContainer &frontRays,
1707                                           RayInfoContainer &backRays) const
1708{
1709        int splits = 0;
1710
1711        RayInfoContainer::const_iterator rit, rit_end = rays.end();
1712
1713        for (rit = rays.begin(); rit != rit_end; ++ rit)
1714        {
1715                RayInfo bRay = *rit;
1716               
1717                VssRay *ray = bRay.mRay;
1718                float t;
1719
1720                // get classification and receive new t
1721                //-- test if start point behind or in front of plane
1722                const int side = bRay.ComputeRayIntersection(plane.mAxis, plane.mPosition, t);
1723                       
1724                if (side == 0)
1725                {
1726                        ++ splits;
1727
1728                        if (ray->HasPosDir(plane.mAxis))
1729                        {
1730                                backRays.push_back(RayInfo(ray, bRay.GetMinT(), t));
1731                                frontRays.push_back(RayInfo(ray, t, bRay.GetMaxT()));
1732                        }
1733                        else
1734                        {
1735                                frontRays.push_back(RayInfo(ray, bRay.GetMinT(), t));
1736                                backRays.push_back(RayInfo(ray, t, bRay.GetMaxT()));
1737                        }
1738                }
1739                else if (side == 1)
1740                {
1741                        frontRays.push_back(bRay);
1742                }
1743                else
1744                {
1745                        backRays.push_back(bRay);
1746                }
1747        }
1748
1749        return splits;
1750}
1751
1752
1753int OspTree::FilterRays(KdLeaf *leaf,
1754                                                const RayInfoContainer &rays,
1755                                                RayInfoContainer &filteredRays)
1756{
1757        RayInfoContainer::const_iterator rit, rit_end = rays.end();
1758
1759        for (rit = rays.begin(); rit != rit_end; ++ rit)
1760        {
1761                VssRay *ray = (*rit).mRay;
1762
1763                // test if intersection point with one of the objects is inside this node
1764                const bool originInside = EndPointInsideNode(leaf, *ray, false);
1765        const bool terminationInside = EndPointInsideNode(leaf, *ray, true);
1766
1767                if (originInside || terminationInside)
1768                {
1769                        filteredRays.push_back(ray);
1770                }
1771        }
1772
1773        return 0;
1774}
1775                                         
1776
1777int OspTree::CheckViewCellsPvs(KdLeaf *leaf,
1778                                                           const RayInfoContainer &rays) const
1779{
1780        RayInfoContainer::const_iterator rit, rit_end = rays.end();
1781
1782        Intersectable::NewMail();
1783        ObjectContainer touchedObjects;
1784       
1785
1786        for (rit = rays.begin(); rit < rit_end; ++ rit)
1787        {
1788                VssRay *ray = (*rit).mRay;
1789
1790                if (ray->mTerminationObject)
1791                {
1792                        Intersectable *obj = ray->mTerminationObject;
1793
1794                        if (!obj->Mailed())
1795                        {
1796                                obj->Mail();
1797                                touchedObjects.push_back(obj);
1798                        }
1799                }
1800
1801                if (ray->mOriginObject)
1802                {
1803                        Intersectable *obj = ray->mOriginObject;
1804
1805                        if (!obj->Mailed())
1806                        {
1807                                obj->Mail();
1808                                touchedObjects.push_back(obj);
1809                        }
1810                }
1811        }
1812        Debug << "touched view cells: " << (int)touchedObjects.size() << endl;
1813        ObjectContainer::const_iterator it, it_end = touchedObjects.end();
1814        for (it = touchedObjects.begin(); it != it_end; ++ it)
1815        {
1816                // no more view cell pvs!!
1817                /*Debug << "\nobj: " << (*it) << " vc pvs size: " << (*it)->mViewCellPvs.GetSize() << endl << endl;
1818                ViewCellPvsMap::const_iterator mit, mit_end = (*it)->mViewCellPvs.mEntries.end();
1819
1820                for (mit = (*it)->mViewCellPvs.mEntries.begin(); mit != mit_end; ++ mit)
1821                {
1822                        Debug << "new sumpdf: " << (*mit).second.mSumPdf << endl;
1823                }*/
1824        }
1825
1826        return 0;
1827}
1828
1829
1830KdIntersectable *OspTree::GetOrCreateKdIntersectable(KdNode *node)
1831{
1832        //if (!node) return NULL;
1833
1834        // search nodes
1835        std::map<KdNode *, KdIntersectable *>::const_iterator it = mKdIntersectables.find(node);
1836
1837        if (it != mKdIntersectables.end())
1838        {
1839                return (*it).second;
1840        }
1841
1842        // not in map => create new entry
1843        KdIntersectable *kdObj = new KdIntersectable(node, GetBoundingBox(node));
1844        mKdIntersectables[node] = kdObj;
1845
1846        return kdObj;
1847}
1848
1849
1850/*
1851void OspTree::AddViewCellVolume(ViewCell *vc,
1852                                                                const int cf,
1853                                                                float &frontVol,
1854                                                                float &backVol,
1855                                                                float &totalVol) const
1856{
1857        //const float renderCost = mViewCellsManager->SimpleRay &raynderCost(obj);
1858        const float vol = vc->GetVolume();
1859
1860        // view cell not found yet => new
1861        if (!vc->Mailed() && !vc->Mailed(1) && !vc->Mailed(2))
1862        {
1863                totalVol += vol;
1864        }
1865
1866        if (cf >= 0) // front volume
1867        {
1868                if (!vc->Mailed() && !vc->Mailed(2))
1869                {
1870                        frontVol += vol;
1871               
1872                        // already in back volume => in both volumes
1873                        if (vc->Mailed(1))
1874                                vc->Mail(2);
1875                        else
1876                                vc->Mail();
1877                }
1878        }
1879
1880        if (cf <= 0) // back volume
1881        {
1882                if (!vc->Mailed(1) && !vc->Mailed(2))
1883                {
1884                        backVol += vol;
1885               
1886                        // already in front volume => in both volume
1887                        if (vc->Mailed())
1888                                vc->Mail(2);
1889                        else
1890                                vc->Mail(1);
1891                }
1892        }
1893}
1894*/
1895
1896
1897void OspTree::MailViewCell(ViewCell *vc, const int cf) const
1898{
1899        if (vc->Mailed(2)) // already classified
1900                return;
1901
1902        if (cf >= 0) // front volume
1903        {
1904                // already in back volume => in both volumes
1905                if (vc->Mailed(1))
1906                {
1907                        vc->Mail(2);
1908                }
1909                else
1910                {
1911                        vc->Mail();
1912                }
1913        }
1914
1915        if (cf <= 0) // back volume
1916        {
1917                // already in front volume => in both volume
1918                if (vc->Mailed())
1919                {
1920                        vc->Mail(2);
1921                }
1922                else
1923                {
1924                        vc->Mail(1);
1925                }
1926        }
1927}
1928
1929
1930void OspTree::AddViewCellVolumeContri(ViewCell *vc,
1931                                                                          float &frontVol,
1932                                                                          float &backVol,
1933                                                                          float &frontAndBackVol) const
1934{
1935        if (vc->Mailed())
1936        {
1937                frontVol += vc->GetVolume();
1938        }
1939        else if (vc->Mailed(1))
1940        {
1941                backVol += vc->GetVolume();
1942        }
1943        else if (vc->Mailed(2))
1944        {
1945                frontAndBackVol += vc->GetVolume();
1946        }
1947}
1948
1949
1950float OspTree::EvalViewCellsVolume(KdLeaf *leaf,
1951                                                                   const RayInfoContainer &rays) const
1952{
1953        float vol = 0;
1954        ViewCell::NewMail();
1955
1956        RayInfoContainer::const_iterator rit, rit_end = rays.end();
1957
1958        for (rit = rays.begin(); rit != rays.end(); ++ rit)
1959        {
1960                VssRay *ray = (*rit).mRay;
1961
1962                ViewCellContainer viewCells;
1963                mVspTree->GetViewCells(*ray, viewCells);
1964
1965                ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
1966                       
1967                for (vit = viewCells.begin(); vit != vit_end; ++ vit)
1968                {
1969                        ViewCell *vc = *vit;
1970
1971                        if (!vc->Mailed())
1972                        {
1973                                vc->Mail();
1974                                vol += vc->GetVolume();
1975                        }
1976                }               
1977        }
1978
1979        return vol;
1980}
1981
1982
1983bool OspTree::AddViewCellToObjectPvs(Intersectable *obj,
1984                                                                         ViewCell *vc,
1985                                                                         float &contribution,
1986                                                                         bool onlyUnmailed) const
1987{       
1988        contribution = 0; // todo
1989       
1990        // no more view cell pvs!!
1991        /*MailablePvsData *vdata = obj->mViewCellPvs.Find(vc);
1992        if (!vdata)
1993        {
1994                vdata = obj->mViewCellPvs.AddSample2(vc, 1);
1995        }
1996        else if (!onlyUnmailed || !vdata->Mailed())
1997        {
1998                obj->mViewCellPvs.AddSample(vc, 1);
1999        }
2000
2001        vdata->Mail();
2002        */
2003
2004        return true;
2005}
2006
2007
2008void OspTree::CollectTouchedViewCells(const RayInfoContainer &rays,
2009                                                                          ViewCellContainer &touchedViewCells) const
2010{
2011        ViewCell::NewMail();
2012       
2013        RayInfoContainer::const_iterator rit, rit_end = rays.end();
2014
2015        for (rit = rays.begin(); rit != rit_end; ++ rit)
2016        {
2017                VssRay *ray = (*rit).mRay;
2018
2019                ViewCellContainer viewCells;
2020                mVspTree->GetViewCells(*ray, viewCells);
2021
2022                ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
2023
2024                // traverse through view cells and classify them according
2025                // to them being seen from to back / front / front and back node
2026                for (vit = viewCells.begin(); vit != vit_end; ++ vit)
2027                {
2028                        ViewCell *vc = *vit;
2029                        if (!vc->Mailed())
2030                        {
2031                                vc->Mail();
2032                                touchedViewCells.push_back(vc);
2033                        }
2034                }
2035        }
2036}
2037
2038
2039int OspTree::UpdateViewCellsPvs(KdLeaf *leaf,
2040                                                                const RayInfoContainer &rays) const
2041
2042{
2043        MailablePvsData::NewMail();
2044       
2045        ViewCellContainer touchedViewCells;
2046        CollectTouchedViewCells(rays, touchedViewCells);
2047
2048        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
2049
2050        for (oit = leaf->mObjects.begin(); oit < oit_end; ++ oit)
2051        {
2052                Intersectable *obj = *oit;
2053                ViewCellContainer::const_iterator vit, vit_end = touchedViewCells.end();
2054
2055                // traverse through view cells and classify them according
2056                // to them being seen from to back / front / front and back node
2057                for (vit = touchedViewCells.begin(); vit != vit_end; ++ vit)
2058                {
2059                        ViewCell *vc = *vit;
2060                        float contri;
2061                        AddViewCellToObjectPvs(obj, vc, contri, true);
2062                }
2063        }
2064
2065        return 0;
2066}
2067
2068
2069int OspTree::RemoveParentViewCellsPvs(KdLeaf *leaf,
2070                                                                          const RayInfoContainer &rays
2071                                                                          ) const
2072
2073{
2074        MailablePvsData::NewMail();
2075
2076        ViewCellContainer touchedViewCells;
2077        CollectTouchedViewCells(rays, touchedViewCells);
2078
2079        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
2080
2081        for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
2082        {
2083                Intersectable *obj = *oit;
2084
2085                // traverse through view cells and classify them according
2086                // to them being seen from to back / front / front and back node
2087        ViewCellContainer::const_iterator vit, vit_end = touchedViewCells.end();
2088
2089                for (vit = touchedViewCells.begin(); vit != vit_end; ++ vit)
2090                {
2091                        ViewCell *vc = *vit;
2092                       
2093                        /*MailablePvsData *vdata = obj->mViewCellPvs.Find(vc);
2094
2095                        if (vdata && !vdata->Mailed())
2096                        {
2097                                vdata->Mail();
2098                                obj->mViewCellPvs.RemoveSample(vc, 1);
2099                        }*/
2100                }
2101        }
2102
2103        return 0;
2104}
2105
2106
2107float OspTree::EvalRenderCost(const VssRayContainer &myrays)
2108{
2109        float rc = 0;
2110        float prop = mVspTree->GetBoundingBox().GetVolume();   
2111
2112        KdLeafContainer leaves;
2113        CollectLeaves(leaves);
2114
2115        ViewCellContainer vcleaves;
2116        mVspTree->CollectViewCells(vcleaves, false);
2117       
2118
2119        ViewCellContainer::const_iterator vit, vit_end = vcleaves.end();
2120
2121        for (vit = vcleaves.begin(); vit != vit_end; ++ vit)
2122        {
2123                ViewCell *vc = *vit;
2124                vc->GetPvs().Clear();
2125        }
2126
2127        KdLeafContainer::const_iterator kit, kit_end = leaves.end();
2128
2129        MailablePvsData::NewMail();
2130
2131        for (kit = leaves.begin(); kit != kit_end; ++ kit)
2132        {
2133                KdLeaf *leaf = *kit;
2134                float newCost = 0;
2135                float vol = 0;
2136
2137                ViewCell::NewMail();
2138                VssRayContainer::const_iterator rit, rit_end = leaf->mVssRays.end();
2139                ViewCellContainer touchedViewCells;
2140
2141                for (rit = leaf->mVssRays.begin(); rit != rit_end; ++ rit)
2142                {
2143                        VssRay *ray = *rit;
2144                       
2145                        // test if intersection point with one of the objects is inside this node
2146                        const bool originInside = EndPointInsideNode(leaf, *ray, false);
2147                        const bool terminationInside = EndPointInsideNode(leaf, *ray, true);
2148
2149                        if (originInside || terminationInside)
2150                        {
2151                                ViewCellContainer viewCells;
2152                                mVspTree->GetViewCells(*ray, viewCells);
2153                       
2154                                ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
2155
2156                                for (vit = viewCells.begin(); vit != vit_end; ++ vit)
2157                                {
2158                                        ViewCell *vc = *vit;
2159
2160                                        // if not previously mailed
2161                                        if (!vc->Mailed())
2162                                        {
2163                                                vc->Mail();
2164                                                touchedViewCells.push_back(vc);
2165                                        }
2166
2167                        }
2168                        }
2169                }
2170               
2171                ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
2172
2173                for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
2174                {
2175                        Intersectable *obj = *oit;
2176                        ViewCellContainer::const_iterator vit, vit_end = touchedViewCells.end();
2177
2178                        for (vit = touchedViewCells.begin(); vit != vit_end; ++ vit)
2179                        {
2180                                ViewCell *vc = *vit;
2181                                /*PvsData *vdata = vc->GetPvs().Find(obj);
2182
2183                                if (!vdata)
2184                                {
2185                                        vc->GetPvs().AddSample(obj, 1);
2186                                        newCost += vc->GetVolume();
2187                                }
2188
2189                                MailablePvsData *vdata = obj->mViewCellPvs.Find(vc);
2190
2191                                if (!vdata || !vdata->Mailed())
2192                                {
2193                                        newCost += vc->GetVolume();
2194                                        if (!vdata)
2195                                                vdata = obj->mViewCellPvs.AddSample2(vc, 1);
2196                                        vdata->Mail();
2197                                }*/
2198                        }
2199                }
2200
2201                rc += newCost;
2202        }
2203
2204        return rc / prop;
2205}
2206
2207
2208float OspTree::EvalLeafCost(const OspTraversalData &tData)
2209{
2210        KdLeaf *leaf = tData.mNode;
2211
2212        float rc = 0;
2213        //float prop = mVspTree->GetBoundingBox().GetVolume(); 
2214        //float vol = 0;
2215        //ViewCell::NewMail();
2216       
2217        RayInfoContainer::const_iterator rit, rit_end = tData.mRays->end();
2218        ViewCellContainer touchedViewCells;
2219
2220        for (rit = tData.mRays->begin(); rit != rit_end; ++ rit)
2221        {
2222                VssRay *ray = (*rit).mRay;
2223                       
2224                // test if intersection point with one of the objects is inside this node
2225
2226                ViewCellContainer viewCells;
2227                mVspTree->GetViewCells(*ray, viewCells);
2228                       
2229                ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
2230
2231                for (vit = viewCells.begin(); vit != vit_end; ++ vit)
2232                {
2233                        ViewCell *vc = *vit;
2234
2235                        // if not previously mailed
2236                        if (!vc->Mailed())
2237                        {
2238                                vc->Mail();
2239                                touchedViewCells.push_back(vc);
2240                        }
2241                }
2242        }
2243
2244        // clear pvs of involved view cells
2245        ViewCellContainer::const_iterator vit, vit_end = touchedViewCells.end();
2246
2247        for (vit = touchedViewCells.begin(); vit != vit_end; ++ vit)
2248        {
2249                ViewCell *vc = *vit;
2250                vc->GetPvs().Clear();
2251        }
2252       
2253        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
2254
2255        for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
2256        {
2257                Intersectable *obj = *oit;
2258
2259                for (vit = touchedViewCells.begin(); vit != vit_end; ++ vit)
2260                {
2261                        ViewCell *vc = *vit;
2262                        /*PvsData *vdata = vc->GetPvs().Find(obj);
2263
2264                        if (!vdata)
2265                        {
2266                                vc->GetPvs().AddSample(obj, 1);
2267                                rc += vc->GetVolume();
2268                        }
2269                        */
2270                }
2271        }
2272       
2273        return rc;
2274}
2275
2276
2277bool OspTree::Export(OUT_STREAM &stream)
2278{
2279        ExportNode(mRoot, stream);
2280
2281        return true;
2282}
2283
2284
2285void OspTree::ExportNode(KdNode *node, OUT_STREAM &stream)
2286{
2287        if (node->IsLeaf())
2288        {
2289                KdLeaf *leaf = static_cast<KdLeaf *>(node);
2290
2291                stream << "<Leaf ";
2292                stream << "objects=\"";
2293               
2294                // export objects in kd leaves
2295                //if (mExportObjects) ExportObjects(leaf, stream);
2296               
2297                stream << "\" />" << endl;
2298        }
2299        else
2300        {       
2301                KdInterior *interior = static_cast<KdInterior *>(node);
2302       
2303                stream << "<Interior plane=\"" << interior->mPosition << " "
2304                           << interior->mAxis << "\">" << endl;
2305
2306                ExportNode(interior->mBack, stream);
2307                ExportNode(interior->mFront, stream);
2308
2309                stream << "</Interior>" << endl;
2310        }
2311}
2312
2313
2314struct KdObjectsTraversalData
2315{
2316        KdNode *node;
2317        ObjectContainer *objects;
2318};
2319
2320
2321void OspTree::InsertObjects(KdNode *node, const ObjectContainer &objects)
2322{
2323        stack<KdObjectsTraversalData> tStack;
2324
2325        while (!tStack.empty())
2326        {
2327                KdObjectsTraversalData tData = tStack.top();
2328        tStack.pop();
2329
2330                KdNode *node = tData.node;
2331               
2332                if (node->IsLeaf())
2333                {
2334                        KdLeaf *leaf = static_cast<KdLeaf *>(node);
2335
2336                        ObjectContainer::const_iterator oit, oit_end = tData.objects->end();
2337
2338                        for (oit = tData.objects->begin(); oit != oit_end; ++ oit)
2339                        {
2340                                leaf->mObjects.push_back(*oit);
2341                        }
2342                }
2343                else // interior
2344                {
2345                        KdObjectsTraversalData frontData, backData;
2346                        KdInterior *interior = static_cast<KdInterior *>(node);
2347
2348                        frontData.objects = new ObjectContainer();
2349                        backData.objects = new ObjectContainer();
2350
2351                        ObjectContainer::const_iterator oit, oit_end = tData.objects->end();
2352                       
2353                    for (oit = tData.objects->begin(); oit != oit_end; ++ oit)
2354                        {
2355                                Intersectable *object = *oit;
2356               
2357                                // determine the side of this ray with respect to the plane
2358                                const AxisAlignedBox3 box = object->GetBox();
2359
2360                                if (box.Max(interior->mAxis) >= interior->mPosition)
2361                                {
2362                                        frontData.objects->push_back(object);
2363                                }
2364
2365                                if (box.Min(interior->mAxis) < interior->mPosition)
2366                                {
2367                                        backData.objects->push_back(object);
2368                                }
2369                        }
2370
2371                        tStack.push(backData);
2372                        tStack.push(frontData);
2373                }
2374
2375                DEL_PTR(tData.objects);
2376        }
2377}
2378
2379
2380void OspTree::PrepareConstruction(SplitQueue &tQueue,
2381                                                                  const VssRayContainer &sampleRays,
2382                                                                  const ObjectContainer &objects,
2383                                                                  RayInfoContainer &rays)
2384{
2385        // store pointer to this tree
2386        OspSubdivisionCandidate::sOspTree = this;
2387        mOspStats.nodes = 1;
2388       
2389        // compute bounding box from objects
2390        ComputeBoundingBox(objects);
2391
2392        mTermMinProbability *= mBoundingBox.GetVolume();
2393        mGlobalCostMisses = 0;
2394
2395        //-- create new root
2396        KdLeaf *kdleaf = new KdLeaf(NULL, 0);
2397        kdleaf->mObjects = objects;
2398        mRoot = kdleaf;
2399       
2400        // get clipped rays
2401        PreprocessRays(kdleaf, sampleRays, rays);
2402
2403        // probabilty is voume of all "seen" view cells
2404#if 1
2405        const float prop = EvalViewCellsVolume(kdleaf, rays);
2406#else
2407        const float prop = GetBoundingBox().GetVolume();
2408#endif
2409
2410        //-- add first candidate for object space partition
2411
2412        // create osp traversal data
2413        OspTraversalData oData(kdleaf, 0, &rays, 0, prop, mBoundingBox);
2414
2415        //-- first split candidate
2416        OspSubdivisionCandidate *oSubdivisionCandidate =
2417                new OspSubdivisionCandidate(oData);
2418
2419        UpdateViewCellsPvs(kdleaf, rays);
2420
2421        EvalSubdivisionCandidate(*oSubdivisionCandidate);
2422
2423        mTotalCost = (float)objects.size() * prop /
2424                mVspTree->GetBoundingBox().GetVolume();
2425
2426        EvalSubdivisionStats(*oSubdivisionCandidate);
2427
2428        tQueue.Push(oSubdivisionCandidate);
2429}
2430
2431
2432bool OspTree::AddLeafToPvs(KdLeaf *leaf,
2433                                                   ViewCell *vc,
2434                                                   const float pdf,
2435                                                   float &contribution)
2436{
2437        // add kd intersecable to pvs
2438        KdIntersectable *kdObj = GetOrCreateKdIntersectable(leaf);
2439       
2440        return vc->AddPvsSample(kdObj, pdf, contribution);
2441}
2442
2443
2444}
Note: See TracBrowser for help on using the repository browser.