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

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