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

Revision 1733, 65.7 KB checked in by mattausch, 18 years ago (diff)

removed bug from dirtycandidates

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