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

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