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

Revision 1684, 59.0 KB checked in by mattausch, 18 years ago (diff)

found constant for ratio

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