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

Revision 1370, 47.8 KB checked in by mattausch, 18 years ago (diff)

debugged global sorting, worked on object-viewspace subdivision

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