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

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