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

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