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

Revision 2560, 85.9 KB checked in by mattausch, 17 years ago (diff)

added functionality for visualization

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