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

Revision 1640, 55.0 KB checked in by mattausch, 18 years ago (diff)

worked on vsp osp methodsd

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