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

Revision 1379, 48.2 KB checked in by mattausch, 18 years ago (diff)

fixed sah for objeect partition
loader for single triangles also for x3d

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