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

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