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

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