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

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

worked on vsp osp methodsd

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