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

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