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

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