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

Revision 1323, 41.5 KB checked in by mattausch, 18 years ago (diff)
RevLine 
[1237]1#include <stack>
2#include <time.h>
3#include <iomanip>
4
5#include "BvHierarchy.h"
6#include "ViewCell.h"
7#include "Plane3.h"
8#include "Mesh.h"
9#include "common.h"
10#include "Environment.h"
11#include "Polygon3.h"
12#include "Ray.h"
13#include "AxisAlignedBox3.h"
14#include "Exporter.h"
15#include "Plane3.h"
16#include "ViewCellsManager.h"
17#include "Beam.h"
18#include "VspTree.h"
19
20
21namespace GtpVisibilityPreprocessor {
22
23
24#define USE_FIXEDPOINT_T 0
25
26static float debugVol = 0;
[1291]27
[1297]28int BvhNode::sMailId = 10000;//2147483647;
[1291]29int BvhNode::sReservedMailboxes = 1;
30
[1237]31BvHierarchy *BvHierarchy::BvhSubdivisionCandidate::sBvHierarchy = NULL;
32
33
34inline static bool ilt(Intersectable *obj1, Intersectable *obj2)
35{
36        return obj1->mId < obj2->mId;
37}
38
39
40/***************************************************************/
41/*              class BvhNode implementation                   */
42/***************************************************************/
43
[1297]44BvhNode::BvhNode(): mParent(NULL), mMailbox(0)
[1237]45{
46}
47
48BvhNode::BvhNode(const AxisAlignedBox3 &bbox):
[1297]49mParent(NULL), mBoundingBox(bbox), mMailbox(0)
[1237]50{
51}
52
53
54BvhNode::BvhNode(const AxisAlignedBox3 &bbox, BvhInterior *parent):
[1297]55mBoundingBox(bbox), mParent(parent), mMailbox(0)
[1237]56{
57}
58
59
60bool BvhNode::IsRoot() const
61{
62        return mParent == NULL;
63}
64
65
66BvhInterior *BvhNode::GetParent()
67{
68        return mParent;
69}
70
71
72void BvhNode::SetParent(BvhInterior *parent)
73{
74        mParent = parent;
75}
76
77
78
79/******************************************************************/
80/*              class BvhInterior implementation                  */
81/******************************************************************/
82
83
84BvhLeaf::BvhLeaf(const AxisAlignedBox3 &bbox):
[1302]85BvhNode(bbox), mSubdivisionCandidate(NULL)
[1237]86{
87}
88
89
90BvhLeaf::BvhLeaf(const AxisAlignedBox3 &bbox, BvhInterior *parent):
91BvhNode(bbox, parent)
92{
93}
94
95
[1287]96BvhLeaf::BvhLeaf(const AxisAlignedBox3 &bbox,
97                                 BvhInterior *parent,
98                                 const int numObjects):
[1237]99BvhNode(bbox, parent)
100{
101        mObjects.reserve(numObjects);
102}
103
104
105bool BvhLeaf::IsLeaf() const
106{
107        return true;
108}
109
110
111BvhLeaf::~BvhLeaf()
112{
113}
114
115
116/******************************************************************/
117/*              class BvhInterior implementation                  */
118/******************************************************************/
119
120
121BvhInterior::BvhInterior(const AxisAlignedBox3 &bbox):
[1287]122BvhNode(bbox), mFront(NULL), mBack(NULL)
[1237]123{
124}
125
126
127BvhInterior::BvhInterior(const AxisAlignedBox3 &bbox, BvhInterior *parent):
[1287]128BvhNode(bbox, parent), mFront(NULL), mBack(NULL)
[1237]129{
130}
131
132
133void BvhInterior::ReplaceChildLink(BvhNode *oldChild, BvhNode *newChild)
134{
135        if (mBack == oldChild)
136                mBack = newChild;
137        else
138                mFront = newChild;
139}
140
141
142bool BvhInterior::IsLeaf() const
143{
144        return false;
145}
146
147
148BvhInterior::~BvhInterior()
149{
150        DEL_PTR(mFront);
151        DEL_PTR(mBack);
152}
153
154
155void BvhInterior::SetupChildLinks(BvhNode *front, BvhNode *back)
156{
157    mBack = back;
158    mFront = front;
159}
160
161
162
163/*******************************************************************/
164/*                  class BvHierarchy implementation               */
165/*******************************************************************/
166
167
168BvHierarchy::BvHierarchy():
169mRoot(NULL),
170mTimeStamp(1)
171{
172        ReadEnvironment();
173        mSubdivisionCandidates = new vector<SortableEntry>;
174}
175
176
177BvHierarchy::~BvHierarchy()
178{
179        // delete kd intersectables
180        BvhIntersectableMap::iterator it, it_end = mBvhIntersectables.end();
181
182        for (it = mBvhIntersectables.begin(); it != mBvhIntersectables.end(); ++ it)
183        {
184                DEL_PTR((*it).second);
185        }
186
187        DEL_PTR(mSubdivisionCandidates);
188
189        mSubdivisionStats.close();
190}
191
192
193void BvHierarchy::ReadEnvironment()
194{
195        bool randomize = false;
196        Environment::GetSingleton()->GetBoolValue("VspTree.Construction.randomize", randomize);
197        if (randomize)
198                Randomize(); // initialise random generator for heuristics
199
200        //-- termination criteria for autopartition
[1288]201        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.maxDepth", mTermMaxDepth);
202        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.maxLeaves", mTermMaxLeaves);
203        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.minObjects", mTermMinObjects);
204        Environment::GetSingleton()->GetFloatValue("BvHierarchy.Termination.minProbability", mTermMinProbability);
[1237]205       
[1288]206        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.missTolerance", mTermMissTolerance);
[1237]207       
208        //-- max cost ratio for early tree termination
[1288]209        Environment::GetSingleton()->GetFloatValue("BvHierarchy.Termination.maxCostRatio", mTermMaxCostRatio);
[1237]210
[1288]211        Environment::GetSingleton()->GetFloatValue("BvHierarchy.Termination.minGlobalCostRatio",
[1237]212                mTermMinGlobalCostRatio);
[1294]213        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.globalCostMissTolerance",
214                mTermGlobalCostMissTolerance);
[1237]215
216        //-- factors for bsp tree split plane heuristics
217
218        // if only the driving axis is used for axis aligned split
[1288]219        Environment::GetSingleton()->GetBoolValue("BvHierarchy.splitUseOnlyDrivingAxis", mOnlyDrivingAxis);
220        Environment::GetSingleton()->GetFloatValue("BvHierarchy.maxStaticMemory", mMaxMemory);
221        Environment::GetSingleton()->GetBoolValue("BvHierarchy.useCostHeuristics", mUseCostHeuristics);
[1237]222
223        char subdivisionStatsLog[100];
[1288]224        Environment::GetSingleton()->GetStringValue("BvHierarchy.subdivisionStats", subdivisionStatsLog);
[1237]225        mSubdivisionStats.open(subdivisionStatsLog);
226
[1288]227        Environment::GetSingleton()->GetFloatValue(
228                "BvHierarchy.Construction.renderCostDecreaseWeight", mRenderCostDecreaseWeight);
[1237]229       
230
231        //-- debug output
232
233        Debug << "******* Bvh hierarchy options ******** " << endl;
234    Debug << "max depth: " << mTermMaxDepth << endl;
[1287]235        Debug << "min probabiliy: " << mTermMinProbability<< endl;
[1237]236        Debug << "min objects: " << mTermMinObjects << endl;
237        Debug << "max cost ratio: " << mTermMaxCostRatio << endl;
238        Debug << "miss tolerance: " << mTermMissTolerance << endl;
239        Debug << "max leaves: " << mTermMaxLeaves << endl;
240        Debug << "randomize: " << randomize << endl;
241        Debug << "min global cost ratio: " << mTermMinGlobalCostRatio << endl;
242        Debug << "global cost miss tolerance: " << mTermGlobalCostMissTolerance << endl;
243        Debug << "only driving axis: " << mOnlyDrivingAxis << endl;
244        Debug << "max memory: " << mMaxMemory << endl;
245        Debug << "use cost heuristics: " << mUseCostHeuristics << endl;
246        Debug << "subdivision stats log: " << subdivisionStatsLog << endl;
247       
248        Debug << "split borders: " << mSplitBorder << endl;
249        Debug << "render cost decrease weight: " << mRenderCostDecreaseWeight << endl;
250        Debug << endl;
251}
252
253
254void AssociateObjectsWithLeaf(BvhLeaf *leaf)
255{
256        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
257        for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
258        {
259                (*oit)->mBvhLeaf = leaf;
260        }
261}
262
263
264BvhInterior *BvHierarchy::SubdivideNode(const ObjectContainer &frontObjects,
265                                                                                const ObjectContainer &backObjects,
266                                                                                const BvhTraversalData &tData,
267                                                                                BvhTraversalData &frontData,
268                                                                                BvhTraversalData &backData)
269{
270        BvhLeaf *leaf = tData.mNode;
271       
272        // two new leaves
273    mBvhStats.nodes += 2;
274
275        // add the new nodes to the tree
276        BvhInterior *node = new BvhInterior(tData.mBoundingBox, leaf->GetParent());
[1294]277       
[1237]278
279        //-- the front and back traversal data is filled with the new values
280
281        frontData.mDepth = backData.mDepth = tData.mDepth + 1;
282
[1294]283        frontData.mBoundingBox = ComputeBoundingBox(frontObjects, &tData.mBoundingBox);
284        backData.mBoundingBox = ComputeBoundingBox(backObjects, &tData.mBoundingBox);
[1288]285       
[1237]286        /////////////
287        //-- create front and back leaf
288
[1287]289        BvhLeaf *back =
290                new BvhLeaf(backData.mBoundingBox, node, (int)backObjects.size());
291        BvhLeaf *front =
292                new BvhLeaf(frontData.mBoundingBox, node, (int)frontObjects.size());
[1237]293
294        BvhInterior *parent = leaf->GetParent();
295
296
297        // replace a link from node's parent
298        if (parent)
299        {
300                parent->ReplaceChildLink(leaf, node);
301                node->SetParent(parent);
302        }
303        else // new root
304        {
305                mRoot = node;
306        }
307
308        // and setup child links
309        node->SetupChildLinks(front, back);
310
311        ++ mBvhStats.splits;
312
313
314        ////////////////////////////////////
315
316        frontData.mNode = front;
317        backData.mNode = back;
318
319        back->mObjects = backObjects;
320        front->mObjects = frontObjects;
321
322        AssociateObjectsWithLeaf(back);
323        AssociateObjectsWithLeaf(front);
324   
325        // compute probability, i.e., volume of seen view cells
[1287]326        frontData.mProbability = EvalViewCellsVolume(frontObjects);
327        backData.mProbability = EvalViewCellsVolume(backObjects);
[1237]328
329        return node;
330}
331
332
333BvhNode *BvHierarchy::Subdivide(SplitQueue &tQueue,
334                                                                SubdivisionCandidate *splitCandidate,
335                                                                const bool globalCriteriaMet)
336{
[1288]337        BvhSubdivisionCandidate *sc =
338                dynamic_cast<BvhSubdivisionCandidate *>(splitCandidate);
[1237]339        BvhTraversalData &tData = sc->mParentData;
340
341        BvhNode *newNode = tData.mNode;
342
343        if (!LocalTerminationCriteriaMet(tData) && !globalCriteriaMet)
344        {       
[1294]345                //-- continue subdivision
346
[1237]347                BvhTraversalData tFrontData;
348                BvhTraversalData tBackData;
[1294]349                       
[1237]350                // create new interior node and two leaf node
351                newNode = SubdivideNode(sc->mFrontObjects,
352                                                                sc->mBackObjects,
353                                                                tData,
354                                                                tFrontData,
355                                                                tBackData);
356       
357                const int maxCostMisses = sc->mMaxCostMisses;
358
359        // how often was max cost ratio missed in this branch?
360                tFrontData.mMaxCostMisses = maxCostMisses;
361                tBackData.mMaxCostMisses = maxCostMisses;
362               
[1287]363                // decrease the weighted average cost of the subdivisoin
[1237]364                mTotalCost -= sc->GetRenderCostDecrease();
365
366                // subdivision statistics
[1287]367                if (1) PrintSubdivisionStats(*sc);
[1237]368
369                //-- push the new split candidates on the queue
370               
[1287]371                BvhSubdivisionCandidate *frontCandidate =
372                        new BvhSubdivisionCandidate(tFrontData);
373                BvhSubdivisionCandidate *backCandidate =
374                        new BvhSubdivisionCandidate(tBackData);
[1237]375
376                EvalSubdivisionCandidate(*frontCandidate);
377                EvalSubdivisionCandidate(*backCandidate);
[1297]378       
379                // cross reference
380                tFrontData.mNode->SetSubdivisionCandidate(frontCandidate);
381                tBackData.mNode->SetSubdivisionCandidate(backCandidate);
[1305]382
383                Debug << "leaf: " << tFrontData.mNode << " setting f candidate: " << tFrontData.mNode->GetSubdivisionCandidate() << " type: " << tFrontData.mNode->GetSubdivisionCandidate()->Type() << endl;
384                Debug << "leaf: " << tBackData.mNode << " setting b candidate: " << tBackData.mNode->GetSubdivisionCandidate() << " type: " << tBackData.mNode->GetSubdivisionCandidate()->Type() << endl;
385               
[1237]386                tQueue.Push(frontCandidate);
387                tQueue.Push(backCandidate);
388
389                // delete old leaf node
[1294]390                //DEL_PTR(tData.mNode);
[1237]391        }
392
[1305]393        //-- terminate traversal
[1237]394
[1297]395    if (newNode->IsLeaf())
[1237]396        {
[1297]397                //-- store additional info
[1305]398               
[1237]399                EvaluateLeafStats(tData);
400       
[1297]401                const bool mStoreRays = true;
[1237]402                if (mStoreRays)
403                {
404                        BvhLeaf *leaf = dynamic_cast<BvhLeaf *>(newNode);
405                        CollectRays(leaf->mObjects, leaf->mVssRays);
406                }
[1305]407               
408                // detach subdivision candidate: this leaf is no candidate for
409                // splitting anymore
410                tData.mNode->SetSubdivisionCandidate(NULL);
[1294]411                // detach node so it won't get deleted
412                tData.mNode = NULL;
[1237]413        }
414       
415        return newNode;
416}
417
418
419void BvHierarchy::EvalSubdivisionCandidate(BvhSubdivisionCandidate &splitCandidate)
420{
421        // compute best object partition
[1287]422        const float ratio =     SelectObjectPartition(
423                                                        splitCandidate.mParentData,
424                                                        splitCandidate.mFrontObjects,
425                                                        splitCandidate.mBackObjects);
426       
427        BvhLeaf *leaf = splitCandidate.mParentData.mNode;
[1237]428
[1288]429        // cost ratio violated?
[1297]430        const bool maxCostRatioViolated = mTermMaxCostRatio < ratio;
[1287]431
[1288]432        splitCandidate.mMaxCostMisses = maxCostRatioViolated ?
[1297]433                splitCandidate.mParentData.mMaxCostMisses + 1 :
434                splitCandidate.mParentData.mMaxCostMisses;
[1288]435
436        const float viewSpaceVol = mVspTree->GetBoundingBox().GetVolume();
[1302]437        const float oldProp = EvalViewCellsVolume(leaf->mObjects);
[1305]438        //const float oldProp2 = splitCandidate.mParentData.mProbability; Debug << "here8 " << (oldProp - oldProp2) / viewSpaceVol << "  " << oldProp  / viewSpaceVol << " " << oldProp2  / viewSpaceVol << endl;
[1287]439
[1302]440        const float oldRenderCost = oldProp * (float)leaf->mObjects.size() / viewSpaceVol;
441
[1237]442        // compute global decrease in render cost
[1287]443        float newRenderCost = EvalRenderCost(splitCandidate.mParentData,
[1302]444                                                                             splitCandidate.mFrontObjects,
[1287]445                                                                                 splitCandidate.mBackObjects);
[1237]446
[1287]447        newRenderCost /=  viewSpaceVol;
448        const float renderCostDecr = oldRenderCost - newRenderCost;
449
[1294]450        Debug << "\nbvh render cost decr: " << renderCostDecr << endl;
[1237]451        splitCandidate.SetRenderCostDecrease(renderCostDecr);
452
[1313]453#if 0
[1294]454        const float priority = (float)-splitCandidate.mParentData.mDepth;
[1237]455#else   
456        // take render cost of node into account
457        // otherwise danger of being stuck in a local minimum!!
458        const float factor = mRenderCostDecreaseWeight;
459        const float priority = factor * renderCostDecr + (1.0f - factor) * oldRenderCost;
460#endif
461
462        // compute global decrease in render cost
463        splitCandidate.SetPriority(priority);
464}
465
466
[1251]467inline bool BvHierarchy::LocalTerminationCriteriaMet(const BvhTraversalData &data) const
[1237]468{
469        // matt: TODO
[1288]470        return ( 0
[1294]471                //|| ((int)data.mNode->mObjects.size() < mTermMinObjects)
472                //|| (data.mProbability <= mTermMinProbability)
473                //|| (data.mDepth >= mTermMaxDepth)
[1237]474                 );
475}
476
477
[1251]478inline bool BvHierarchy::GlobalTerminationCriteriaMet(const BvhTraversalData &data) const
[1237]479{
480        // matt: TODO
[1288]481        return (0
482                || (mBvhStats.Leaves() >= mTermMaxLeaves)
[1302]483                //|| (mGlobalCostMisses >= mTermGlobalCostMissTolerance)
[1288]484                //|| mOutOfMemory
[1237]485                );
486}
487
488
489void BvHierarchy::EvaluateLeafStats(const BvhTraversalData &data)
490{
491        // the node became a leaf -> evaluate stats for leafs
492        BvhLeaf *leaf = data.mNode;
493       
494        ++ mCreatedLeaves;
495
496        if (data.mDepth >= mTermMaxDepth)
497        {
498        ++ mBvhStats.maxDepthNodes;
499                //Debug << "new max depth: " << mVspStats.maxDepthNodes << endl;
500        }
501
[1288]502        if (data.mDepth < mTermMaxDepth)
503        {
504        ++ mBvhStats.minDepthNodes;
505        }
506
[1287]507        if (data.mProbability <= mTermMinProbability)
[1237]508                ++ mBvhStats.minProbabilityNodes;
509       
510        // accumulate depth to compute average depth
511        mBvhStats.accumDepth += data.mDepth;
512 
[1288]513        if ((int)(leaf->mObjects.size()) < mTermMinObjects)
514             ++ mBvhStats.minObjectsNodes;
[1237]515 
516        if ((int)(leaf->mObjects.size()) > mBvhStats.maxObjectRefs)
517                mBvhStats.maxObjectRefs = (int)leaf->mObjects.size();
518}
519
520
[1297]521#if 0
[1287]522float BvHierarchy::EvalLocalObjectPartition(const BvhTraversalData &tData,
523                                                                                        const int axis,
524                                                                                        ObjectContainer &objectsFront,
525                                                                                        ObjectContainer &objectsBack)
[1237]526{
[1287]527        const float maxBox = tData.mBoundingBox.Max(axis);
528        const float minBox = tData.mBoundingBox.Min(axis);
[1237]529
[1287]530        float midPoint = (maxBox + minBox) * 0.5f;
531
532        ObjectContainer::const_iterator oit, oit_end = tData.mNode->mObjects.end();
[1237]533       
[1287]534        for (oit = tData.mNode->mObjects.begin(); oit != oit_end; ++ oit)
535        {
536                Intersectable *obj = *oit;
[1297]537                const AxisAlignedBox3 box = obj->GetBox();
[1291]538
[1294]539                const float objMid = (box.Max(axis) + box.Min(axis)) * 0.5f;
[1291]540
[1287]541                // object mailed => belongs to back objects
542                if (objMid < midPoint)
543                        objectsBack.push_back(obj);
544                else
545                        objectsFront.push_back(obj);
546        }
[1237]547
[1287]548        const float oldRenderCost = tData.mProbability * (float)tData.mNode->mObjects.size();
549        const float newRenderCost =
550                EvalRenderCost(tData, objectsFront, objectsBack);
[1237]551
[1287]552        const float ratio = newRenderCost / oldRenderCost;
553        return ratio;
554}
[1237]555
[1297]556#else
[1237]557
[1297]558float BvHierarchy::EvalLocalObjectPartition(const BvhTraversalData &tData,
559                                                                                        const int axis,
560                                                                                        ObjectContainer &objectsFront,
561                                                                                        ObjectContainer &objectsBack)
562{
563        SortSubdivisionCandidates(tData, axis);
564       
565        vector<SortableEntry>::const_iterator cit, cit_end = mSubdivisionCandidates->end();
566
567        int i = 0;
568        const int border = (int)tData.mNode->mObjects.size() / 2;
569
570    for (cit = mSubdivisionCandidates->begin(); cit != cit_end; ++ cit, ++ i)
571        {
572                Intersectable *obj = (*cit).mObject;
573
574                // object mailed => belongs to back objects
575                if (i < border)
576                        objectsBack.push_back(obj);
577                else
578                        objectsFront.push_back(obj);
579        }
580
[1302]581        const float oldProp = EvalViewCellsVolume(tData.mNode->mObjects);
[1323]582        //const float oldProp2 = tData.mProbability;
[1297]583
[1302]584        const float oldRenderCost = oldProp * (float)tData.mNode->mObjects.size();
585        const float newRenderCost = EvalRenderCost(tData, objectsFront, objectsBack);
586
[1297]587        const float ratio = newRenderCost / oldRenderCost;
588        return ratio;
589}
590#endif
591
592
[1323]593float BvHierarchy::EvalSah(const BvhTraversalData &tData,
594                                                   const int axis,
595                                                   ObjectContainer &objectsFront,
596                                                   ObjectContainer &objectsBack)
597{
598        SortSubdivisionCandidates(tData, axis);
599 
600        // go through the lists, count the number of objects left and right
601        // and evaluate the following cost funcion:
602        // C = ct_div_ci  + (ol + or)/queries
603        int objectsLeft = 0, objectsRight = (int)tData.mNode->mObjects.size();
604 
605        AxisAlignedBox3 box = tData.mNode->GetBoundingBox();
606
607        float minBox = box.Min(axis);
608        float maxBox = box.Max(axis);
609        float boxArea = box.SurfaceArea();
610
611        float minSum = 1e20f;
612 
613        vector<float> bordersRight;
614        bordersRight.resize(mSubdivisionCandidates->size());
615
616        float minBorder = maxBox;
617        float maxBorder = minBox;
618
619        vector<SortableEntry>::const_iterator currentPos =
620                mSubdivisionCandidates->begin();
621
622        vector<SortableEntry>::reverse_iterator rcit =
623                mSubdivisionCandidates->rbegin(), rcit_end = mSubdivisionCandidates->rend();
624               
625        vector<float>::reverse_iterator rbit = bordersRight.rbegin();
626       
627        for (; rcit != rcit_end; ++ rcit, ++ rbit)
628        {
629                Intersectable *obj = (*rcit).mObject;
630                const AxisAlignedBox3 box = obj->GetBox();
631
632                if (box.Min() < minBorder)
633                        minBorder = box.Min(axis);
634               
635                (*rbit) = minBorder;
636        }
637
638        vector<float>::const_iterator bit = bordersRight.begin();
639
640        vector<SortableEntry>::const_iterator cit, cit_end = mSubdivisionCandidates->end();
641        for (cit = mSubdivisionCandidates->begin(); cit != cit_end; ++ cit, ++ bit)
642        {
643                Intersectable *obj = (*cit).mObject;
644
645                ++ objectsLeft;
646                -- objectsRight;
647
648                AxisAlignedBox3 lbox = box;
649                AxisAlignedBox3 rbox = box;
650       
651                const AxisAlignedBox3 obox = obj->GetBox();
652
653                if (obox.Max(axis) > maxBorder)
654                        maxBorder = obox.Max(axis);
655
656        lbox.SetMax(axis, maxBorder);
657                rbox.SetMin(axis, *bit);
658       
659                const float sum = objectsLeft * lbox.SurfaceArea() + objectsRight * rbox.SurfaceArea();
660     
661            // cout<<"pos="<<(*ci).value<<"\t q=("<<ql<<","<<qr<<")\t r=("<<rl<<","<<rr<<")"<<endl;
662            // cout<<"cost= "<<sum<<endl;
663     
664                if (sum < minSum)
665                {
666                        minSum = sum;   
667                        // objects belongs to left side now
668                        for (; currentPos != (cit + 1); ++ currentPos);
669                }
670        }
671
672        //-- assign object to front and back volume
673
674        // belongs to back bv
675        for (cit = mSubdivisionCandidates->begin(); cit != currentPos; ++ cit)
676                objectsBack.push_back((*cit).mObject);
677       
678        // belongs to front bv
679        for (cit = currentPos; cit != cit_end; ++ cit)
680                objectsFront.push_back((*cit).mObject);
681
682        float oldCost = (float)tData.mNode->mObjects.size();
683        float newCost = minSum / boxArea;
684        float ratio = newCost / oldCost;
685 
686#if 0
687  cout<<"===================="<<endl;
688  cout<<"costRatio="<<ratio<<" pos="<<position<<" t="<<(position - minBox)/(maxBox - minBox)
689      <<"\t o=("<<objectsBack<<","<<objectsFront<<")"<<endl;
690#endif
691  return ratio;
692}
693
694
695static bool PrepareOutput(const int axis,
696                                                  const int leaves,
697                                                  ofstream &sumStats,
698                                                  ofstream &vollStats,
699                                                  ofstream &volrStats)
700{
701        if ((axis == 0) && (leaves > 0) && (leaves < 90))
702        {
703                char str[64];   
704                sprintf(str, "tmp/bvh_heur_sum-%04d.log", leaves);
705                sumStats.open(str);
706                sprintf(str, "tmp/bvh_heur_voll-%04d.log", leaves);
707                vollStats.open(str);
708                sprintf(str, "tmp/bvh_heur_volr-%04d.log", leaves);
709                volrStats.open(str);
710        }
711
712        return sumStats.is_open() && vollStats.is_open() && volrStats.is_open();
713}
714
715
716static void PrintHeuristics(const int objectsRight,
717                                                        const float sum,
718                                                        const float volLeft,
719                                                        const float volRight,
720                                                        const float viewSpaceVol,
721                                                        ofstream &sumStats,
722                                                        ofstream &vollStats,
723                                                        ofstream &volrStats)
724{
725        sumStats
726                << "#Position\n" << objectsRight << endl
727                << "#Sum\n" << sum / viewSpaceVol << endl
728                << "#Vol\n" << (volLeft +  volRight) / viewSpaceVol << endl;
729
730        vollStats
731                << "#Position\n" << objectsRight << endl
732                << "#Vol\n" << volLeft / viewSpaceVol << endl;
733
734        volrStats
735                << "#Position\n" << objectsRight << endl
736                << "#Vol\n" << volRight / viewSpaceVol << endl;
737}
738
739
[1287]740float BvHierarchy::EvalLocalCostHeuristics(const BvhTraversalData &tData,
741                                                                                   const int axis,
742                                                                                   ObjectContainer &objectsFront,
743                                                                                   ObjectContainer &objectsBack)
744{
745        // prepare the heuristics by setting mailboxes and counters.
746        const float totalVol = PrepareHeuristics(tData, axis);
[1237]747
[1287]748        // go through the lists, count the number of objects left and right
749        // and evaluate the cost funcion
[1237]750
[1287]751        // local helper variables
752        float volLeft = 0;
753        float volRight = totalVol;
[1237]754
[1287]755        int nObjectsLeft = 0;
[1237]756
[1287]757        const int nTotalObjects = (int)tData.mNode->mObjects.size();
758        const float viewSpaceVol = mVspTree->GetBoundingBox().GetVolume();
[1237]759
[1287]760        vector<SortableEntry>::const_iterator currentPos =
761                mSubdivisionCandidates->begin();
762
[1237]763        /////////////////////////////////
764        // the parameters for the current optimum
765
[1287]766        float volBack = volLeft;
767        float volFront = volRight;
768        float newRenderCost = nTotalObjects * totalVol;
[1237]769
[1314]770#ifdef _DEBUG
771        ofstream sumStats;
772        ofstream vollStats;
773        ofstream volrStats;
[1237]774
[1323]775        const bool printStats =
776                PrepareOutput(axis, mBvhStats.Leaves(), sumStats, vollStats, volrStats);
777       
[1314]778#endif
779
[1237]780        /////////////////////////////
781        // the sweep heuristics
782       
783        //-- traverse through events and find best split plane
784
[1287]785        vector<SortableEntry>::const_iterator cit, cit_end = mSubdivisionCandidates->end();
786
787        for (cit = mSubdivisionCandidates->begin(); cit != cit_end; ++ cit)
[1237]788        {
[1287]789                Intersectable *object = (*cit).mObject;
790               
791                // evaluate change in l and r volume
792                // voll = view cells that see only left node (i.e., left pvs)
793                // volr = view cells that see only right node (i.e., right pvs)
794                EvalHeuristicsContribution(object, volLeft, volRight);
[1237]795
[1287]796                ++ nObjectsLeft;
797               
798                const int nObjectsRight = nTotalObjects - nObjectsLeft;
[1237]799
[1287]800                // the heuristics
801            const float sum = volLeft * (float)nObjectsLeft +
802                                                  volRight * (float)nObjectsRight;
803
[1314]804#ifdef _DEBUG
805                if (printStats)
[1323]806                        PrintHeuristics(nObjectsRight, sum, volLeft, volRight, viewSpaceVol,
807                                                        sumStats, vollStats, volrStats);
[1314]808#endif
809
[1287]810                if (sum < newRenderCost)
[1237]811                {
[1287]812                        newRenderCost = sum;
[1237]813
[1287]814                        volBack = volLeft;
815                        volFront = volRight;
[1237]816
[1287]817                        // objects belongs to left side now
818                        for (; currentPos != (cit + 1); ++ currentPos);
[1237]819                }
820        }
821
[1287]822        //-- assign object to front and back volume
[1237]823
[1287]824        // belongs to back bv
825        for (cit = mSubdivisionCandidates->begin(); cit != currentPos; ++ cit)
826                objectsBack.push_back((*cit).mObject);
827       
828        // belongs to front bv
829        for (cit = currentPos; cit != cit_end; ++ cit)
830                objectsFront.push_back((*cit).mObject);
[1237]831
[1287]832        const float oldRenderCost = (float)nTotalObjects * totalVol + Limits::Small;
833        // the relative cost ratio
834        const float ratio = newRenderCost / oldRenderCost;
835
[1314]836#ifdef _DEBUG
[1237]837        Debug << "\n§§§§ eval local cost §§§§" << endl
[1293]838                  << "back pvs: " << (int)objectsBack.size() << " front pvs: " << (int)objectsFront.size() << " total pvs: " << nTotalObjects << endl
[1237]839                  << "back p: " << volBack / viewSpaceVol << " front p " << volFront / viewSpaceVol << " p: " << totalVol / viewSpaceVol << endl
840                  << "old rc: " << oldRenderCost / viewSpaceVol << " new rc: " << newRenderCost / viewSpaceVol << endl
841                  << "render cost decrease: " << oldRenderCost / viewSpaceVol - newRenderCost / viewSpaceVol << endl;
[1314]842#endif
[1237]843
844        return ratio;
845}
846
847
848void BvHierarchy::SortSubdivisionCandidates(const BvhTraversalData &tData,
[1287]849                                                                                        const int axis)                                                                                 
[1237]850{
851        mSubdivisionCandidates->clear();
852
853        //RayInfoContainer *rays = tData.mRays;
854        BvhLeaf *leaf = tData.mNode;
855
856        // compute requested size
[1287]857        const int requestedSize = (int)leaf->mObjects.size() * 2;
[1237]858       
859        // creates a sorted split candidates array
860        if (mSubdivisionCandidates->capacity() > 500000 &&
861                requestedSize < (int)(mSubdivisionCandidates->capacity() / 10) )
862        {
863        delete mSubdivisionCandidates;
864                mSubdivisionCandidates = new vector<SortableEntry>;
865        }
866
867        mSubdivisionCandidates->reserve(requestedSize);
868
869        //-- insert object queries
870        //-- These queries can induce a change in pvs size.
871        //-- Note that they cannot induce a change in view cell volume, as
872        //-- there is no ray associated with these events!!
873
[1287]874        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
875
[1237]876        for (oit = leaf->mObjects.begin(); oit < oit_end; ++ oit)
877        {
878                Intersectable *obj = *oit;
879               
880                Intersectable *object = *oit;
[1287]881                const AxisAlignedBox3 &box = object->GetBox();
882                const float midPt = (box.Min(axis) + box.Max(axis)) * 0.5f;
[1237]883
[1287]884                mSubdivisionCandidates->push_back(SortableEntry(object, midPt));
[1237]885        }
886
887        stable_sort(mSubdivisionCandidates->begin(), mSubdivisionCandidates->end());
888}
889
890
891const BvhStatistics &BvHierarchy::GetStatistics() const
892{
893        return mBvhStats;
894}
895
896
[1287]897float BvHierarchy::PrepareHeuristics(const BvhTraversalData &tData, const int axis)
898{       
[1323]899        BvhLeaf *leaf = tData.mNode;
900        float vol = 0;
901
902        // sort so we can use a sweep from right to left
[1287]903        SortSubdivisionCandidates(tData, axis);
904
905        // collect and mark the view cells as belonging to front pvs
906        ViewCellContainer viewCells;
907        CollectViewCells(tData.mNode->mObjects, viewCells, true);
[1323]908                       
909        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
[1287]910        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
911        {
912                vol += (*vit)->GetVolume();
913        }
914
[1323]915        // mail the objects on the left side
916        Intersectable::NewMail();
[1287]917        // mail view cells on the left side
918        ViewCell::NewMail();
[1323]919       
[1287]920        return vol;
921}
922///////////////////////////////////////////////////////////
923
924
925void BvHierarchy::EvalHeuristicsContribution(Intersectable *obj,
926                                                                                         float &volLeft,
927                                                                                         float &volRight)
[1237]928{
[1287]929        // collect all view cells associated with this objects
930        // (also multiple times, if they are pierced by several rays)
[1237]931        ViewCellContainer viewCells;
[1287]932        const bool useMailboxing = false;
[1323]933
[1287]934        CollectViewCells(obj, viewCells, useMailboxing);
[1237]935
936        /// classify view cells and compute volume contri accordingly
937        /// possible view cell classifications:
938        /// view cell mailed => view cell can be seen from left child node
939        /// view cell counter > 0 view cell can be seen from right child node
940        /// combined: view cell volume belongs to both nodes
941        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
942       
943        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
944        {
945                // view cells can also be seen from left child node
946                ViewCell *viewCell = *vit;
947
948                const float vol = viewCell->GetVolume();
949
950                if (!viewCell->Mailed())
951                {
952                        viewCell->Mail();
953
954                        // we now see view cell from both nodes
[1287]955                        // => add volume to left node
956                        volLeft += vol;
[1237]957                }
958
959                // last reference into the right node
960                if (-- viewCell->mCounter == 0)
961                {
962                        // view cell was previously seen from both nodes  =>
[1287]963                        // remove volume from right node
964                        volRight -= vol;
[1237]965                }
966        }
967}
968
969
970void BvHierarchy::SetViewCellsManager(ViewCellsManager *vcm)
971{
972        mViewCellsManager = vcm;
973}
974
975
976AxisAlignedBox3 BvHierarchy::GetBoundingBox() const
977{
978        return mBoundingBox;
979}
980
981
982float BvHierarchy::SelectObjectPartition(const BvhTraversalData &tData,
983                                                                                 ObjectContainer &frontObjects,
984                                                                                 ObjectContainer &backObjects)
985{
986        ObjectContainer nFrontObjects[3];
987        ObjectContainer nBackObjects[3];
988
989        float nCostRatio[3];
990
991        // create bounding box of node geometry
992        AxisAlignedBox3 box = tData.mBoundingBox;
993               
994        int sAxis = 0;
995        int bestAxis = -1;
996
997        if (mOnlyDrivingAxis)
998        {
999                sAxis = box.Size().DrivingAxis();
1000        }
1001       
1002        // -- evaluate split cost for all three axis
1003       
1004        for (int axis = 0; axis < 3; ++ axis)
1005        {
1006                if (!mOnlyDrivingAxis || (axis == sAxis))
1007                {
[1287]1008                        if (mUseCostHeuristics)
[1298]1009                        {
[1237]1010                                //-- partition objects using heuristics
1011                                nCostRatio[axis] =
1012                                        EvalLocalCostHeuristics(
1013                                                                                        tData,
1014                                                                                        axis,
1015                                                                                        nFrontObjects[axis],
[1287]1016                                                                                        nBackObjects[axis]);
[1237]1017                        }
[1287]1018                        else
[1298]1019                        {
[1287]1020                                nCostRatio[axis] =
1021                                        EvalLocalObjectPartition(
1022                                                                                         tData,
1023                                                                                         axis,
1024                                                                                         nFrontObjects[axis],
1025                                                                                         nBackObjects[axis]);
1026                        }
1027
[1237]1028                        if (bestAxis == -1)
1029                        {
1030                                bestAxis = axis;
1031                        }
1032                        else if (nCostRatio[axis] < nCostRatio[bestAxis])
1033                        {
1034                                bestAxis = axis;
1035                        }
1036                }
1037        }
1038
1039        //-- assign values
[1287]1040
[1237]1041        frontObjects = nFrontObjects[bestAxis];
[1287]1042        backObjects = nBackObjects[bestAxis];
[1237]1043
[1293]1044        //Debug << "val: " << nCostRatio[bestAxis] << " axis: " << bestAxis << endl;
[1237]1045        return nCostRatio[bestAxis];
1046}
1047
1048
1049void BvHierarchy::AssociateObjectsWithRays(const VssRayContainer &rays)
1050{
1051
1052        VssRayContainer::const_iterator rit, rit_end = rays.end();
1053
1054    for (rit = rays.begin(); rit != rays.end(); ++ rit)
1055        {
1056                VssRay *ray = (*rit);
1057
1058                if (ray->mTerminationObject)
1059                {
1060                        ray->mTerminationObject->mVssRays.push_back(ray);
1061                }
1062
1063                if (0 && ray->mOriginObject)
1064                {
1065                        ray->mOriginObject->mVssRays.push_back(ray);
1066                }
1067        }
1068}
1069
1070
[1287]1071void BvHierarchy::PrintSubdivisionStats(const SubdivisionCandidate &sc)
[1237]1072{
[1287]1073        const float costDecr = sc.GetRenderCostDecrease();     
[1237]1074
1075        mSubdivisionStats
[1287]1076                        << "#Leaves\n" << mBvhStats.Leaves()
1077                        << "#RenderCostDecrease\n" << costDecr << endl
1078                        << "#TotalRenderCost\n" << mTotalCost << endl;
[1237]1079                        //<< "#AvgRenderCost\n" << avgRenderCost << endl;
1080}
1081
1082
1083void BvHierarchy::CollectRays(const ObjectContainer &objects,
1084                                                          VssRayContainer &rays) const
1085{
1086        VssRay::NewMail();
1087       
1088        ObjectContainer::const_iterator oit, oit_end = objects.end();
1089
1090        // evaluate reverse pvs and view cell volume on left and right cell
1091        // note: should I take all leaf objects or rather the objects hit by rays?
1092        for (oit = objects.begin(); oit != oit_end; ++ oit)
1093        {
1094                Intersectable *obj = *oit;
1095               
1096                VssRayContainer::const_iterator rit, rit_end = obj->mVssRays.end();
1097
1098                for (rit = obj->mVssRays.begin(); rit < rit_end; ++ rit)
1099                {
1100                        VssRay *ray = (*rit);
1101
1102                        if (!ray->Mailed())
1103                        {
1104                                ray->Mail();
1105                                rays.push_back(ray);
1106                        }
1107                }
1108        }
1109}
1110
1111
[1287]1112float BvHierarchy::EvalRenderCost(const BvhTraversalData &tData,
1113                                                                  const ObjectContainer &objectsFront,
1114                                                                  const ObjectContainer &objectsBack) const
1115{
1116        BvhLeaf *leaf = tData.mNode;
1117
1118        // probability that view point lies in a view cell which sees this node
1119        const float pFront = EvalViewCellsVolume(objectsFront);
1120        const float pBack = EvalViewCellsVolume(objectsBack);
1121               
1122        const int totalObjects = (int)leaf->mObjects.size();
1123        const int nObjectsFront = (int)objectsFront.size();
1124        const int nObjectsBack = (int)objectsBack.size();
1125
1126        //-- pvs rendering heuristics
[1302]1127        const float newRenderCost = nObjectsFront * pFront + nObjectsBack * pBack;
1128        /*
[1287]1129        const float viewSpaceVol = mVspTree->GetBoundingBox().GetVolume();
[1302]1130        Debug << "\nbvh render cost\n"
[1287]1131                  << "back p: " << pBack / viewSpaceVol << " front p " << pFront / viewSpaceVol << endl
[1294]1132                  << "new rc: " << newRenderCost / viewSpaceVol << endl;*/
[1287]1133
1134        return newRenderCost;
1135}
1136
1137
1138AxisAlignedBox3 BvHierarchy::ComputeBoundingBox(const ObjectContainer &objects,
1139                                                                                                const AxisAlignedBox3 *parentBox)
[1237]1140{
[1287]1141        if (parentBox && objects.empty())
1142                return *parentBox;
1143
[1237]1144        AxisAlignedBox3 box;
1145        box.Initialize();
1146
1147        ObjectContainer::const_iterator oit, oit_end = objects.end();
1148
1149        //-- compute bounding box
1150        for (oit = objects.begin(); oit != oit_end; ++ oit)
1151        {
1152                Intersectable *obj = *oit;
1153
1154                // compute bounding box of view space
[1287]1155                box.Include(obj->GetBox());
[1237]1156        }
[1287]1157
[1237]1158        return box;
1159}
1160
1161
1162void BvHierarchy::CollectLeaves(vector<BvhLeaf *> &leaves) const
1163{
1164        stack<BvhNode *> nodeStack;
1165        nodeStack.push(mRoot);
1166
1167        while (!nodeStack.empty())
1168        {
1169                BvhNode *node = nodeStack.top();
1170                nodeStack.pop();
[1287]1171
[1237]1172                if (node->IsLeaf())
1173                {
1174                        BvhLeaf *leaf = (BvhLeaf *)node;
1175                        leaves.push_back(leaf);
1176                }
1177                else
1178                {
1179                        BvhInterior *interior = (BvhInterior *)node;
1180
1181                        nodeStack.push(interior->GetBack());
1182                        nodeStack.push(interior->GetFront());
1183                }
1184        }
1185}
1186
1187
1188AxisAlignedBox3 BvHierarchy::GetBoundingBox(BvhNode *node) const
1189{
1190        return node->GetBoundingBox();
1191}
1192
1193
[1287]1194void BvHierarchy::CollectViewCells(const ObjectContainer &objects,
1195                                                                   ViewCellContainer &viewCells,
1196                                                                   const bool setCounter) const
[1237]1197{
1198        ViewCell::NewMail();
[1287]1199        ObjectContainer::const_iterator oit, oit_end = objects.end();
[1237]1200
1201        // loop through all object and collect view cell pvs of this node
[1287]1202        for (oit = objects.begin(); oit != oit_end; ++ oit)
[1237]1203        {
[1287]1204                CollectViewCells(*oit, viewCells, true, setCounter);
[1237]1205        }
1206}
1207
1208
[1287]1209void BvHierarchy::CollectViewCells(Intersectable *obj,
1210                                                                   ViewCellContainer &viewCells,
1211                                                                   const bool useMailBoxing,
1212                                                                   const bool setCounter) const
[1237]1213{
[1287]1214        VssRayContainer::const_iterator rit, rit_end = obj->mVssRays.end();
[1237]1215
[1287]1216        for (rit = obj->mVssRays.begin(); rit < rit_end; ++ rit)
[1237]1217        {
1218                VssRay *ray = (*rit);
[1287]1219                ViewCellContainer tmpViewCells;
1220       
[1237]1221                mVspTree->GetViewCells(*ray, tmpViewCells);
1222
1223                ViewCellContainer::const_iterator vit, vit_end = tmpViewCells.end();
1224
1225                for (vit = tmpViewCells.begin(); vit != vit_end; ++ vit)
1226                {
1227                        VspViewCell *vc = dynamic_cast<VspViewCell *>(*vit);
1228
[1287]1229                        // store view cells
1230                        if (!useMailBoxing || !vc->Mailed())
[1237]1231                        {
[1287]1232                                if (useMailBoxing)
1233                                {
1234                                        vc->Mail();
1235                                        if (setCounter)
[1305]1236                                        {
[1287]1237                                                vc->mCounter = 0;
[1305]1238                                        }
[1287]1239                                }
[1237]1240                                viewCells.push_back(vc);
1241                        }
[1287]1242                       
1243                        if (setCounter)
1244                        {
1245                                ++ vc->mCounter;
1246                        }
[1237]1247                }
1248        }
[1287]1249}
[1237]1250
1251
[1287]1252void BvHierarchy::CollectDirtyCandidates(BvhSubdivisionCandidate *sc,
1253                                                                                 vector<SubdivisionCandidate *> &dirtyList)
1254{
1255        BvhTraversalData &tData = sc->mParentData;
1256        BvhLeaf *node = tData.mNode;
1257       
1258        ViewCellContainer viewCells;
1259        CollectViewCells(node->mObjects, viewCells);
1260
1261        // split candidates handling
1262        // these view cells  are thrown into dirty list
[1237]1263        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
1264
[1297]1265        Debug << "collecting " << (int)viewCells.size() << " dirty candidates" << endl;
[1302]1266
[1237]1267        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
1268        {
1269                VspViewCell *vc = dynamic_cast<VspViewCell *>(*vit);
1270                VspLeaf *leaf = vc->mLeaf;
[1297]1271                SubdivisionCandidate *candidate = leaf->GetSubdivisionCandidate();
1272               
[1305]1273                if (candidate) // is this leaf still a split candidate?
1274                {
1275                        dirtyList.push_back(candidate);
1276                }
[1237]1277        }
1278}
1279
1280
1281BvhNode *BvHierarchy::GetRoot() const
1282{
1283        return mRoot;
1284}
1285
1286
1287bool BvHierarchy::IsObjectInLeaf(BvhLeaf *leaf, Intersectable *object) const
1288{
1289        ObjectContainer::const_iterator oit =
1290                lower_bound(leaf->mObjects.begin(), leaf->mObjects.end(), object, ilt);
1291                               
1292        // objects sorted by id
1293        if ((oit != leaf->mObjects.end()) && ((*oit)->GetId() == object->GetId()))
1294        {
1295                return true;
1296        }
1297        else
1298        {
1299                return false;
1300        }
1301}
1302
1303
1304BvhLeaf *BvHierarchy::GetLeaf(Intersectable *object, BvhNode *node) const
1305{
1306        // rather use the simple version
[1297]1307        if (!object) return NULL;
1308        return object->mBvhLeaf;
1309       
[1237]1310        ///////////////////////////////////////
1311        // start from root of tree
[1297]1312       
[1237]1313        if (node == NULL)
1314                node = mRoot;
[1297]1315       
[1237]1316        vector<BvhLeaf *> leaves;
1317
1318        stack<BvhNode *> nodeStack;
1319        nodeStack.push(node);
1320 
1321        BvhLeaf *leaf = NULL;
1322 
1323        while (!nodeStack.empty()) 
1324        {
1325                BvhNode *node = nodeStack.top();
1326                nodeStack.pop();
1327       
1328                if (node->IsLeaf())
1329                {
1330                        leaf = dynamic_cast<BvhLeaf *>(node);
1331
1332                        if (IsObjectInLeaf(leaf, object))
[1293]1333                        {
[1237]1334                                return leaf;
[1293]1335                        }
[1237]1336                }
1337                else   
1338                {       
1339                        // find point
1340                        BvhInterior *interior = dynamic_cast<BvhInterior *>(node);
1341       
1342                        if (interior->GetBack()->GetBoundingBox().Includes(object->GetBox()))
1343                        {
1344                                nodeStack.push(interior->GetBack());
1345                        }
1346                       
1347                        // search both sides as we are using bounding volumes
1348                        if (interior->GetFront()->GetBoundingBox().Includes(object->GetBox()))
1349                        {
1350                                nodeStack.push(interior->GetFront());
1351                        }
1352                }
1353        }
1354 
1355        return leaf;
1356}
1357
1358
1359BvhIntersectable *BvHierarchy::GetOrCreateBvhIntersectable(BvhNode *node)
1360{
1361        // search nodes
1362        std::map<BvhNode *, BvhIntersectable *>::
1363                const_iterator it = mBvhIntersectables.find(node);
1364
1365        if (it != mBvhIntersectables.end())
1366        {
1367                return (*it).second;
1368        }
1369
1370        // not in map => create new entry
1371        BvhIntersectable *bvhObj = new BvhIntersectable(node);
1372        mBvhIntersectables[node] = bvhObj;
1373
1374        return bvhObj;
1375}
1376
1377
1378bool BvHierarchy::Export(OUT_STREAM &stream)
1379{
1380        ExportNode(mRoot, stream);
1381
1382        return true;
1383}
1384
1385
[1286]1386void BvHierarchy::ExportObjects(BvhLeaf *leaf, OUT_STREAM &stream)
1387{
1388        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
1389        for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
1390        {
1391                stream << (*oit)->GetId() << " ";
1392        }
1393}
1394
1395
[1237]1396void BvHierarchy::ExportNode(BvhNode *node, OUT_STREAM &stream)
1397{
1398        if (node->IsLeaf())
1399        {
1400                BvhLeaf *leaf = dynamic_cast<BvhLeaf *>(node);
[1287]1401                const AxisAlignedBox3 box = leaf->GetBoundingBox();
[1286]1402                stream << "<Leaf"
[1287]1403                           << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
1404                           << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\""
[1286]1405                           << " objects=\"";
[1237]1406               
[1286]1407                //-- export objects
1408                ExportObjects(leaf, stream);
[1237]1409               
1410                stream << "\" />" << endl;
1411        }
1412        else
1413        {       
1414                BvhInterior *interior = dynamic_cast<BvhInterior *>(node);
[1287]1415                const AxisAlignedBox3 box = interior->GetBoundingBox();
1416
[1286]1417                stream << "<Interior"
[1287]1418                           << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
1419                           << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z
[1286]1420                           << "\">" << endl;
[1237]1421
1422                ExportNode(interior->GetBack(), stream);
1423                ExportNode(interior->GetFront(), stream);
1424
1425                stream << "</Interior>" << endl;
1426        }
1427}
1428
1429
[1287]1430float BvHierarchy::EvalViewCellsVolume(const ObjectContainer &objects) const
[1237]1431{
1432        float vol = 0;
1433
[1287]1434        ViewCellContainer viewCells;
1435        CollectViewCells(objects, viewCells);
[1237]1436
[1287]1437        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
[1237]1438
[1287]1439        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
[1237]1440        {
[1287]1441                vol += (*vit)->GetVolume();
[1237]1442        }
1443
1444        return vol;
1445}
1446
[1294]1447void BvHierarchy::CreateRoot(const ObjectContainer &objects)
1448{
1449        //-- create new root
1450        AxisAlignedBox3 box = ComputeBoundingBox(objects);
1451        BvhLeaf *bvhleaf = new BvhLeaf(box, NULL, (int)objects.size());
1452        bvhleaf->mObjects = objects;
[1237]1453
[1294]1454        mRoot = bvhleaf;
1455
1456        // associate root with current objects
1457        AssociateObjectsWithLeaf(bvhleaf);
1458}
1459
1460
[1237]1461SubdivisionCandidate *BvHierarchy::PrepareConstruction(const VssRayContainer &sampleRays,
[1294]1462                                                                                                           const ObjectContainer &objects)
[1237]1463{
[1308]1464        mBvhStats.Reset();
1465        mBvhStats.Start();
1466        mBvhStats.nodes = 1;
1467
[1287]1468        // note matt: we assume that we have objects sorted by their id
1469
[1237]1470        // store pointer to this tree
1471        BvhSubdivisionCandidate::sBvHierarchy = this;
1472        mBvhStats.nodes = 1;
1473
1474        // compute bounding box from objects
[1302]1475        // note: we assume that root was already created
[1294]1476        mBoundingBox = mRoot->GetBoundingBox();
1477        BvhLeaf *bvhleaf = dynamic_cast<BvhLeaf *>(mRoot);
[1237]1478
[1287]1479        mTermMinProbability *= mBoundingBox.GetVolume();
[1237]1480        mGlobalCostMisses = 0;
[1287]1481       
[1237]1482        // only rays intersecting objects in node are interesting
1483        AssociateObjectsWithRays(sampleRays);
[1294]1484       
[1287]1485        // probabilty is voume of all "seen" view cells
1486#if 1
[1294]1487        const float prop = EvalViewCellsVolume(objects);
[1287]1488#else
1489        const float prop = GetBoundingBox().GetVolume();
1490#endif
[1237]1491
[1288]1492        // create bvh traversal data
[1287]1493        BvhTraversalData oData(bvhleaf, 0, mBoundingBox, prop);
[1237]1494
[1294]1495        //-- add first candidate for object space partition     
[1237]1496        BvhSubdivisionCandidate *oSubdivisionCandidate =
1497                new BvhSubdivisionCandidate(oData);
1498
1499        EvalSubdivisionCandidate(*oSubdivisionCandidate);
[1302]1500        bvhleaf->SetSubdivisionCandidate(oSubdivisionCandidate);
[1237]1501
[1287]1502        const float viewSpaceVol = mVspTree->GetBoundingBox().GetVolume();
1503        mTotalCost = (float)objects.size() * prop / viewSpaceVol;
[1237]1504
[1287]1505        PrintSubdivisionStats(*oSubdivisionCandidate);
[1237]1506
1507        return oSubdivisionCandidate;
1508}
1509
1510
[1259]1511bool BvHierarchy::AddLeafToPvs(BvhLeaf *leaf,
1512                                                           ViewCell *vc,
1513                                                           const float pdf,
1514                                                           float &contribution)
1515{
1516        // add kd intersecable to pvs
1517        BvhIntersectable *bvhObj = GetOrCreateBvhIntersectable(leaf);
1518       
1519        return vc->AddPvsSample(bvhObj, pdf, contribution);
1520}
[1237]1521
[1279]1522
1523void BvhStatistics::Print(ostream &app) const
1524{
[1288]1525        app << "=========== BvHierarchy statistics ===============\n";
[1279]1526
1527        app << setprecision(4);
1528
1529        app << "#N_CTIME  ( Construction time [s] )\n" << Time() << " \n";
1530
1531        app << "#N_NODES ( Number of nodes )\n" << nodes << "\n";
1532
1533        app << "#N_INTERIORS ( Number of interior nodes )\n" << Interior() << "\n";
1534
1535        app << "#N_LEAVES ( Number of leaves )\n" << Leaves() << "\n";
1536
1537        app << "#AXIS_ALIGNED_SPLITS (number of axis aligned splits)\n" << splits << endl;
1538
[1288]1539        app << "#N_PMINDEPTHLEAVES ( Percentage of leaves at minimum depth )\n"
1540                <<      minDepthNodes * 100 / (double)Leaves() << endl;
1541
[1279]1542        app << "#N_PMAXDEPTHLEAVES ( Percentage of leaves at maximum depth )\n"
1543                <<      maxDepthNodes * 100 / (double)Leaves() << endl;
1544
1545        app << "#N_MAXCOSTNODES  ( Percentage of leaves with terminated because of max cost ratio )\n"
1546                << maxCostNodes * 100 / (double)Leaves() << endl;
1547
1548        app << "#N_PMINPROBABILITYLEAVES  ( Percentage of leaves with mininum probability )\n"
1549                << minProbabilityNodes * 100 / (double)Leaves() << endl;
1550
[1288]1551        app << "#N_PMINOBJECTSLEAVES  ( Percentage of leaves with mininum objects )\n"
1552                << minObjectsNodes * 100 / (double)Leaves() << endl;
1553
[1279]1554        app << "#N_PMAXDEPTH ( Maximal reached depth )\n" << maxDepth << endl;
1555
1556        app << "#N_PMINDEPTH ( Minimal reached depth )\n" << minDepth << endl;
1557
1558        app << "#AVGDEPTH ( average depth )\n" << AvgDepth() << endl;
1559
1560        app << "#N_INVALIDLEAVES (number of invalid leaves )\n" << invalidLeaves << endl;
1561
1562        app << "#N_MAXOBJECTREFS  ( Max number of object refs / leaf )\n" << maxObjectRefs << "\n";
1563
1564        //app << "#N_RAYS (number of rays / leaf)\n" << AvgRays() << endl;
1565       
1566        app << "========== END OF VspTree statistics ==========\n";
[1272]1567}
[1259]1568
[1279]1569
1570}
Note: See TracBrowser for help on using the repository browser.