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

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