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

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