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

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