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

Revision 1633, 54.1 KB checked in by mattausch, 18 years ago (diff)

worked on gradient method for vsposp

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