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

Revision 1696, 58.6 KB checked in by mattausch, 18 years ago (diff)

removed memory leaks

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