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

Revision 1749, 65.7 KB checked in by mattausch, 18 years ago (diff)

removed bug from exportviewcells

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