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

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