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

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