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

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