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

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