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

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