source: GTP/trunk/Lib/Vis/Preprocessing/src/BvHierarchy.cpp @ 1486

Revision 1486, 49.2 KB checked in by mattausch, 18 years ago (diff)

worked on guided visibility sampling

Line 
1#include <stack>
2#include <time.h>
3#include <iomanip>
4
5#include "BvHierarchy.h"
6#include "ViewCell.h"
7#include "Plane3.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 "VspTree.h"
19#include "HierarchyManager.h"
20
21
22namespace GtpVisibilityPreprocessor {
23
24
25#define PROBABILIY_IS_BV_VOLUME 1
26#define USE_FIXEDPOINT_T 0
27
28int BvhNode::sMailId = 10000; //2147483647;
29int BvhNode::sReservedMailboxes = 1;
30
31BvHierarchy *BvHierarchy::BvhSubdivisionCandidate::sBvHierarchy = NULL;
32
33
34/// sorting operator
35inline static bool ilt(Intersectable *obj1, Intersectable *obj2)
36{
37        return obj1->mId < obj2->mId;
38}
39
40
41/***************************************************************/
42/*              class BvhNode implementation                   */
43/***************************************************************/
44
45BvhNode::BvhNode(): mParent(NULL), mMailbox(0)
46{
47}
48
49BvhNode::BvhNode(const AxisAlignedBox3 &bbox):
50mParent(NULL), mBoundingBox(bbox), mMailbox(0)
51{
52}
53
54
55BvhNode::BvhNode(const AxisAlignedBox3 &bbox, BvhInterior *parent):
56mBoundingBox(bbox), mParent(parent), mMailbox(0)
57{
58}
59
60
61bool BvhNode::IsRoot() const
62{
63        return mParent == NULL;
64}
65
66
67BvhInterior *BvhNode::GetParent()
68{
69        return mParent;
70}
71
72
73void BvhNode::SetParent(BvhInterior *parent)
74{
75        mParent = parent;
76}
77
78
79
80/******************************************************************/
81/*              class BvhInterior implementation                  */
82/******************************************************************/
83
84
85BvhLeaf::BvhLeaf(const AxisAlignedBox3 &bbox):
86BvhNode(bbox), mSubdivisionCandidate(NULL)
87{
88}
89
90
91BvhLeaf::BvhLeaf(const AxisAlignedBox3 &bbox, BvhInterior *parent):
92BvhNode(bbox, parent)
93{
94}
95
96
97BvhLeaf::BvhLeaf(const AxisAlignedBox3 &bbox,
98                                 BvhInterior *parent,
99                                 const int numObjects):
100BvhNode(bbox, parent)
101{
102        mObjects.reserve(numObjects);
103}
104
105
106bool BvhLeaf::IsLeaf() const
107{
108        return true;
109}
110
111
112BvhLeaf::~BvhLeaf()
113{
114}
115
116
117/******************************************************************/
118/*              class BvhInterior implementation                  */
119/******************************************************************/
120
121
122BvhInterior::BvhInterior(const AxisAlignedBox3 &bbox):
123BvhNode(bbox), mFront(NULL), mBack(NULL)
124{
125}
126
127
128BvhInterior::BvhInterior(const AxisAlignedBox3 &bbox, BvhInterior *parent):
129BvhNode(bbox, parent), mFront(NULL), mBack(NULL)
130{
131}
132
133
134void BvhInterior::ReplaceChildLink(BvhNode *oldChild, BvhNode *newChild)
135{
136        if (mBack == oldChild)
137                mBack = newChild;
138        else
139                mFront = newChild;
140}
141
142
143bool BvhInterior::IsLeaf() const
144{
145        return false;
146}
147
148
149BvhInterior::~BvhInterior()
150{
151        DEL_PTR(mFront);
152        DEL_PTR(mBack);
153}
154
155
156void BvhInterior::SetupChildLinks(BvhNode *front, BvhNode *back)
157{
158    mBack = back;
159    mFront = front;
160}
161
162
163
164/*******************************************************************/
165/*                  class BvHierarchy implementation               */
166/*******************************************************************/
167
168
169BvHierarchy::BvHierarchy():
170mRoot(NULL),
171mTimeStamp(1)
172{
173        ReadEnvironment();
174        mSubdivisionCandidates = new SortableEntryContainer;
175}
176
177
178BvHierarchy::~BvHierarchy()
179{
180        // delete kd intersectables
181        BvhIntersectableMap::iterator it, it_end = mBvhIntersectables.end();
182
183        for (it = mBvhIntersectables.begin(); it != mBvhIntersectables.end(); ++ it)
184        {
185                DEL_PTR((*it).second);
186        }
187
188        DEL_PTR(mSubdivisionCandidates);
189
190        mSubdivisionStats.close();
191}
192
193
194void BvHierarchy::ReadEnvironment()
195{
196        bool randomize = false;
197        Environment::GetSingleton()->GetBoolValue("VspTree.Construction.randomize", randomize);
198        if (randomize)
199                Randomize(); // initialise random generator for heuristics
200
201
202        /////////////////////////////////////////////////////////////
203        //-- termination criteria for autopartition
204        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.maxDepth", mTermMaxDepth);
205        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.maxLeaves", mTermMaxLeaves);
206        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.minObjects", mTermMinObjects);
207        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.minRays", mTermMinRays);
208        Environment::GetSingleton()->GetFloatValue("BvHierarchy.Termination.minProbability", mTermMinProbability);
209       
210        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.missTolerance", mTermMissTolerance);
211
212
213        //////////////////////////////
214        //-- max cost ratio for early tree termination
215
216        Environment::GetSingleton()->GetFloatValue("BvHierarchy.Termination.maxCostRatio", mTermMaxCostRatio);
217        Environment::GetSingleton()->GetFloatValue("BvHierarchy.Termination.minGlobalCostRatio",
218                mTermMinGlobalCostRatio);
219        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.globalCostMissTolerance",
220                mTermGlobalCostMissTolerance);
221
222
223        //////////////////////////////
224        //-- factors for subdivision heuristics
225
226        // if only the driving axis is used for splits
227        Environment::GetSingleton()->GetBoolValue("BvHierarchy.splitUseOnlyDrivingAxis", mOnlyDrivingAxis);
228        Environment::GetSingleton()->GetFloatValue("BvHierarchy.maxStaticMemory", mMaxMemory);
229        Environment::GetSingleton()->GetBoolValue("BvHierarchy.useCostHeuristics", mUseCostHeuristics);
230
231        char subdivisionStatsLog[100];
232        Environment::GetSingleton()->GetStringValue("BvHierarchy.subdivisionStats", subdivisionStatsLog);
233        mSubdivisionStats.open(subdivisionStatsLog);
234
235        Environment::GetSingleton()->GetFloatValue(
236                "BvHierarchy.Construction.renderCostDecreaseWeight", mRenderCostDecreaseWeight);
237       
238        Environment::GetSingleton()->GetBoolValue("BvHierarchy.Construction.useGlobalSorting", mUseGlobalSorting);
239
240
241        /////////////
242        //-- debug output
243
244        Debug << "******* Bvh hierarchy options ******** " << endl;
245    Debug << "max depth: " << mTermMaxDepth << endl;
246        Debug << "min probabiliy: " << mTermMinProbability<< endl;
247        Debug << "min objects: " << mTermMinObjects << endl;
248        Debug << "max cost ratio: " << mTermMaxCostRatio << endl;
249        Debug << "miss tolerance: " << mTermMissTolerance << endl;
250        Debug << "max leaves: " << mTermMaxLeaves << endl;
251        Debug << "randomize: " << randomize << endl;
252        Debug << "min global cost ratio: " << mTermMinGlobalCostRatio << endl;
253        Debug << "global cost miss tolerance: " << mTermGlobalCostMissTolerance << endl;
254        Debug << "only driving axis: " << mOnlyDrivingAxis << endl;
255        Debug << "max memory: " << mMaxMemory << endl;
256        Debug << "use cost heuristics: " << mUseCostHeuristics << endl;
257        Debug << "subdivision stats log: " << subdivisionStatsLog << endl;
258        Debug << "split borders: " << mSplitBorder << endl;
259        Debug << "render cost decrease weight: " << mRenderCostDecreaseWeight << endl;
260        Debug << "use global sort: " << mUseGlobalSorting << endl;
261        Debug << endl;
262}
263
264
265void BvHierarchy::AssociateObjectsWithLeaf(BvhLeaf *leaf)
266{
267        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
268        for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
269        {
270                (*oit)->mBvhLeaf = leaf;
271        }
272}
273
274
275static int CountRays(const ObjectContainer &objects)
276{
277        int nRays = 0;
278
279        ObjectContainer::const_iterator oit, oit_end = objects.end();
280
281        for (oit = objects.begin(); oit != oit_end; ++ oit)
282        {
283                nRays += (int)(*oit)->mVssRays.size();
284        }
285
286        return nRays;
287}
288
289
290BvhInterior *BvHierarchy::SubdivideNode(const BvhSubdivisionCandidate &sc,
291                                                                                BvhTraversalData &frontData,
292                                                                                BvhTraversalData &backData)
293{
294        const BvhTraversalData &tData = sc.mParentData;
295        BvhLeaf *leaf = tData.mNode;
296        AxisAlignedBox3 parentBox = leaf->GetBoundingBox();
297
298        // update stats: we have two new leaves
299        mBvhStats.nodes += 2;
300
301        if (tData.mDepth > mBvhStats.maxDepth)
302        {
303                mBvhStats.maxDepth = tData.mDepth;
304        }
305
306        // add the new nodes to the tree
307        BvhInterior *node = new BvhInterior(parentBox, leaf->GetParent());
308       
309
310        //////////////////
311        //-- create front and back leaf
312
313        AxisAlignedBox3 fbox = EvalBoundingBox(sc.mFrontObjects, &parentBox);
314        AxisAlignedBox3 bbox = EvalBoundingBox(sc.mBackObjects, &parentBox);
315
316        BvhLeaf *back =
317                new BvhLeaf(bbox, node, (int)sc.mBackObjects.size());
318        BvhLeaf *front =
319                new BvhLeaf(fbox, node, (int)sc.mFrontObjects.size());
320
321        BvhInterior *parent = leaf->GetParent();
322
323        // replace a link from node's parent
324        if (parent)
325        {
326                parent->ReplaceChildLink(leaf, node);
327                node->SetParent(parent);
328        }
329        else // no parent => this node is the root
330        {
331                mRoot = node;
332        }
333
334        // and setup child links
335        node->SetupChildLinks(front, back);
336
337        ++ mBvhStats.splits;
338
339
340        ////////////////////////////////////////
341        //-- fill  front and back traversal data with the new values
342
343        frontData.mDepth = backData.mDepth = tData.mDepth + 1;
344
345        frontData.mNode = front;
346        backData.mNode = back;
347
348        back->mObjects = sc.mBackObjects;
349        front->mObjects = sc.mFrontObjects;
350
351        // if the number of rays is too low, no assumptions can be made
352        // (=> switch to surface area heuristics?)
353        frontData.mNumRays = CountRays(sc.mFrontObjects);
354        backData.mNumRays = CountRays(sc.mBackObjects);
355
356        AssociateObjectsWithLeaf(back);
357        AssociateObjectsWithLeaf(front);
358   
359#if PROBABILIY_IS_BV_VOLUME
360        // volume of bvh (= probability that this bvh can be seen)
361        frontData.mProbability = fbox.GetVolume();
362        backData.mProbability = bbox.GetVolume();
363#else
364        // compute probability of this node being visible,
365        // i.e., volume of the view cells that can see this node
366        frontData.mProbability = EvalViewCellsVolume(sc.mFrontObjects);
367        backData.mProbability = EvalViewCellsVolume(sc.mBackObjects);
368#endif
369
370    // how often was max cost ratio missed in this branch?
371        frontData.mMaxCostMisses = sc.mMaxCostMisses;
372        backData.mMaxCostMisses = sc.mMaxCostMisses;
373       
374        // assign the objects in sorted order
375        if (mUseGlobalSorting)
376        {
377                AssignSortedObjects(sc, frontData, backData);
378        }
379       
380        // return the new interior node
381        return node;
382}
383
384
385BvhNode *BvHierarchy::Subdivide(SplitQueue &tQueue,
386                                                                SubdivisionCandidate *splitCandidate,
387                                                                const bool globalCriteriaMet)
388{
389        BvhSubdivisionCandidate *sc =
390                dynamic_cast<BvhSubdivisionCandidate *>(splitCandidate);
391        BvhTraversalData &tData = sc->mParentData;
392
393        BvhNode *currentNode = tData.mNode;
394
395        if (!LocalTerminationCriteriaMet(tData) && !globalCriteriaMet)
396        {       
397                //////////////
398                //-- continue subdivision
399
400                BvhTraversalData tFrontData;
401                BvhTraversalData tBackData;
402                       
403                // create new interior node and two leaf node
404                currentNode = SubdivideNode(
405                        *sc,
406                        tFrontData,
407                        tBackData);
408       
409                // decrease the weighted average cost of the subdivisoin
410                mTotalCost -= sc->GetRenderCostDecrease();
411
412                // subdivision statistics
413                if (1) PrintSubdivisionStats(*sc);
414
415
416                ///////////////////////////
417                //-- push the new split candidates on the queue
418               
419                BvhSubdivisionCandidate *frontCandidate =
420                        new BvhSubdivisionCandidate(tFrontData);
421                BvhSubdivisionCandidate *backCandidate =
422                        new BvhSubdivisionCandidate(tBackData);
423
424                EvalSubdivisionCandidate(*frontCandidate);
425                EvalSubdivisionCandidate(*backCandidate);
426       
427                // cross reference
428                tFrontData.mNode->SetSubdivisionCandidate(frontCandidate);
429                tBackData.mNode->SetSubdivisionCandidate(backCandidate);
430
431                tQueue.Push(frontCandidate);
432                tQueue.Push(backCandidate);
433        }
434
435        /////////////////////////////////
436        //-- node is a leaf => terminate traversal
437
438        if (currentNode->IsLeaf())
439        {
440                //////////////////////////////////////
441                //-- store additional info
442                EvaluateLeafStats(tData);
443       
444                const bool mStoreRays = true;
445                if (mStoreRays)
446                {
447                        BvhLeaf *leaf = dynamic_cast<BvhLeaf *>(currentNode);
448                        CollectRays(leaf->mObjects, leaf->mVssRays);
449                }
450               
451                //////////////////////////////////////
452               
453                // this leaf is no candidate for splitting anymore
454                // => detach subdivision candidate
455                tData.mNode->SetSubdivisionCandidate(NULL);
456                // detach node so we don't delete it with the traversal data
457                tData.mNode = NULL;
458        }
459       
460        return currentNode;
461}
462
463
464void BvHierarchy::EvalSubdivisionCandidate(BvhSubdivisionCandidate &splitCandidate)
465{
466        // compute best object partition
467        const float ratio =     SelectObjectPartition(
468                                                        splitCandidate.mParentData,
469                                                        splitCandidate.mFrontObjects,
470                                                        splitCandidate.mBackObjects);
471       
472        BvhLeaf *leaf = splitCandidate.mParentData.mNode;
473
474        // cost ratio violated?
475        const bool maxCostRatioViolated = mTermMaxCostRatio < ratio;
476
477        splitCandidate.mMaxCostMisses = maxCostRatioViolated ?
478                splitCandidate.mParentData.mMaxCostMisses + 1 :
479                splitCandidate.mParentData.mMaxCostMisses;
480
481        const float oldProp = EvalViewCellsVolume(leaf->mObjects);
482        const float oldRenderCost = EvalRenderCost(leaf->mObjects);
483               
484        // compute global decrease in render cost
485        const float newRenderCost =
486                EvalRenderCost(splitCandidate.mFrontObjects) +
487                EvalRenderCost(splitCandidate.mBackObjects);
488
489        const float renderCostDecr = oldRenderCost - newRenderCost;
490
491//#ifdef _DEBUG
492        Debug << "old render cost: " << oldRenderCost << endl;
493        Debug << "new render cost: " << newRenderCost << endl;
494        Debug << "render cost decrease: " << renderCostDecr << endl;
495//#endif
496        splitCandidate.SetRenderCostDecrease(renderCostDecr);
497
498#if 1
499        // take render cost of node into account
500        // otherwise danger of being stuck in a local minimum!!
501        const float factor = mRenderCostDecreaseWeight;
502        const float priority = factor * renderCostDecr + (1.0f - factor) * oldRenderCost;
503#else
504        const float priority = (float)-splitCandidate.mParentData.mDepth;
505#endif
506
507        // compute global decrease in render cost
508        splitCandidate.SetPriority(priority);
509}
510
511
512inline bool BvHierarchy::LocalTerminationCriteriaMet(const BvhTraversalData &data) const
513{
514        // matt: TODO
515        return ( 0
516                || ((int)data.mNode->mObjects.size() <= mTermMinObjects)
517                || (data.mProbability <= mTermMinProbability)
518                || (data.mDepth >= mTermMaxDepth)
519                || (data.mNumRays <= mTermMinRays)
520                 );
521}
522
523
524inline bool BvHierarchy::GlobalTerminationCriteriaMet(const BvhTraversalData &data) const
525{
526        const bool terminationCriteriaMet =
527                (0
528                || (mBvhStats.Leaves() >= mTermMaxLeaves)
529                || (mBvhStats.mGlobalCostMisses >= mTermGlobalCostMissTolerance)
530                //|| mOutOfMemory
531                );
532
533        if (1 && terminationCriteriaMet)
534        {
535                Debug << "bvh global termination criteria met:" << endl;
536                Debug << "cost misses: " << mBvhStats.mGlobalCostMisses << " " << mTermGlobalCostMissTolerance << endl;
537                Debug << "leaves: " << mBvhStats.Leaves() << " " << mTermMaxLeaves << endl;
538        }
539
540        return terminationCriteriaMet;
541}
542
543
544void BvHierarchy::EvaluateLeafStats(const BvhTraversalData &data)
545{
546        // the node became a leaf -> evaluate stats for leafs
547        BvhLeaf *leaf = data.mNode;
548       
549        ++ mCreatedLeaves;
550
551       
552        if (data.mProbability <= mTermMinProbability)
553        {
554                ++ mBvhStats.minProbabilityNodes;
555        }
556
557        ////////////////////////////////////////////
558        // depth related stuff
559
560        if (data.mDepth < mBvhStats.minDepth)
561        {
562                mBvhStats.minDepth = data.mDepth;
563        }
564
565        if (data.mDepth >= mTermMaxDepth)
566        {
567        ++ mBvhStats.maxDepthNodes;
568        }
569
570        // accumulate depth to compute average depth
571        mBvhStats.accumDepth += data.mDepth;
572
573
574        ////////////////////////////////////////////
575        // objects related stuff
576
577        // note: this number should always accumulate to the total number of objects
578        mBvhStats.objectRefs += (int)leaf->mObjects.size();
579
580        if ((int)leaf->mObjects.size() <= mTermMinObjects)
581        {
582             ++ mBvhStats.minObjectsNodes;
583        }
584
585        if (leaf->mObjects.empty())
586        {
587                ++ mBvhStats.emptyNodes;
588        }
589
590        if ((int)leaf->mObjects.size() > mBvhStats.maxObjectRefs)
591        {
592                mBvhStats.maxObjectRefs = (int)leaf->mObjects.size();
593        }
594
595        if ((int)leaf->mObjects.size() < mBvhStats.minObjectRefs)
596        {
597                mBvhStats.minObjectRefs = (int)leaf->mObjects.size();
598        }
599
600        ////////////////////////////////////////////
601        // ray related stuff
602
603        // note: this number should always accumulate to the total number of rays
604        mBvhStats.rayRefs += data.mNumRays;
605       
606        if (data.mNumRays <= mTermMinRays)
607        {
608             ++ mBvhStats.minRaysNodes;
609        }
610
611        if (data.mNumRays > mBvhStats.maxRayRefs)
612        {
613                mBvhStats.maxRayRefs = data.mNumRays;
614        }
615
616        if (data.mNumRays < mBvhStats.minRayRefs)
617        {
618                mBvhStats.minRayRefs = data.mNumRays;
619        }
620
621#if 0
622        cout << "depth: " << data.mDepth << " objects: " << (int)leaf->mObjects.size()
623                 << " rays: " << data.mNumRays << " rays / objects "
624                 << (float)data.mNumRays / (float)leaf->mObjects.size() << endl;
625#endif
626}
627
628
629#if 0
630
631/// compute object boundaries using spatial mid split
632float BvHierarchy::EvalLocalObjectPartition(const BvhTraversalData &tData,
633                                                                                        const int axis,
634                                                                                        ObjectContainer &objectsFront,
635                                                                                        ObjectContainer &objectsBack)
636{
637        const float maxBox = tData.mBoundingBox.Max(axis);
638        const float minBox = tData.mBoundingBox.Min(axis);
639
640        float midPoint = (maxBox + minBox) * 0.5f;
641
642        ObjectContainer::const_iterator oit, oit_end = tData.mNode->mObjects.end();
643       
644        for (oit = tData.mNode->mObjects.begin(); oit != oit_end; ++ oit)
645        {
646                Intersectable *obj = *oit;
647                const AxisAlignedBox3 box = obj->GetBox();
648
649                const float objMid = (box.Max(axis) + box.Min(axis)) * 0.5f;
650
651                // object mailed => belongs to back objects
652                if (objMid < midPoint)
653                {
654                        objectsBack.push_back(obj);
655                }
656                else
657                {
658                        objectsFront.push_back(obj);
659                }
660        }
661
662        const float oldRenderCost = EvalRenderCost(tData.mNode->mObjects);
663        const float newRenderCost =
664                EvalRenderCost(objectsFront) * EvalRenderCost(objectsBack);
665
666        const float ratio = newRenderCost / oldRenderCost;
667        return ratio;
668}
669
670#else
671
672/// compute object partition by getting balanced objects on the left and right side
673float BvHierarchy::EvalLocalObjectPartition(const BvhTraversalData &tData,
674                                                                                        const int axis,
675                                                                                        ObjectContainer &objectsFront,
676                                                                                        ObjectContainer &objectsBack)
677{
678        PrepareLocalSubdivisionCandidates(tData, axis);
679       
680        SortableEntryContainer::const_iterator cit, cit_end = mSubdivisionCandidates->end();
681
682        int i = 0;
683        const int border = (int)tData.mNode->mObjects.size() / 2;
684
685    for (cit = mSubdivisionCandidates->begin(); cit != cit_end; ++ cit, ++ i)
686        {
687                Intersectable *obj = (*cit).mObject;
688
689                // object mailed => belongs to back objects
690                if (i < border)
691                {
692                        objectsBack.push_back(obj);
693                }
694                else
695                {
696                        objectsFront.push_back(obj);
697                }
698        }
699
700        const float oldRenderCost = EvalRenderCost(tData.mNode->mObjects);
701        const float newRenderCost = EvalRenderCost(objectsFront) + EvalRenderCost(objectsBack);
702
703        const float ratio = newRenderCost / oldRenderCost;
704        return ratio;
705}
706#endif
707
708
709float BvHierarchy::EvalSah(const BvhTraversalData &tData,
710                                                   const int axis,
711                                                   ObjectContainer &objectsFront,
712                                                   ObjectContainer &objectsBack)
713{
714        // go through the lists, count the number of objects left and right
715        // and evaluate the following cost funcion:
716        // C = ct_div_ci  + (ol + or)/queries
717        PrepareLocalSubdivisionCandidates(tData, axis);
718
719        int objectsLeft = 0, objectsRight = (int)tData.mNode->mObjects.size();
720 
721        AxisAlignedBox3 box = tData.mNode->GetBoundingBox();
722
723        float minBox = box.Min(axis);
724        float maxBox = box.Max(axis);
725        float boxArea = box.SurfaceArea();
726
727        float minSum = 1e20f;
728 
729        float minBorder = maxBox;
730        float maxBorder = minBox;
731        float areaLeft = 0, areaRight = 0;
732
733        SortableEntryContainer::const_iterator currentPos =
734                mSubdivisionCandidates->begin();
735
736       
737        // we keep track of both borders of the bounding boxes =>
738        // store the events in descending order
739        vector<float> bordersRight;
740        bordersRight.resize(mSubdivisionCandidates->size());
741
742        SortableEntryContainer::reverse_iterator rcit =
743                mSubdivisionCandidates->rbegin(), rcit_end = mSubdivisionCandidates->rend();
744       
745        vector<float>::reverse_iterator rbit = bordersRight.rbegin();
746       
747        for (; rcit != rcit_end; ++ rcit, ++ rbit)
748        {
749                Intersectable *obj = (*rcit).mObject;
750                const AxisAlignedBox3 box = obj->GetBox();
751
752                if (box.Min(axis) < minBorder)
753                {
754                        minBorder = box.Min(axis);
755                }
756
757                (*rbit) = minBorder;
758        }
759
760        vector<float>::const_iterator bit = bordersRight.begin();
761        SortableEntryContainer::const_iterator cit, cit_end = mSubdivisionCandidates->end();
762
763        for (cit = mSubdivisionCandidates->begin(); cit != cit_end; ++ cit, ++ bit)
764        {
765                Intersectable *obj = (*cit).mObject;
766
767                ++ objectsLeft;
768                -- objectsRight;
769
770                AxisAlignedBox3 lbox = box;
771                AxisAlignedBox3 rbox = box;
772       
773                const AxisAlignedBox3 obox = obj->GetBox();
774
775                // the borders of the bounding boxes have changed
776                if (obox.Max(axis) > maxBorder)
777                {
778                        maxBorder = obox.Max(axis);
779                }
780
781                minBorder = (*bit);
782       
783        lbox.SetMax(axis, maxBorder);
784                rbox.SetMin(axis, minBorder);
785       
786                const float al = lbox.SurfaceArea();
787                const float ar = rbox.SurfaceArea();
788
789                const float sum = objectsLeft * al + objectsRight * ar;
790     
791                /*cout << "pos=" << (*cit).mPos << "\t q=(" << objectsLeft << "," << objectsRight <<")\t r=("
792                         << lbox.SurfaceArea() << "," << rbox.SurfaceArea() << ")" << endl;
793                cout << "minborder: " << minBorder << " maxborder: " << maxBorder << endl;
794            cout << "cost= " << sum << endl;
795*/
796                if (sum < minSum)
797                {
798                        minSum = sum;
799                        areaLeft = al;
800                        areaRight = ar;
801                        // objects belong to left side now
802                        for (; currentPos != (cit + 1); ++ currentPos);
803                }
804        }
805
806
807        ////////////////////////////////////////////
808        //-- assign object to front and back volume
809
810        // belongs to back bv
811        for (cit = mSubdivisionCandidates->begin(); cit != currentPos; ++ cit)
812                objectsBack.push_back((*cit).mObject);
813       
814        // belongs to front bv
815        for (cit = currentPos; cit != cit_end; ++ cit)
816                objectsFront.push_back((*cit).mObject);
817
818        float oldCost = (float)tData.mNode->mObjects.size();
819        float newCost = minSum / boxArea;
820        float ratio = newCost / oldCost;
821 
822#ifdef _DEBUG
823        cout << "\n\nobjects=(" << (int)objectsBack.size() << "," << (int)objectsFront.size() << " of "
824                 << (int)tData.mNode->mObjects.size() << ")\t area=("
825                 << areaLeft << "," << areaRight << ")" << endl;
826        cout << "cost= " << minSum << endl;
827#endif
828  return ratio;
829}
830
831
832static bool PrepareOutput(const int axis,
833                                                  const int leaves,
834                                                  ofstream &sumStats,
835                                                  ofstream &vollStats,
836                                                  ofstream &volrStats)
837{
838        if ((axis == 0) && (leaves > 0) && (leaves < 90))
839        {
840                char str[64];   
841                sprintf(str, "tmp/bvh_heur_sum-%04d.log", leaves);
842                sumStats.open(str);
843                sprintf(str, "tmp/bvh_heur_voll-%04d.log", leaves);
844                vollStats.open(str);
845                sprintf(str, "tmp/bvh_heur_volr-%04d.log", leaves);
846                volrStats.open(str);
847        }
848
849        return sumStats.is_open() && vollStats.is_open() && volrStats.is_open();
850}
851
852
853static void PrintHeuristics(const int objectsRight,
854                                                        const float sum,
855                                                        const float volLeft,
856                                                        const float volRight,
857                                                        const float viewSpaceVol,
858                                                        ofstream &sumStats,
859                                                        ofstream &vollStats,
860                                                        ofstream &volrStats)
861{
862        sumStats
863                << "#Position\n" << objectsRight << endl
864                << "#Sum\n" << sum / viewSpaceVol << endl
865                << "#Vol\n" << (volLeft +  volRight) / viewSpaceVol << endl;
866
867        vollStats
868                << "#Position\n" << objectsRight << endl
869                << "#Vol\n" << volLeft / viewSpaceVol << endl;
870
871        volrStats
872                << "#Position\n" << objectsRight << endl
873                << "#Vol\n" << volRight / viewSpaceVol << endl;
874}
875
876
877float BvHierarchy::EvalLocalCostHeuristics(const BvhTraversalData &tData,
878                                                                                   const int axis,
879                                                                                   ObjectContainer &objectsFront,
880                                                                                   ObjectContainer &objectsBack)
881{
882        ////////////////////////////////////////////////////////////////
883        // go through the lists, count the number of objects left and right
884        // and evaluate the cost funcion
885
886        // prepare the heuristics by setting mailboxes and counters.
887        const float totalVol = PrepareHeuristics(tData, axis);
888       
889        // local helper variables
890        float volLeft = 0;
891        float volRight = totalVol;
892        int nObjectsLeft = 0;
893        const int nTotalObjects = (int)tData.mNode->mObjects.size();
894        const float viewSpaceVol = mHierarchyManager->GetViewSpaceBox().GetVolume();
895
896        SortableEntryContainer::const_iterator backObjectsStart = mSubdivisionCandidates->begin();
897
898        /////////////////////////////////
899        //-- the parameters for the current optimum
900
901        float volBack = volLeft;
902        float volFront = volRight;
903        float newRenderCost = nTotalObjects * totalVol;
904
905#ifdef _DEBUG
906        ofstream sumStats;
907        ofstream vollStats;
908        ofstream volrStats;
909
910        const bool printStats =
911                PrepareOutput(axis, mBvhStats.Leaves(), sumStats, vollStats, volrStats);
912#endif
913
914        ///////////////////////////////////////////////////
915        //-- the sweep heuristics
916        //-- traverse through events and find best split plane
917
918        SortableEntryContainer::const_iterator cit, cit_end = cit_end = mSubdivisionCandidates->end();
919
920        for (cit = mSubdivisionCandidates->begin(); cit != cit_end; ++ cit)
921        {
922                Intersectable *object = (*cit).mObject;
923       
924                // evaluate change in l and r volume
925                // voll = view cells that see only left node (i.e., left pvs)
926                // volr = view cells that see only right node (i.e., right pvs)
927                EvalHeuristicsContribution(object, volLeft, volRight);
928
929                ++ nObjectsLeft;
930                const int nObjectsRight = nTotalObjects - nObjectsLeft;
931
932                // the heuristics
933            const float sum = volLeft * (float)nObjectsLeft +
934                                                  volRight * (float)nObjectsRight;
935
936#ifdef _DEBUG
937                if (printStats)
938                {
939                        PrintHeuristics(nObjectsRight, sum, volLeft, volRight, viewSpaceVol,
940                                                        sumStats, vollStats, volrStats);
941                }
942#endif
943
944                if (sum < newRenderCost)
945                {
946                        newRenderCost = sum;
947
948                        volBack = volLeft;
949                        volFront = volRight;
950
951                        // objects belongs to left side now
952                        for (; backObjectsStart != (cit + 1); ++ backObjectsStart);
953                }
954        }
955
956        ////////////////////////////////////////////
957        //-- assign object to front and back volume
958
959        // belongs to back bv
960        for (cit = mSubdivisionCandidates->begin(); cit != backObjectsStart; ++ cit)
961        {
962                objectsBack.push_back((*cit).mObject);
963        }
964        // belongs to front bv
965        for (cit = backObjectsStart; cit != cit_end; ++ cit)
966        {
967                objectsFront.push_back((*cit).mObject);
968        }
969
970        // render cost of the old parent
971        const float oldRenderCost = (float)nTotalObjects * totalVol + Limits::Small;
972        // the relative cost ratio
973        const float ratio = newRenderCost / oldRenderCost;
974
975#ifdef _DEBUG
976        Debug << "\n§§§§ eval local cost §§§§" << endl
977                  << "back pvs: " << (int)objectsBack.size() << " front pvs: " << (int)objectsFront.size() << " total pvs: " << nTotalObjects << endl
978                  << "back p: " << volBack / viewSpaceVol << " front p " << volFront / viewSpaceVol << " p: " << totalVol / viewSpaceVol << endl
979                  << "old rc: " << oldRenderCost / viewSpaceVol << " new rc: " << newRenderCost / viewSpaceVol << endl
980                  << "render cost decrease: " << oldRenderCost / viewSpaceVol - newRenderCost / viewSpaceVol << endl;
981#endif
982
983        return ratio;
984}
985
986
987void BvHierarchy::PrepareLocalSubdivisionCandidates(const BvhTraversalData &tData,
988                                                                                                        const int axis)                                                                                 
989{
990        //-- insert object queries
991        ObjectContainer *objects = mUseGlobalSorting ? tData.mSortedObjects[axis] : &tData.mNode->mObjects;
992
993        CreateLocalSubdivisionCandidates(*objects, &mSubdivisionCandidates, !mUseGlobalSorting, axis);
994}
995
996
997void BvHierarchy::CreateLocalSubdivisionCandidates(const ObjectContainer &objects,
998                                                                                                  SortableEntryContainer **subdivisionCandidates,
999                                                                                                  const bool sort,
1000                                                                                                  const int axis)
1001{
1002        (*subdivisionCandidates)->clear();
1003
1004        // compute requested size and look if subdivision candidate has to be recomputed
1005        const int requestedSize = (int)objects.size() * 2;
1006       
1007        // creates a sorted split candidates array
1008        if ((*subdivisionCandidates)->capacity() > 500000 &&
1009                requestedSize < (int)((*subdivisionCandidates)->capacity() / 10) )
1010        {
1011        delete (*subdivisionCandidates);
1012                (*subdivisionCandidates) = new SortableEntryContainer;
1013        }
1014
1015        (*subdivisionCandidates)->reserve(requestedSize);
1016
1017        ObjectContainer::const_iterator oit, oit_end = objects.end();
1018
1019        for (oit = objects.begin(); oit < oit_end; ++ oit)
1020        {
1021                Intersectable *object = *oit;
1022                const AxisAlignedBox3 &box = object->GetBox();
1023                const float midPt = (box.Min(axis) + box.Max(axis)) * 0.5f;
1024
1025                (*subdivisionCandidates)->push_back(SortableEntry(object, midPt));
1026        }
1027
1028        if (sort)
1029        {
1030                stable_sort((*subdivisionCandidates)->begin(), (*subdivisionCandidates)->end());
1031        }
1032}
1033
1034
1035const BvhStatistics &BvHierarchy::GetStatistics() const
1036{
1037        return mBvhStats;
1038}
1039
1040
1041float BvHierarchy::PrepareHeuristics(const BvhTraversalData &tData, const int axis)
1042{       
1043        BvhLeaf *leaf = tData.mNode;
1044        float vol = 0;
1045
1046    // sort so we can use a sweep from right to left
1047        PrepareLocalSubdivisionCandidates(tData, axis);
1048       
1049        // collect and mark the view cells as belonging to front pvs
1050        ViewCellContainer viewCells;
1051        CollectViewCells(tData.mNode->mObjects, viewCells, true);
1052                       
1053        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
1054        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
1055        {
1056                vol += (*vit)->GetVolume();
1057        }
1058
1059        // we will mail view cells switching to the back side
1060        ViewCell::NewMail();
1061       
1062        return vol;
1063}
1064///////////////////////////////////////////////////////////
1065
1066
1067void BvHierarchy::EvalHeuristicsContribution(Intersectable *obj,
1068                                                                                         float &volLeft,
1069                                                                                         float &volRight)
1070{
1071        // collect all view cells associated with this objects
1072        // (also multiple times, if they are pierced by several rays)
1073        ViewCellContainer viewCells;
1074        const bool useMailboxing = false;
1075
1076        CollectViewCells(obj, viewCells, useMailboxing);
1077
1078        // classify view cells and compute volume contri accordingly
1079        // possible view cell classifications:
1080        // view cell mailed => view cell can be seen from left child node
1081        // view cell counter > 0 view cell can be seen from right child node
1082        // combined: view cell volume belongs to both nodes
1083        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
1084       
1085        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
1086        {
1087                // view cells can also be seen from left child node
1088                ViewCell *viewCell = *vit;
1089
1090                const float vol = viewCell->GetVolume();
1091
1092                if (!viewCell->Mailed())
1093                {
1094                        viewCell->Mail();
1095                        // we now see view cell from both nodes
1096                        // => add volume to left node
1097                        volLeft += vol;
1098                }
1099
1100                // last reference into the right node
1101                if (-- viewCell->mCounter == 0)
1102                {       
1103                        // view cell was previously seen from both nodes  =>
1104                        // remove volume from right node
1105                        volRight -= vol;
1106                }
1107        }
1108}
1109
1110
1111void BvHierarchy::SetViewCellsManager(ViewCellsManager *vcm)
1112{
1113        mViewCellsManager = vcm;
1114}
1115
1116
1117AxisAlignedBox3 BvHierarchy::GetBoundingBox() const
1118{
1119        return mBoundingBox;
1120}
1121
1122
1123float BvHierarchy::SelectObjectPartition(const BvhTraversalData &tData,
1124                                                                                 ObjectContainer &frontObjects,
1125                                                                                 ObjectContainer &backObjects)
1126{
1127        ObjectContainer nFrontObjects[3];
1128        ObjectContainer nBackObjects[3];
1129        float nCostRatio[3];
1130
1131        int sAxis = 0;
1132        int bestAxis = -1;
1133
1134        if (mOnlyDrivingAxis)
1135        {
1136                const AxisAlignedBox3 box = tData.mNode->GetBoundingBox();
1137                sAxis = box.Size().DrivingAxis();
1138        }
1139       
1140        ////////////////////////////////////////////
1141        //-- evaluate split cost for all three axis
1142       
1143        for (int axis = 0; axis < 3; ++ axis)
1144        {
1145                if (!mOnlyDrivingAxis || (axis == sAxis))
1146                {
1147                        if (mUseCostHeuristics)
1148                        {
1149                                //////////////////////////////////
1150                //-- split objects using heuristics
1151                               
1152                                if (mHierarchyManager->GetViewSpaceSubdivisionType() ==
1153                                        HierarchyManager::KD_BASED_VIEWSPACE_SUBDIV)
1154                                {
1155                                        //-- heuristics using objects weighted by view cells volume
1156                                        nCostRatio[axis] =
1157                                                EvalLocalCostHeuristics(
1158                                                                                                tData,
1159                                                                                                axis,
1160                                                                                                nFrontObjects[axis],
1161                                                                                                nBackObjects[axis]);
1162                                }
1163                                else
1164                                {
1165                                        //-- use surface area heuristic because view cells not constructed yet                         
1166                                        nCostRatio[axis] =
1167                                                EvalSah(
1168                                                                tData,
1169                                                                axis,
1170                                                                nFrontObjects[axis],
1171                                                                nBackObjects[axis]);
1172                                }
1173                        }
1174                        else
1175                        {
1176                                //-- split objects using some simple criteria
1177                                nCostRatio[axis] =
1178                                        EvalLocalObjectPartition(
1179                                                                                         tData,
1180                                                                                         axis,
1181                                                                                         nFrontObjects[axis],
1182                                                                                         nBackObjects[axis]);
1183                        }
1184
1185                        if (bestAxis == -1)
1186                        {
1187                                bestAxis = axis;
1188                        }
1189                        else if (nCostRatio[axis] < nCostRatio[bestAxis])
1190                        {
1191                                bestAxis = axis;
1192                        }
1193                }
1194        }
1195
1196        /////////////////////////////////////
1197        //-- assign values
1198
1199        frontObjects = nFrontObjects[bestAxis];
1200        backObjects = nBackObjects[bestAxis];
1201
1202        //Debug << "val: " << nCostRatio[bestAxis] << " axis: " << bestAxis << endl;
1203        return nCostRatio[bestAxis];
1204}
1205
1206
1207int BvHierarchy::AssociateObjectsWithRays(const VssRayContainer &rays) const
1208{
1209        int nRays = 0;
1210        VssRayContainer::const_iterator rit, rit_end = rays.end();
1211
1212        VssRay::NewMail();
1213
1214    for (rit = rays.begin(); rit != rays.end(); ++ rit)
1215        {
1216                VssRay *ray = (*rit);
1217
1218                if (ray->mTerminationObject)
1219                {
1220                        ray->mTerminationObject->mVssRays.push_back(ray);
1221                        if (!ray->Mailed())
1222                        {
1223                                ray->Mail();
1224                                ++ nRays;
1225                        }
1226                }
1227
1228                if (1 && ray->mOriginObject)
1229                {
1230                        ray->mOriginObject->mVssRays.push_back(ray);
1231
1232                        if (!ray->Mailed())
1233                        {
1234                                ray->Mail();
1235                                ++ nRays;
1236                        }
1237                }
1238        }
1239
1240        return nRays;
1241}
1242
1243
1244void BvHierarchy::PrintSubdivisionStats(const SubdivisionCandidate &sc)
1245{
1246        const float costDecr =
1247                sc.GetRenderCostDecrease();// / mHierarchyManager->GetViewSpaceBox().GetVolume();       
1248
1249        mSubdivisionStats
1250                        << "#Leaves\n" << mBvhStats.Leaves() << endl
1251                        << "#RenderCostDecrease\n" << costDecr << endl
1252                        << "#TotalRenderCost\n" << mTotalCost << endl;
1253}
1254
1255
1256void BvHierarchy::CollectRays(const ObjectContainer &objects,
1257                                                          VssRayContainer &rays) const
1258{
1259        VssRay::NewMail();
1260        ObjectContainer::const_iterator oit, oit_end = objects.end();
1261
1262        // evaluate reverse pvs and view cell volume on left and right cell
1263        // note: should I take all leaf objects or rather the objects hit by rays?
1264        for (oit = objects.begin(); oit != oit_end; ++ oit)
1265        {
1266                Intersectable *obj = *oit;
1267                VssRayContainer::const_iterator rit, rit_end = obj->mVssRays.end();
1268
1269                for (rit = obj->mVssRays.begin(); rit < rit_end; ++ rit)
1270                {
1271                        VssRay *ray = (*rit);
1272
1273                        if (!ray->Mailed())
1274                        {
1275                                ray->Mail();
1276                                rays.push_back(ray);
1277                        }
1278                }
1279        }
1280}
1281
1282
1283float BvHierarchy::EvalRenderCost(const ObjectContainer &objects) const
1284{
1285        if (mHierarchyManager->GetViewSpaceSubdivisionType() == HierarchyManager::NO_VIEWSPACE_SUBDIV)
1286        {
1287                if (objects.empty())
1288                        return 0.0f;
1289
1290                ////////////////////
1291                //-- surface area heuristics
1292
1293                const AxisAlignedBox3 box = EvalBoundingBox(objects);
1294                const float area = box.SurfaceArea();
1295
1296                return (float)objects.size() * area / mHierarchyManager->GetViewSpaceBox().SurfaceArea();
1297        }
1298        else
1299        {       ////////////////////
1300                //-- render cost heuristics
1301
1302                const float viewSpaceVol = mHierarchyManager->GetViewSpaceBox().GetVolume();
1303                // probability that view point lies in a view cell which sees this node
1304                const float p = EvalViewCellsVolume(objects) / viewSpaceVol;   
1305
1306                return (float)objects.size() * p;
1307        }
1308}
1309
1310
1311AxisAlignedBox3 BvHierarchy::EvalBoundingBox(const ObjectContainer &objects,
1312                                                                                         const AxisAlignedBox3 *parentBox) const
1313{
1314        // if there are no objects in this box, box size is set to parent box size.
1315        // Question: Invalidate box instead?
1316        if (parentBox && objects.empty())
1317                return *parentBox;
1318
1319        AxisAlignedBox3 box;
1320        box.Initialize();
1321
1322        ObjectContainer::const_iterator oit, oit_end = objects.end();
1323
1324        for (oit = objects.begin(); oit != oit_end; ++ oit)
1325        {
1326                Intersectable *obj = *oit;
1327                // grow bounding box to include all objects
1328                box.Include(obj->GetBox());
1329        }
1330
1331        return box;
1332}
1333
1334
1335void BvHierarchy::CollectLeaves(vector<BvhLeaf *> &leaves) const
1336{
1337        stack<BvhNode *> nodeStack;
1338        nodeStack.push(mRoot);
1339
1340        while (!nodeStack.empty())
1341        {
1342                BvhNode *node = nodeStack.top();
1343                nodeStack.pop();
1344
1345                if (node->IsLeaf())
1346                {
1347                        BvhLeaf *leaf = (BvhLeaf *)node;
1348                        leaves.push_back(leaf);
1349                }
1350                else
1351                {
1352                        BvhInterior *interior = (BvhInterior *)node;
1353
1354                        nodeStack.push(interior->GetBack());
1355                        nodeStack.push(interior->GetFront());
1356                }
1357        }
1358}
1359
1360
1361AxisAlignedBox3 BvHierarchy::GetBoundingBox(BvhNode *node) const
1362{
1363        return node->GetBoundingBox();
1364}
1365
1366
1367void BvHierarchy::CollectViewCells(const ObjectContainer &objects,
1368                                                                   ViewCellContainer &viewCells,
1369                                                                   const bool setCounter) const
1370{
1371        // no view cells yet
1372        if (mHierarchyManager->GetViewSpaceSubdivisionType() ==
1373                HierarchyManager::NO_VIEWSPACE_SUBDIV)
1374                return;
1375
1376        ViewCell::NewMail();
1377        ObjectContainer::const_iterator oit, oit_end = objects.end();
1378
1379        // loop through all object and collect view cell pvs of this node
1380        for (oit = objects.begin(); oit != oit_end; ++ oit)
1381        {
1382                CollectViewCells(*oit, viewCells, true, setCounter);
1383        }
1384}
1385
1386
1387void BvHierarchy::CollectViewCells(Intersectable *obj,
1388                                                                   ViewCellContainer &viewCells,
1389                                                                   const bool useMailBoxing,
1390                                                                   const bool setCounter) const
1391{
1392        VssRayContainer::const_iterator rit, rit_end = obj->mVssRays.end();
1393
1394        for (rit = obj->mVssRays.begin(); rit < rit_end; ++ rit)
1395        {
1396                VssRay *ray = (*rit);
1397                ViewCellContainer tmpViewCells;
1398       
1399                mHierarchyManager->mVspTree->GetViewCells(*ray, tmpViewCells);
1400
1401                ViewCellContainer::const_iterator vit, vit_end = tmpViewCells.end();
1402
1403                for (vit = tmpViewCells.begin(); vit != vit_end; ++ vit)
1404                {
1405                        VspViewCell *vc = dynamic_cast<VspViewCell *>(*vit);
1406
1407                        // store view cells
1408                        if (!useMailBoxing || !vc->Mailed())
1409                        {
1410                                if (useMailBoxing)
1411                                {
1412                                        vc->Mail();
1413                                        if (setCounter)
1414                                        {
1415                                                vc->mCounter = 0;
1416                                        }
1417                                }
1418                                viewCells.push_back(vc);
1419                        }
1420                       
1421                        if (setCounter)
1422                        {
1423                                ++ vc->mCounter;
1424                        }
1425                }
1426        }
1427}
1428
1429
1430void BvHierarchy::CollectDirtyCandidates(BvhSubdivisionCandidate *sc,
1431                                                                                 vector<SubdivisionCandidate *> &dirtyList)
1432{
1433        BvhTraversalData &tData = sc->mParentData;
1434        BvhLeaf *node = tData.mNode;
1435       
1436        ViewCellContainer viewCells;
1437        CollectViewCells(node->mObjects, viewCells);
1438        if (0) cout << "collected " << (int)viewCells.size() << " dirty candidates" << endl;
1439
1440        // split candidates handling
1441        // these view cells  are thrown into dirty list
1442        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
1443
1444        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
1445        {
1446                VspViewCell *vc = dynamic_cast<VspViewCell *>(*vit);
1447                VspLeaf *leaf = vc->mLeaf;
1448                SubdivisionCandidate *candidate = leaf->GetSubdivisionCandidate();
1449               
1450                if (candidate) // is this leaf still a split candidate?
1451                {
1452                        dirtyList.push_back(candidate);
1453                }
1454        }
1455}
1456
1457
1458BvhNode *BvHierarchy::GetRoot() const
1459{
1460        return mRoot;
1461}
1462
1463
1464bool BvHierarchy::IsObjectInLeaf(BvhLeaf *leaf, Intersectable *object) const
1465{
1466        ObjectContainer::const_iterator oit =
1467                lower_bound(leaf->mObjects.begin(), leaf->mObjects.end(), object, ilt);
1468                               
1469        // objects sorted by id
1470        if ((oit != leaf->mObjects.end()) && ((*oit)->GetId() == object->GetId()))
1471        {
1472                return true;
1473        }
1474        else
1475        {
1476                return false;
1477        }
1478}
1479
1480
1481BvhLeaf *BvHierarchy::GetLeaf(Intersectable *object, BvhNode *node) const
1482{
1483        // rather use the simple version
1484        if (!object) return NULL;
1485        return object->mBvhLeaf;
1486       
1487        ///////////////////////////////////////
1488        // start from root of tree
1489       
1490        if (node == NULL)
1491                node = mRoot;
1492       
1493        vector<BvhLeaf *> leaves;
1494
1495        stack<BvhNode *> nodeStack;
1496        nodeStack.push(node);
1497 
1498        BvhLeaf *leaf = NULL;
1499 
1500        while (!nodeStack.empty()) 
1501        {
1502                BvhNode *node = nodeStack.top();
1503                nodeStack.pop();
1504       
1505                if (node->IsLeaf())
1506                {
1507                        leaf = dynamic_cast<BvhLeaf *>(node);
1508
1509                        if (IsObjectInLeaf(leaf, object))
1510                        {
1511                                return leaf;
1512                        }
1513                }
1514                else   
1515                {       
1516                        // find point
1517                        BvhInterior *interior = dynamic_cast<BvhInterior *>(node);
1518       
1519                        if (interior->GetBack()->GetBoundingBox().Includes(object->GetBox()))
1520                        {
1521                                nodeStack.push(interior->GetBack());
1522                        }
1523                       
1524                        // search both sides as we are using bounding volumes
1525                        if (interior->GetFront()->GetBoundingBox().Includes(object->GetBox()))
1526                        {
1527                                nodeStack.push(interior->GetFront());
1528                        }
1529                }
1530        }
1531 
1532        return leaf;
1533}
1534
1535
1536BvhIntersectable *BvHierarchy::GetOrCreateBvhIntersectable(BvhNode *node)
1537{
1538        // search nodes
1539        std::map<BvhNode *, BvhIntersectable *>::const_iterator it
1540                = mBvhIntersectables.find(node);
1541
1542        if (it != mBvhIntersectables.end())
1543        {
1544                return (*it).second;
1545        }
1546
1547        // not in map => create new entry
1548        BvhIntersectable *bvhObj = new BvhIntersectable(node);
1549        mBvhIntersectables[node] = bvhObj;
1550
1551        return bvhObj;
1552}
1553
1554
1555bool BvHierarchy::Export(OUT_STREAM &stream)
1556{
1557        ExportNode(mRoot, stream);
1558
1559        return true;
1560}
1561
1562
1563void BvHierarchy::ExportObjects(BvhLeaf *leaf, OUT_STREAM &stream)
1564{
1565        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
1566        for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
1567        {
1568                stream << (*oit)->GetId() << " ";
1569        }
1570}
1571
1572
1573void BvHierarchy::ExportNode(BvhNode *node, OUT_STREAM &stream)
1574{
1575        if (node->IsLeaf())
1576        {
1577                BvhLeaf *leaf = dynamic_cast<BvhLeaf *>(node);
1578                const AxisAlignedBox3 box = leaf->GetBoundingBox();
1579                stream << "<Leaf"
1580                           << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
1581                           << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\""
1582                           << " objects=\"";
1583               
1584                //-- export objects
1585                ExportObjects(leaf, stream);
1586               
1587                stream << "\" />" << endl;
1588        }
1589        else
1590        {       
1591                BvhInterior *interior = dynamic_cast<BvhInterior *>(node);
1592                const AxisAlignedBox3 box = interior->GetBoundingBox();
1593
1594                stream << "<Interior"
1595                           << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
1596                           << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z
1597                           << "\">" << endl;
1598
1599                ExportNode(interior->GetBack(), stream);
1600                ExportNode(interior->GetFront(), stream);
1601
1602                stream << "</Interior>" << endl;
1603        }
1604}
1605
1606
1607float BvHierarchy::EvalViewCellsVolume(const ObjectContainer &objects) const
1608{
1609        float vol = 0;
1610
1611        ViewCellContainer viewCells;
1612        CollectViewCells(objects, viewCells);
1613
1614        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
1615
1616        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
1617        {
1618                vol += (*vit)->GetVolume();
1619        }
1620
1621        return vol;
1622}
1623
1624
1625void BvHierarchy::CreateRoot(const ObjectContainer &objects)
1626{
1627        ///////
1628        //-- create new root
1629
1630        AxisAlignedBox3 box = EvalBoundingBox(objects);
1631        BvhLeaf *bvhleaf = new BvhLeaf(box, NULL, (int)objects.size());
1632        bvhleaf->mObjects = objects;
1633        mRoot = bvhleaf;
1634
1635        // associate root with current objects
1636        AssociateObjectsWithLeaf(bvhleaf);
1637}
1638
1639/*
1640Mesh *BvHierarchy::MergeLeafToMesh()
1641void BvHierarchy::MergeLeavesToMeshes()
1642{
1643        vector<BvhLeaf *> leaves;
1644        CollectLeaves(leaves);
1645
1646        vector<BvhLeaf *>::const_iterator lit, lit_end = leaves.end();
1647
1648        for (lit = leaves.begin(); lit != lit_end; ++ lit)
1649        {
1650                Mesh *mesh = MergeLeafToMesh(*lit);
1651        }
1652}*/
1653
1654
1655SubdivisionCandidate *BvHierarchy::PrepareConstruction(const VssRayContainer &sampleRays,
1656                                                                                                           const ObjectContainer &objects)
1657{
1658        ///////////////////////////////////////////////////////////////
1659        //-- note matt: we assume that we have objects sorted by their id =>
1660        //-- we don't have to sort them here and an binary search
1661        //-- for identifying if a object is in a leaf.
1662       
1663        mBvhStats.Reset();
1664        mBvhStats.Start();
1665
1666        mBvhStats.nodes = 1;
1667       
1668       
1669        // store pointer to this tree
1670        BvhSubdivisionCandidate::sBvHierarchy = this;
1671       
1672        // compute bounding box from objects
1673        // note: we assume that root was already created
1674        mBoundingBox = mRoot->GetBoundingBox();
1675        BvhLeaf *bvhleaf = dynamic_cast<BvhLeaf *>(mRoot);
1676
1677        // multiply termination criterium for comparison,
1678        // so it can be set between zero and one and
1679        // no division is necessary during traversal
1680
1681#if PROBABILIY_IS_BV_VOLUME
1682        mTermMinProbability *= mBoundingBox.GetVolume();
1683        // probability that bounding volume is seen
1684        const float prop = GetBoundingBox().GetVolume();
1685#else
1686        mTermMinProbability *= mVspTree->GetBoundingBox().GetVolume();
1687        // probability that volume is "seen" from the view cells
1688        const float prop = EvalViewCellsVolume(objects);
1689#endif
1690
1691        // only rays intersecting objects in node are interesting
1692        const int nRays = AssociateObjectsWithRays(sampleRays);
1693        //Debug << "using " << nRays << " of " << (int)sampleRays.size() << " rays" << endl;
1694
1695        // create bvh traversal data
1696        BvhTraversalData oData(bvhleaf, 0, prop, nRays);
1697
1698        // create sorted object lists for the first data
1699        if (mUseGlobalSorting)
1700        {
1701                CreateInitialSortedObjectList(oData);
1702        }
1703       
1704
1705        ///////////////////
1706        //-- add first candidate for object space partition     
1707
1708        BvhSubdivisionCandidate *oSubdivisionCandidate =
1709                new BvhSubdivisionCandidate(oData);
1710
1711        EvalSubdivisionCandidate(*oSubdivisionCandidate);
1712        bvhleaf->SetSubdivisionCandidate(oSubdivisionCandidate);
1713
1714        const float viewSpaceVol = mHierarchyManager->GetViewSpaceBox().GetVolume();
1715        mTotalCost = (float)objects.size() * prop / viewSpaceVol;
1716
1717        PrintSubdivisionStats(*oSubdivisionCandidate);
1718
1719        return oSubdivisionCandidate;
1720}
1721
1722
1723void BvHierarchy::CreateInitialSortedObjectList(BvhTraversalData &tData)
1724{
1725        SortableEntryContainer *sortedObjects = new SortableEntryContainer();
1726
1727        // we sort the objects as a preprocess so they don't have
1728        // to be sorted for each split
1729        for (int i = 0; i < 3; ++ i)
1730        {
1731                CreateLocalSubdivisionCandidates(tData.mNode->mObjects, &sortedObjects, true, i);
1732                       
1733                tData.mSortedObjects[i] = new ObjectContainer();
1734                tData.mSortedObjects[i]->reserve((int)sortedObjects->size());
1735
1736                SortableEntryContainer::const_iterator oit, oit_end = sortedObjects->end();
1737                for (oit = sortedObjects->begin(); oit != oit_end; ++ oit)
1738                {
1739                        tData.mSortedObjects[i]->push_back((*oit).mObject);
1740                }
1741        }
1742
1743        delete sortedObjects;
1744}
1745
1746
1747void BvHierarchy::AssignSortedObjects(const BvhSubdivisionCandidate &sc,
1748                                                                          BvhTraversalData &frontData,
1749                                                                          BvhTraversalData &backData)
1750{
1751        Intersectable::NewMail();
1752
1753        // we sorted the objects as a preprocess so they don't have
1754        // to be sorted for each split
1755        ObjectContainer::const_iterator fit, fit_end = sc.mFrontObjects.end();
1756
1757        for (fit = sc.mFrontObjects.begin(); fit != fit_end; ++ fit)
1758        {
1759                (*fit)->Mail();
1760        }
1761
1762        for (int i = 0; i < 3; ++ i)
1763        {
1764                frontData.mSortedObjects[i] = new ObjectContainer();
1765                backData.mSortedObjects[i] = new ObjectContainer();
1766
1767                frontData.mSortedObjects[i]->reserve((int)sc.mFrontObjects.size());
1768                backData.mSortedObjects[i]->reserve((int)sc.mFrontObjects.size());
1769
1770                ObjectContainer::const_iterator oit, oit_end = sc.mParentData.mSortedObjects[i]->end();
1771
1772                for (oit = sc.mParentData.mSortedObjects[i]->begin(); oit != oit_end; ++ oit)
1773                {
1774                        if ((*oit)->Mailed())
1775                        {
1776                                frontData.mSortedObjects[i]->push_back(*oit);
1777                        }
1778                        else
1779                        {
1780                                backData.mSortedObjects[i]->push_back(*oit);
1781                        }
1782                }
1783        }
1784}
1785
1786
1787void BvhStatistics::Print(ostream &app) const
1788{
1789        app << "=========== BvHierarchy statistics ===============\n";
1790
1791        app << setprecision(4);
1792
1793        app << "#N_CTIME  ( Construction time [s] )\n" << Time() << " \n";
1794
1795        app << "#N_NODES ( Number of nodes )\n" << nodes << "\n";
1796
1797        app << "#N_INTERIORS ( Number of interior nodes )\n" << Interior() << "\n";
1798
1799        app << "#N_LEAVES ( Number of leaves )\n" << Leaves() << "\n";
1800
1801        app << "#AXIS_ALIGNED_SPLITS (number of axis aligned splits)\n" << splits << endl;
1802
1803        app << "#N_MAXCOSTNODES  ( Percentage of leaves with terminated because of max cost ratio )\n"
1804                << maxCostNodes * 100 / (double)Leaves() << endl;
1805
1806        app << "#N_PMINPROBABILITYLEAVES  ( Percentage of leaves with mininum probability )\n"
1807                << minProbabilityNodes * 100 / (double)Leaves() << endl;
1808
1809
1810        //////////////////////////////////////////////////
1811       
1812        app << "#N_PMAXDEPTHLEAVES ( Percentage of leaves at maximum depth )\n"
1813                <<      maxDepthNodes * 100 / (double)Leaves() << endl;
1814       
1815        app << "#N_PMAXDEPTH ( Maximal reached depth )\n" << maxDepth << endl;
1816
1817        app << "#N_PMINDEPTH ( Minimal reached depth )\n" << minDepth << endl;
1818
1819        app << "#AVGDEPTH ( average depth )\n" << AvgDepth() << endl;
1820
1821       
1822        ////////////////////////////////////////////////////////
1823       
1824        app << "#N_PMINOBJECTSLEAVES  ( Percentage of leaves with mininum objects )\n"
1825                << minObjectsNodes * 100 / (double)Leaves() << endl;
1826
1827        app << "#N_MAXOBJECTREFS  ( Max number of object refs / leaf )\n" << maxObjectRefs << "\n";
1828
1829        app << "#N_MINOBJECTREFS  ( Min number of object refs / leaf )\n" << minObjectRefs << "\n";
1830
1831        app << "#N_EMPTYLEAFS ( Empty leafs )\n" << emptyNodes << "\n";
1832       
1833        app << "#N_PAVGOBJECTSLEAVES  ( average object refs / leaf)\n" << AvgObjectRefs() << endl;
1834
1835
1836        ////////////////////////////////////////////////////////
1837       
1838        app << "#N_PMINRAYSLEAVES  ( Percentage of leaves with mininum rays )\n"
1839                << minRaysNodes * 100 / (double)Leaves() << endl;
1840
1841        app << "#N_MAXRAYREFS  ( Max number of ray refs / leaf )\n" << maxRayRefs << "\n";
1842
1843        app << "#N_MINRAYREFS  ( Min number of ray refs / leaf )\n" << minRayRefs << "\n";
1844       
1845        app << "#N_PAVGRAYLEAVES  ( average ray refs / leaf )\n" << AvgRayRefs() << endl;
1846       
1847        app << "#N_PAVGRAYCONTRIBLEAVES  ( Average ray contribution)\n" <<
1848                rayRefs / (double)objectRefs << endl;
1849
1850        app << "#N_PMAXRAYCONTRIBLEAVES  ( Percentage of leaves with maximal ray contribution )\n"<<
1851                maxRayContriNodes * 100 / (double)Leaves() << endl;
1852
1853        app << "#N_PGLOBALCOSTMISSES ( Global cost misses )\n" << mGlobalCostMisses << endl;
1854
1855        app << "========== END OF BvHierarchy statistics ==========\n";
1856}
1857
1858
1859}
Note: See TracBrowser for help on using the repository browser.