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

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