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

Revision 1666, 56.5 KB checked in by mattausch, 18 years ago (diff)

working on render cost evaluation framework for interleaved splits

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