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

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