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

Revision 2575, 86.4 KB checked in by bittner, 17 years ago (diff)

big merge: preparation for havran ray caster, check if everything works

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