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

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