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

Revision 1357, 44.4 KB checked in by mattausch, 18 years ago (diff)

implemented the global version of the bounding volume construction

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.useGlobalSort", mUseGlobalSorting);
230
231
232        ///////////////////
233        //-- debug output
234        Debug << "******* Bvh hierarchy options ******** " << endl;
235    Debug << "max depth: " << mTermMaxDepth << endl;
236        Debug << "min probabiliy: " << mTermMinProbability<< endl;
237        Debug << "min objects: " << mTermMinObjects << endl;
238        Debug << "max cost ratio: " << mTermMaxCostRatio << endl;
239        Debug << "miss tolerance: " << mTermMissTolerance << endl;
240        Debug << "max leaves: " << mTermMaxLeaves << endl;
241        Debug << "randomize: " << randomize << endl;
242        Debug << "min global cost ratio: " << mTermMinGlobalCostRatio << endl;
243        Debug << "global cost miss tolerance: " << mTermGlobalCostMissTolerance << endl;
244        Debug << "only driving axis: " << mOnlyDrivingAxis << endl;
245        Debug << "max memory: " << mMaxMemory << endl;
246        Debug << "use cost heuristics: " << mUseCostHeuristics << endl;
247        Debug << "subdivision stats log: " << subdivisionStatsLog << endl;
248        Debug << "split borders: " << mSplitBorder << endl;
249        Debug << "render cost decrease weight: " << mRenderCostDecreaseWeight << endl;
250        Debug << "use global sort: " << mUseGlobalSorting << endl;
251        Debug << endl;
252}
253
254
255static void AssociateObjectsWithLeaf(BvhLeaf *leaf)
256{
257        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
258        for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
259        {
260                (*oit)->mBvhLeaf = leaf;
261        }
262}
263
264
265BvhInterior *BvHierarchy::SubdivideNode(const BvhSubdivisionCandidate &sc,
266                                                                                BvhTraversalData &frontData,
267                                                                                BvhTraversalData &backData)
268{
269        const BvhTraversalData &tData = sc.mParentData;
270        BvhLeaf *leaf = tData.mNode;
271    mBvhStats.nodes += 2; // we have two new leaves
272
273        // add the new nodes to the tree
274        BvhInterior *node = new BvhInterior(tData.mBoundingBox, leaf->GetParent());
275       
276
277        ///////////////////////////////////////////////////////////////////
278        //-- fill  front and back traversal data with the new values
279
280        frontData.mDepth = backData.mDepth = tData.mDepth + 1;
281
282        frontData.mBoundingBox = ComputeBoundingBox(sc.mFrontObjects, &tData.mBoundingBox);
283        backData.mBoundingBox = ComputeBoundingBox(sc.mBackObjects, &tData.mBoundingBox);
284       
285
286        ////////////////////////////////
287        //-- create front and back leaf
288
289        BvhLeaf *back =
290                new BvhLeaf(backData.mBoundingBox, node, (int)sc.mBackObjects.size());
291        BvhLeaf *front =
292                new BvhLeaf(frontData.mBoundingBox, node, (int)sc.mFrontObjects.size());
293
294        BvhInterior *parent = leaf->GetParent();
295
296        // replace a link from node's parent
297        if (parent)
298        {
299                parent->ReplaceChildLink(leaf, node);
300                node->SetParent(parent);
301        }
302        else // no parent => this node is the root
303        {
304                mRoot = node;
305        }
306
307        // and setup child links
308        node->SetupChildLinks(front, back);
309
310        ++ mBvhStats.splits;
311
312        ////////////////////////////////////
313        //-- fill traversal data
314
315        frontData.mNode = front;
316        backData.mNode = back;
317
318        back->mObjects = sc.mBackObjects;
319        front->mObjects = sc.mFrontObjects;
320
321        AssociateObjectsWithLeaf(back);
322        AssociateObjectsWithLeaf(front);
323   
324        // compute probability of this node being visible,
325        // i.e., volume of the view cells that can see this node
326        frontData.mProbability = EvalViewCellsVolume(sc.mFrontObjects);
327        backData.mProbability = EvalViewCellsVolume(sc.mBackObjects);
328
329    // how often was max cost ratio missed in this branch?
330        frontData.mMaxCostMisses = sc.mMaxCostMisses;
331        backData.mMaxCostMisses = sc.mMaxCostMisses;
332       
333        // assign the objects in sorted order
334        if (mUseGlobalSorting)
335        {
336                AssignSortedObjects(sc, frontData, backData);
337        }
338       
339        // return the new interior node
340        return node;
341}
342
343
344BvhNode *BvHierarchy::Subdivide(SplitQueue &tQueue,
345                                                                SubdivisionCandidate *splitCandidate,
346                                                                const bool globalCriteriaMet)
347{
348        BvhSubdivisionCandidate *sc =
349                dynamic_cast<BvhSubdivisionCandidate *>(splitCandidate);
350        BvhTraversalData &tData = sc->mParentData;
351
352        BvhNode *currentNode = tData.mNode;
353
354        if (!LocalTerminationCriteriaMet(tData) && !globalCriteriaMet)
355        {       
356                //////////////////////////////////////////
357                //-- continue subdivision
358
359                BvhTraversalData tFrontData;
360                BvhTraversalData tBackData;
361                       
362                // create new interior node and two leaf node
363                currentNode = SubdivideNode(
364                        *sc,
365                        tFrontData,
366                        tBackData);
367       
368                // decrease the weighted average cost of the subdivisoin
369                mTotalCost -= sc->GetRenderCostDecrease();
370
371                // subdivision statistics
372                if (1) PrintSubdivisionStats(*sc);
373
374
375                /////////////////////////////////////////
376                //-- push the new split candidates on the queue
377               
378                BvhSubdivisionCandidate *frontCandidate =
379                        new BvhSubdivisionCandidate(tFrontData);
380                BvhSubdivisionCandidate *backCandidate =
381                        new BvhSubdivisionCandidate(tBackData);
382
383                EvalSubdivisionCandidate(*frontCandidate);
384                EvalSubdivisionCandidate(*backCandidate);
385       
386                // cross reference
387                tFrontData.mNode->SetSubdivisionCandidate(frontCandidate);
388                tBackData.mNode->SetSubdivisionCandidate(backCandidate);
389
390                Debug << "leaf: " << tFrontData.mNode << " setting f candidate: "
391                          << tFrontData.mNode->GetSubdivisionCandidate() << " type: "
392                          << tFrontData.mNode->GetSubdivisionCandidate()->Type() << endl;
393
394                Debug << "leaf: " << tBackData.mNode << " setting b candidate: "
395                          << tBackData.mNode->GetSubdivisionCandidate() << " type: "
396                          << tBackData.mNode->GetSubdivisionCandidate()->Type() << endl;
397               
398                tQueue.Push(frontCandidate);
399                tQueue.Push(backCandidate);
400        }
401
402        /////////////////////////////////
403        //-- node is a leaf => terminate traversal
404
405        if (currentNode->IsLeaf())
406        {
407                //////////////////////////////////////
408                //-- store additional info
409                EvaluateLeafStats(tData);
410       
411                const bool mStoreRays = true;
412                if (mStoreRays)
413                {
414                        BvhLeaf *leaf = dynamic_cast<BvhLeaf *>(currentNode);
415                        CollectRays(leaf->mObjects, leaf->mVssRays);
416                }
417               
418                //////////////////////////////////////
419               
420                // this leaf is no candidate for splitting anymore
421                // => detach subdivision candidate
422                tData.mNode->SetSubdivisionCandidate(NULL);
423                // detach node so we don't delete it with the traversal data
424                tData.mNode = NULL;
425        }
426       
427        return currentNode;
428}
429
430
431void BvHierarchy::EvalSubdivisionCandidate(BvhSubdivisionCandidate &splitCandidate)
432{
433        // compute best object partition
434        const float ratio =     SelectObjectPartition(
435                                                        splitCandidate.mParentData,
436                                                        splitCandidate.mFrontObjects,
437                                                        splitCandidate.mBackObjects);
438       
439        BvhLeaf *leaf = splitCandidate.mParentData.mNode;
440
441        // cost ratio violated?
442        const bool maxCostRatioViolated = mTermMaxCostRatio < ratio;
443
444        splitCandidate.mMaxCostMisses = maxCostRatioViolated ?
445                splitCandidate.mParentData.mMaxCostMisses + 1 :
446                splitCandidate.mParentData.mMaxCostMisses;
447
448        const float viewSpaceVol = mVspTree->GetBoundingBox().GetVolume();
449        const float oldProp = EvalViewCellsVolume(leaf->mObjects);
450
451        const float oldRenderCost = oldProp * (float)leaf->mObjects.size() / viewSpaceVol;
452
453        // compute global decrease in render cost
454        float newRenderCost = EvalRenderCost(splitCandidate.mParentData,
455                                                                             splitCandidate.mFrontObjects,
456                                                                                 splitCandidate.mBackObjects);
457
458        newRenderCost /=  viewSpaceVol;
459        const float renderCostDecr = oldRenderCost - newRenderCost;
460
461        Debug << "\nbvh render cost decr: " << renderCostDecr << endl;
462        splitCandidate.SetRenderCostDecrease(renderCostDecr);
463
464#if 0
465        const float priority = (float)-splitCandidate.mParentData.mDepth;
466#else   
467        // take render cost of node into account
468        // otherwise danger of being stuck in a local minimum!!
469        const float factor = mRenderCostDecreaseWeight;
470        const float priority = factor * renderCostDecr + (1.0f - factor) * oldRenderCost;
471#endif
472
473        // compute global decrease in render cost
474        splitCandidate.SetPriority(priority);
475}
476
477
478inline bool BvHierarchy::LocalTerminationCriteriaMet(const BvhTraversalData &data) const
479{
480        // matt: TODO
481        return ( 0
482                //|| ((int)data.mNode->mObjects.size() < mTermMinObjects)
483                //|| (data.mProbability <= mTermMinProbability)
484                //|| (data.mDepth >= mTermMaxDepth)
485                 );
486}
487
488
489inline bool BvHierarchy::GlobalTerminationCriteriaMet(const BvhTraversalData &data) const
490{
491        // matt: TODO
492        return (0
493                || (mBvhStats.Leaves() >= mTermMaxLeaves)
494                //|| (mGlobalCostMisses >= mTermGlobalCostMissTolerance)
495                //|| mOutOfMemory
496                );
497}
498
499
500void BvHierarchy::EvaluateLeafStats(const BvhTraversalData &data)
501{
502        // the node became a leaf -> evaluate stats for leafs
503        BvhLeaf *leaf = data.mNode;
504       
505        ++ mCreatedLeaves;
506
507        if (data.mDepth >= mTermMaxDepth)
508        {
509        ++ mBvhStats.maxDepthNodes;
510                //Debug << "new max depth: " << mVspStats.maxDepthNodes << endl;
511        }
512
513        if (data.mDepth < mTermMaxDepth)
514        {
515        ++ mBvhStats.minDepthNodes;
516        }
517
518        if (data.mProbability <= mTermMinProbability)
519                ++ mBvhStats.minProbabilityNodes;
520       
521        // accumulate depth to compute average depth
522        mBvhStats.accumDepth += data.mDepth;
523 
524        if ((int)(leaf->mObjects.size()) < mTermMinObjects)
525             ++ mBvhStats.minObjectsNodes;
526 
527        if ((int)(leaf->mObjects.size()) > mBvhStats.maxObjectRefs)
528                mBvhStats.maxObjectRefs = (int)leaf->mObjects.size();
529}
530
531
532#if 0
533float BvHierarchy::EvalLocalObjectPartition(const BvhTraversalData &tData,
534                                                                                        const int axis,
535                                                                                        ObjectContainer &objectsFront,
536                                                                                        ObjectContainer &objectsBack)
537{
538        const float maxBox = tData.mBoundingBox.Max(axis);
539        const float minBox = tData.mBoundingBox.Min(axis);
540
541        float midPoint = (maxBox + minBox) * 0.5f;
542
543        ObjectContainer::const_iterator oit, oit_end = tData.mNode->mObjects.end();
544       
545        for (oit = tData.mNode->mObjects.begin(); oit != oit_end; ++ oit)
546        {
547                Intersectable *obj = *oit;
548                const AxisAlignedBox3 box = obj->GetBox();
549
550                const float objMid = (box.Max(axis) + box.Min(axis)) * 0.5f;
551
552                // object mailed => belongs to back objects
553                if (objMid < midPoint)
554                        objectsBack.push_back(obj);
555                else
556                        objectsFront.push_back(obj);
557        }
558
559        const float oldRenderCost = tData.mProbability * (float)tData.mNode->mObjects.size();
560        const float newRenderCost =
561                EvalRenderCost(tData, objectsFront, objectsBack);
562
563        const float ratio = newRenderCost / oldRenderCost;
564        return ratio;
565}
566
567#else
568
569float BvHierarchy::EvalLocalObjectPartition(const BvhTraversalData &tData,
570                                                                                        const int axis,
571                                                                                        ObjectContainer &objectsFront,
572                                                                                        ObjectContainer &objectsBack)
573{
574        PrepareLocalSubdivisionCandidates(tData, axis);
575       
576        SortableEntryContainer::const_iterator cit, cit_end = mSubdivisionCandidates->end();
577
578        int i = 0;
579        const int border = (int)tData.mNode->mObjects.size() / 2;
580
581    for (cit = mSubdivisionCandidates->begin(); cit != cit_end; ++ cit, ++ i)
582        {
583                Intersectable *obj = (*cit).mObject;
584
585                // object mailed => belongs to back objects
586                if (i < border)
587                        objectsBack.push_back(obj);
588                else
589                        objectsFront.push_back(obj);
590        }
591
592        const float oldProp = EvalViewCellsVolume(tData.mNode->mObjects);
593        //const float oldProp2 = tData.mProbability;
594
595        const float oldRenderCost = oldProp * (float)tData.mNode->mObjects.size();
596        const float newRenderCost = EvalRenderCost(tData, objectsFront, objectsBack);
597
598        const float ratio = newRenderCost / oldRenderCost;
599        return ratio;
600}
601#endif
602
603
604float BvHierarchy::EvalSah(const BvhTraversalData &tData,
605                                                   const int axis,
606                                                   ObjectContainer &objectsFront,
607                                                   ObjectContainer &objectsBack)
608{
609        PrepareLocalSubdivisionCandidates(tData, axis);
610 
611        // go through the lists, count the number of objects left and right
612        // and evaluate the following cost funcion:
613        // C = ct_div_ci  + (ol + or)/queries
614        int objectsLeft = 0, objectsRight = (int)tData.mNode->mObjects.size();
615 
616        AxisAlignedBox3 box = tData.mNode->GetBoundingBox();
617
618        float minBox = box.Min(axis);
619        float maxBox = box.Max(axis);
620        float boxArea = box.SurfaceArea();
621
622        float minSum = 1e20f;
623 
624        vector<float> bordersRight;
625        bordersRight.resize(mSubdivisionCandidates->size());
626
627        float minBorder = maxBox;
628        float maxBorder = minBox;
629
630        SortableEntryContainer::const_iterator currentPos =
631                mSubdivisionCandidates->begin();
632
633        SortableEntryContainer::reverse_iterator rcit =
634                mSubdivisionCandidates->rbegin(), rcit_end = mSubdivisionCandidates->rend();
635               
636        vector<float>::reverse_iterator rbit = bordersRight.rbegin();
637       
638        for (; rcit != rcit_end; ++ rcit, ++ rbit)
639        {
640                Intersectable *obj = (*rcit).mObject;
641                const AxisAlignedBox3 box = obj->GetBox();
642
643                if (box.Min() < minBorder)
644                        minBorder = box.Min(axis);
645               
646                (*rbit) = minBorder;
647        }
648
649        vector<float>::const_iterator bit = bordersRight.begin();
650
651        SortableEntryContainer::const_iterator cit, cit_end = mSubdivisionCandidates->end();
652        for (cit = mSubdivisionCandidates->begin(); cit != cit_end; ++ cit, ++ bit)
653        {
654                Intersectable *obj = (*cit).mObject;
655
656                ++ objectsLeft;
657                -- objectsRight;
658
659                AxisAlignedBox3 lbox = box;
660                AxisAlignedBox3 rbox = box;
661       
662                const AxisAlignedBox3 obox = obj->GetBox();
663
664                if (obox.Max(axis) > maxBorder)
665                        maxBorder = obox.Max(axis);
666
667        lbox.SetMax(axis, maxBorder);
668                rbox.SetMin(axis, *bit);
669       
670                const float sum = objectsLeft * lbox.SurfaceArea() + objectsRight * rbox.SurfaceArea();
671     
672            // cout<<"pos="<<(*ci).value<<"\t q=("<<ql<<","<<qr<<")\t r=("<<rl<<","<<rr<<")"<<endl;
673            // cout<<"cost= "<<sum<<endl;
674     
675                if (sum < minSum)
676                {
677                        minSum = sum;   
678                        // objects belongs to left side now
679                        for (; currentPos != (cit + 1); ++ currentPos);
680                }
681        }
682
683        //-- assign object to front and back volume
684
685        // belongs to back bv
686        for (cit = mSubdivisionCandidates->begin(); cit != currentPos; ++ cit)
687                objectsBack.push_back((*cit).mObject);
688       
689        // belongs to front bv
690        for (cit = currentPos; cit != cit_end; ++ cit)
691                objectsFront.push_back((*cit).mObject);
692
693        float oldCost = (float)tData.mNode->mObjects.size();
694        float newCost = minSum / boxArea;
695        float ratio = newCost / oldCost;
696 
697#if 0
698  cout<<"===================="<<endl;
699  cout<<"costRatio="<<ratio<<" pos="<<position<<" t="<<(position - minBox)/(maxBox - minBox)
700      <<"\t o=("<<objectsBack<<","<<objectsFront<<")"<<endl;
701#endif
702  return ratio;
703}
704
705
706static bool PrepareOutput(const int axis,
707                                                  const int leaves,
708                                                  ofstream &sumStats,
709                                                  ofstream &vollStats,
710                                                  ofstream &volrStats)
711{
712        if ((axis == 0) && (leaves > 0) && (leaves < 90))
713        {
714                char str[64];   
715                sprintf(str, "tmp/bvh_heur_sum-%04d.log", leaves);
716                sumStats.open(str);
717                sprintf(str, "tmp/bvh_heur_voll-%04d.log", leaves);
718                vollStats.open(str);
719                sprintf(str, "tmp/bvh_heur_volr-%04d.log", leaves);
720                volrStats.open(str);
721        }
722
723        return sumStats.is_open() && vollStats.is_open() && volrStats.is_open();
724}
725
726
727static void PrintHeuristics(const int objectsRight,
728                                                        const float sum,
729                                                        const float volLeft,
730                                                        const float volRight,
731                                                        const float viewSpaceVol,
732                                                        ofstream &sumStats,
733                                                        ofstream &vollStats,
734                                                        ofstream &volrStats)
735{
736        sumStats
737                << "#Position\n" << objectsRight << endl
738                << "#Sum\n" << sum / viewSpaceVol << endl
739                << "#Vol\n" << (volLeft +  volRight) / viewSpaceVol << endl;
740
741        vollStats
742                << "#Position\n" << objectsRight << endl
743                << "#Vol\n" << volLeft / viewSpaceVol << endl;
744
745        volrStats
746                << "#Position\n" << objectsRight << endl
747                << "#Vol\n" << volRight / viewSpaceVol << endl;
748}
749
750
751float BvHierarchy::EvalLocalCostHeuristics(const BvhTraversalData &tData,
752                                                                                   const int axis,
753                                                                                   ObjectContainer &objectsFront,
754                                                                                   ObjectContainer &objectsBack)
755{
756        ////////////////////////////////////////////////////////////////
757        // go through the lists, count the number of objects left and right
758        // and evaluate the cost funcion
759
760        // prepare the heuristics by setting mailboxes and counters.
761        const float totalVol = PrepareHeuristics(tData, axis);
762       
763        // local helper variables
764        float volLeft = 0;
765        float volRight = totalVol;
766        int nObjectsLeft = 0;
767        const int nTotalObjects = (int)tData.mNode->mObjects.size();
768        const float viewSpaceVol = mVspTree->GetBoundingBox().GetVolume();
769
770        SortableEntryContainer::const_iterator backObjectsStart = mSubdivisionCandidates->begin();
771
772        /////////////////////////////////
773        //-- the parameters for the current optimum
774
775        float volBack = volLeft;
776        float volFront = volRight;
777        float newRenderCost = nTotalObjects * totalVol;
778
779#ifdef _DEBUG
780        ofstream sumStats;
781        ofstream vollStats;
782        ofstream volrStats;
783
784        const bool printStats =
785                PrepareOutput(axis, mBvhStats.Leaves(), sumStats, vollStats, volrStats);
786#endif
787
788        ///////////////////////////////////////////////////
789        //-- the sweep heuristics
790        //-- traverse through events and find best split plane
791
792        SortableEntryContainer::const_iterator cit, cit_end = cit_end = mSubdivisionCandidates->end();
793
794        for (cit = mSubdivisionCandidates->begin(); cit != cit_end; ++ cit)
795        {
796                Intersectable *object = (*cit).mObject;
797               
798                // evaluate change in l and r volume
799                // voll = view cells that see only left node (i.e., left pvs)
800                // volr = view cells that see only right node (i.e., right pvs)
801                EvalHeuristicsContribution(object, volLeft, volRight);
802
803                ++ nObjectsLeft;
804                const int nObjectsRight = nTotalObjects - nObjectsLeft;
805
806                // the heuristics
807            const float sum = volLeft * (float)nObjectsLeft +
808                                                  volRight * (float)nObjectsRight;
809
810#ifdef _DEBUG
811                if (printStats)
812                {
813                        PrintHeuristics(nObjectsRight, sum, volLeft, volRight, viewSpaceVol,
814                                                        sumStats, vollStats, volrStats);
815                }
816#endif
817
818                if (sum < newRenderCost)
819                {
820                        newRenderCost = sum;
821
822                        volBack = volLeft;
823                        volFront = volRight;
824
825                        // objects belongs to left side now
826                        for (; backObjectsStart != (cit + 1); ++ backObjectsStart);
827                }
828        }
829
830        ////////////////////////////////////////////
831        //-- assign object to front and back volume
832
833        // belongs to back bv
834        for (cit = mSubdivisionCandidates->begin(); cit != backObjectsStart; ++ cit)
835        {
836                objectsBack.push_back((*cit).mObject);
837        }
838        // belongs to front bv
839        for (cit = backObjectsStart; cit != cit_end; ++ cit)
840        {
841                objectsFront.push_back((*cit).mObject);
842        }
843
844        // render cost of the old parent
845        const float oldRenderCost = (float)nTotalObjects * totalVol + Limits::Small;
846        // the relative cost ratio
847        const float ratio = newRenderCost / oldRenderCost;
848
849#ifdef _DEBUG
850        Debug << "\n§§§§ eval local cost §§§§" << endl
851                  << "back pvs: " << (int)objectsBack.size() << " front pvs: " << (int)objectsFront.size() << " total pvs: " << nTotalObjects << endl
852                  << "back p: " << volBack / viewSpaceVol << " front p " << volFront / viewSpaceVol << " p: " << totalVol / viewSpaceVol << endl
853                  << "old rc: " << oldRenderCost / viewSpaceVol << " new rc: " << newRenderCost / viewSpaceVol << endl
854                  << "render cost decrease: " << oldRenderCost / viewSpaceVol - newRenderCost / viewSpaceVol << endl;
855#endif
856
857        return ratio;
858}
859
860
861void BvHierarchy::PrepareLocalSubdivisionCandidates(const BvhTraversalData &tData,
862                                                                                                        const int axis)                                                                                 
863{
864        //-- insert object queries
865        ObjectContainer *objects;
866
867        if (!mUseGlobalSorting)
868                objects = &tData.mNode->mObjects;
869        else
870                objects = tData.mSortedObjects[axis];
871       
872        CreateLocalSubdivisionCandidates(*objects, &mSubdivisionCandidates, mUseGlobalSorting, axis);
873}
874
875
876void BvHierarchy::CreateLocalSubdivisionCandidates(const ObjectContainer &objects,
877                                                                                                  SortableEntryContainer **subdivisionCandidates,
878                                                                                                  const bool sort,
879                                                                                                  const int axis)
880{
881        (*subdivisionCandidates)->clear();
882
883        // compute requested size and look if subdivision candidate has to be recomputed
884        const int requestedSize = (int)objects.size() * 2;
885       
886        // creates a sorted split candidates array
887        if ((*subdivisionCandidates)->capacity() > 500000 &&
888                requestedSize < (int)((*subdivisionCandidates)->capacity() / 10) )
889        {
890        delete (*subdivisionCandidates);
891                (*subdivisionCandidates) = new SortableEntryContainer;
892        }
893
894        (*subdivisionCandidates)->reserve(requestedSize);
895
896        ObjectContainer::const_iterator oit, oit_end = objects.end();
897
898        for (oit = objects.begin(); oit < oit_end; ++ oit)
899        {
900                Intersectable *object = *oit;
901                const AxisAlignedBox3 &box = object->GetBox();
902                const float midPt = (box.Min(axis) + box.Max(axis)) * 0.5f;
903
904                (*subdivisionCandidates)->push_back(SortableEntry(object, midPt));
905        }
906
907        if (sort)
908        {
909                stable_sort((*subdivisionCandidates)->begin(), (*subdivisionCandidates)->end());
910        }
911}
912
913
914const BvhStatistics &BvHierarchy::GetStatistics() const
915{
916        return mBvhStats;
917}
918
919
920float BvHierarchy::PrepareHeuristics(const BvhTraversalData &tData, const int axis)
921{       
922        BvhLeaf *leaf = tData.mNode;
923        float vol = 0;
924
925    // sort so we can use a sweep from right to left
926        PrepareLocalSubdivisionCandidates(tData, axis);
927       
928        // collect and mark the view cells as belonging to front pvs
929        ViewCellContainer viewCells;
930        CollectViewCells(tData.mNode->mObjects, viewCells, true);
931                       
932        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
933        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
934        {
935                vol += (*vit)->GetVolume();
936        }
937
938        // mail the objects on the left side
939        Intersectable::NewMail();
940        // mail view cells on the left side
941        ViewCell::NewMail();
942       
943        return vol;
944}
945///////////////////////////////////////////////////////////
946
947
948void BvHierarchy::EvalHeuristicsContribution(Intersectable *obj,
949                                                                                         float &volLeft,
950                                                                                         float &volRight)
951{
952        // collect all view cells associated with this objects
953        // (also multiple times, if they are pierced by several rays)
954        ViewCellContainer viewCells;
955        const bool useMailboxing = false;
956
957        CollectViewCells(obj, viewCells, useMailboxing);
958
959        // classify view cells and compute volume contri accordingly
960        // possible view cell classifications:
961        // view cell mailed => view cell can be seen from left child node
962        // view cell counter > 0 view cell can be seen from right child node
963        // combined: view cell volume belongs to both nodes
964        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
965       
966        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
967        {
968                // view cells can also be seen from left child node
969                ViewCell *viewCell = *vit;
970
971                const float vol = viewCell->GetVolume();
972
973                if (!viewCell->Mailed())
974                {
975                        viewCell->Mail();
976                        // we now see view cell from both nodes
977                        // => add volume to left node
978                        volLeft += vol;
979                }
980
981                // last reference into the right node
982                if (-- viewCell->mCounter == 0)
983                {       
984                        // view cell was previously seen from both nodes  =>
985                        // remove volume from right node
986                        volRight -= vol;
987                }
988        }
989}
990
991
992void BvHierarchy::SetViewCellsManager(ViewCellsManager *vcm)
993{
994        mViewCellsManager = vcm;
995}
996
997
998AxisAlignedBox3 BvHierarchy::GetBoundingBox() const
999{
1000        return mBoundingBox;
1001}
1002
1003
1004float BvHierarchy::SelectObjectPartition(const BvhTraversalData &tData,
1005                                                                                 ObjectContainer &frontObjects,
1006                                                                                 ObjectContainer &backObjects)
1007{
1008        ObjectContainer nFrontObjects[3];
1009        ObjectContainer nBackObjects[3];
1010
1011        float nCostRatio[3];
1012
1013        // create bounding box of node geometry
1014        AxisAlignedBox3 box = tData.mBoundingBox;
1015               
1016        int sAxis = 0;
1017        int bestAxis = -1;
1018
1019        if (mOnlyDrivingAxis)
1020        {
1021                sAxis = box.Size().DrivingAxis();
1022        }
1023       
1024        ////////////////////////////////////////////
1025        //-- evaluate split cost for all three axis
1026       
1027        for (int axis = 0; axis < 3; ++ axis)
1028        {
1029                if (!mOnlyDrivingAxis || (axis == sAxis))
1030                {
1031                        if (mUseCostHeuristics)
1032                        {
1033                                //-- partition objects using heuristics
1034                                nCostRatio[axis] =
1035                                        EvalLocalCostHeuristics(
1036                                                                                        tData,
1037                                                                                        axis,
1038                                                                                        nFrontObjects[axis],
1039                                                                                        nBackObjects[axis]);
1040                        }
1041                        else
1042                        {
1043                                nCostRatio[axis] =
1044                                        EvalLocalObjectPartition(
1045                                                                                         tData,
1046                                                                                         axis,
1047                                                                                         nFrontObjects[axis],
1048                                                                                         nBackObjects[axis]);
1049                        }
1050
1051                        if (bestAxis == -1)
1052                        {
1053                                bestAxis = axis;
1054                        }
1055                        else if (nCostRatio[axis] < nCostRatio[bestAxis])
1056                        {
1057                                bestAxis = axis;
1058                        }
1059                }
1060        }
1061
1062        /////////////////////////////////////
1063        //-- assign values
1064
1065        frontObjects = nFrontObjects[bestAxis];
1066        backObjects = nBackObjects[bestAxis];
1067
1068        //Debug << "val: " << nCostRatio[bestAxis] << " axis: " << bestAxis << endl;
1069        return nCostRatio[bestAxis];
1070}
1071
1072
1073void BvHierarchy::AssociateObjectsWithRays(const VssRayContainer &rays)
1074{
1075
1076        VssRayContainer::const_iterator rit, rit_end = rays.end();
1077
1078    for (rit = rays.begin(); rit != rays.end(); ++ rit)
1079        {
1080                VssRay *ray = (*rit);
1081
1082                if (ray->mTerminationObject)
1083                {
1084                        ray->mTerminationObject->mVssRays.push_back(ray);
1085                }
1086
1087                if (0 && ray->mOriginObject)
1088                {
1089                        ray->mOriginObject->mVssRays.push_back(ray);
1090                }
1091        }
1092}
1093
1094
1095void BvHierarchy::PrintSubdivisionStats(const SubdivisionCandidate &sc)
1096{
1097        const float costDecr = sc.GetRenderCostDecrease();     
1098
1099        mSubdivisionStats
1100                        << "#Leaves\n" << mBvhStats.Leaves()
1101                        << "#RenderCostDecrease\n" << costDecr << endl
1102                        << "#TotalRenderCost\n" << mTotalCost << endl;
1103                        //<< "#AvgRenderCost\n" << avgRenderCost << endl;
1104}
1105
1106
1107void BvHierarchy::CollectRays(const ObjectContainer &objects,
1108                                                          VssRayContainer &rays) const
1109{
1110        VssRay::NewMail();
1111        ObjectContainer::const_iterator oit, oit_end = objects.end();
1112
1113        // evaluate reverse pvs and view cell volume on left and right cell
1114        // note: should I take all leaf objects or rather the objects hit by rays?
1115        for (oit = objects.begin(); oit != oit_end; ++ oit)
1116        {
1117                Intersectable *obj = *oit;
1118                VssRayContainer::const_iterator rit, rit_end = obj->mVssRays.end();
1119
1120                for (rit = obj->mVssRays.begin(); rit < rit_end; ++ rit)
1121                {
1122                        VssRay *ray = (*rit);
1123
1124                        if (!ray->Mailed())
1125                        {
1126                                ray->Mail();
1127                                rays.push_back(ray);
1128                        }
1129                }
1130        }
1131}
1132
1133
1134float BvHierarchy::EvalRenderCost(const BvhTraversalData &tData,
1135                                                                  const ObjectContainer &objectsFront,
1136                                                                  const ObjectContainer &objectsBack) const
1137{
1138        BvhLeaf *leaf = tData.mNode;
1139
1140        // probability that view point lies in a view cell which sees this node
1141        const float pFront = EvalViewCellsVolume(objectsFront);
1142        const float pBack = EvalViewCellsVolume(objectsBack);
1143               
1144        const int totalObjects = (int)leaf->mObjects.size();
1145        const int nObjectsFront = (int)objectsFront.size();
1146        const int nObjectsBack = (int)objectsBack.size();
1147
1148        //-- pvs rendering heuristics
1149        const float newRenderCost = nObjectsFront * pFront + nObjectsBack * pBack;
1150
1151#ifdef _DEBUG
1152        const float viewSpaceVol = mVspTree->GetBoundingBox().GetVolume();
1153        Debug << "\nbvh render cost\n"
1154                  << "back p: " << pBack / viewSpaceVol << " front p " << pFront / viewSpaceVol << endl
1155                  << "new rc: " << newRenderCost / viewSpaceVol << endl;*/
1156#endif
1157
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]->reserve((int)sc.mFrontObjects.size());
1599                backData.mSortedObjects[i]->reserve((int)sc.mFrontObjects.size());
1600
1601                ObjectContainer::const_iterator oit, oit_end = sc.mParentData.mNode->mObjects.end();
1602
1603                for (oit = sc.mParentData.mNode->mObjects.begin(); oit != oit_end; ++ oit)
1604                {
1605                        if ((*oit)->Mailed())
1606                        {
1607                                frontData.mSortedObjects[i]->push_back(*oit);
1608                        }
1609                        else
1610                        {
1611                                backData.mSortedObjects[i]->push_back(*oit);
1612                        }
1613                }
1614        }
1615}
1616
1617
1618void BvhStatistics::Print(ostream &app) const
1619{
1620        app << "=========== BvHierarchy statistics ===============\n";
1621
1622        app << setprecision(4);
1623
1624        app << "#N_CTIME  ( Construction time [s] )\n" << Time() << " \n";
1625
1626        app << "#N_NODES ( Number of nodes )\n" << nodes << "\n";
1627
1628        app << "#N_INTERIORS ( Number of interior nodes )\n" << Interior() << "\n";
1629
1630        app << "#N_LEAVES ( Number of leaves )\n" << Leaves() << "\n";
1631
1632        app << "#AXIS_ALIGNED_SPLITS (number of axis aligned splits)\n" << splits << endl;
1633
1634        app << "#N_PMINDEPTHLEAVES ( Percentage of leaves at minimum depth )\n"
1635                <<      minDepthNodes * 100 / (double)Leaves() << endl;
1636
1637        app << "#N_PMAXDEPTHLEAVES ( Percentage of leaves at maximum depth )\n"
1638                <<      maxDepthNodes * 100 / (double)Leaves() << endl;
1639
1640        app << "#N_MAXCOSTNODES  ( Percentage of leaves with terminated because of max cost ratio )\n"
1641                << maxCostNodes * 100 / (double)Leaves() << endl;
1642
1643        app << "#N_PMINPROBABILITYLEAVES  ( Percentage of leaves with mininum probability )\n"
1644                << minProbabilityNodes * 100 / (double)Leaves() << endl;
1645
1646        app << "#N_PMINOBJECTSLEAVES  ( Percentage of leaves with mininum objects )\n"
1647                << minObjectsNodes * 100 / (double)Leaves() << endl;
1648
1649        app << "#N_PMAXDEPTH ( Maximal reached depth )\n" << maxDepth << endl;
1650
1651        app << "#N_PMINDEPTH ( Minimal reached depth )\n" << minDepth << endl;
1652
1653        app << "#AVGDEPTH ( average depth )\n" << AvgDepth() << endl;
1654
1655        app << "#N_INVALIDLEAVES (number of invalid leaves )\n" << invalidLeaves << endl;
1656
1657        app << "#N_MAXOBJECTREFS  ( Max number of object refs / leaf )\n" << maxObjectRefs << "\n";
1658
1659        //app << "#N_RAYS (number of rays / leaf)\n" << AvgRays() << endl;
1660       
1661        app << "========== END OF VspTree statistics ==========\n";
1662}
1663
1664
1665}
Note: See TracBrowser for help on using the repository browser.