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

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