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

Revision 1359, 44.5 KB checked in by mattausch, 18 years ago (diff)

worked on global object sorting

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