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

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