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

Revision 1303, 36.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
20
21namespace GtpVisibilityPreprocessor {
22
23
24#define USE_FIXEDPOINT_T 0
25
26static float debugVol = 0;
27
28int BvhNode::sMailId = 10000;//2147483647;
29int BvhNode::sReservedMailboxes = 1;
30
31BvHierarchy *BvHierarchy::BvhSubdivisionCandidate::sBvHierarchy = NULL;
32
33
34inline static bool ilt(Intersectable *obj1, Intersectable *obj2)
35{
36        return obj1->mId < obj2->mId;
37}
38
39
40/***************************************************************/
41/*              class BvhNode implementation                   */
42/***************************************************************/
43
44BvhNode::BvhNode(): mParent(NULL), mMailbox(0)
45{
46}
47
48BvhNode::BvhNode(const AxisAlignedBox3 &bbox):
49mParent(NULL), mBoundingBox(bbox), mMailbox(0)
50{
51}
52
53
54BvhNode::BvhNode(const AxisAlignedBox3 &bbox, BvhInterior *parent):
55mBoundingBox(bbox), mParent(parent), mMailbox(0)
56{
57}
58
59
60bool BvhNode::IsRoot() const
61{
62        return mParent == NULL;
63}
64
65
66BvhInterior *BvhNode::GetParent()
67{
68        return mParent;
69}
70
71
72void BvhNode::SetParent(BvhInterior *parent)
73{
74        mParent = parent;
75}
76
77
78
79/******************************************************************/
80/*              class BvhInterior implementation                  */
81/******************************************************************/
82
83
84BvhLeaf::BvhLeaf(const AxisAlignedBox3 &bbox):
85BvhNode(bbox), mSubdivisionCandidate(NULL)
86{
87}
88
89
90BvhLeaf::BvhLeaf(const AxisAlignedBox3 &bbox, BvhInterior *parent):
91BvhNode(bbox, parent)
92{
93}
94
95
96BvhLeaf::BvhLeaf(const AxisAlignedBox3 &bbox,
97                                 BvhInterior *parent,
98                                 const int numObjects):
99BvhNode(bbox, parent)
100{
101        mObjects.reserve(numObjects);
102}
103
104
105bool BvhLeaf::IsLeaf() const
106{
107        return true;
108}
109
110
111BvhLeaf::~BvhLeaf()
112{
113}
114
115
116/******************************************************************/
117/*              class BvhInterior implementation                  */
118/******************************************************************/
119
120
121BvhInterior::BvhInterior(const AxisAlignedBox3 &bbox):
122BvhNode(bbox), mFront(NULL), mBack(NULL)
123{
124}
125
126
127BvhInterior::BvhInterior(const AxisAlignedBox3 &bbox, BvhInterior *parent):
128BvhNode(bbox, parent), mFront(NULL), mBack(NULL)
129{
130}
131
132
133void BvhInterior::ReplaceChildLink(BvhNode *oldChild, BvhNode *newChild)
134{
135        if (mBack == oldChild)
136                mBack = newChild;
137        else
138                mFront = newChild;
139}
140
141
142bool BvhInterior::IsLeaf() const
143{
144        return false;
145}
146
147
148BvhInterior::~BvhInterior()
149{
150        DEL_PTR(mFront);
151        DEL_PTR(mBack);
152}
153
154
155void BvhInterior::SetupChildLinks(BvhNode *front, BvhNode *back)
156{
157    mBack = back;
158    mFront = front;
159}
160
161
162
163/*******************************************************************/
164/*                  class BvHierarchy implementation               */
165/*******************************************************************/
166
167
168BvHierarchy::BvHierarchy():
169mRoot(NULL),
170mTimeStamp(1)
171{
172        ReadEnvironment();
173        mSubdivisionCandidates = new vector<SortableEntry>;
174}
175
176
177BvHierarchy::~BvHierarchy()
178{
179        // delete kd intersectables
180        BvhIntersectableMap::iterator it, it_end = mBvhIntersectables.end();
181
182        for (it = mBvhIntersectables.begin(); it != mBvhIntersectables.end(); ++ it)
183        {
184                DEL_PTR((*it).second);
185        }
186
187        DEL_PTR(mSubdivisionCandidates);
188
189        mSubdivisionStats.close();
190}
191
192
193void BvHierarchy::ReadEnvironment()
194{
195        bool randomize = false;
196        Environment::GetSingleton()->GetBoolValue("VspTree.Construction.randomize", randomize);
197        if (randomize)
198                Randomize(); // initialise random generator for heuristics
199
200        //-- termination criteria for autopartition
201        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.maxDepth", mTermMaxDepth);
202        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.maxLeaves", mTermMaxLeaves);
203        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.minObjects", mTermMinObjects);
204        Environment::GetSingleton()->GetFloatValue("BvHierarchy.Termination.minProbability", mTermMinProbability);
205       
206        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.missTolerance", mTermMissTolerance);
207       
208        //-- max cost ratio for early tree termination
209        Environment::GetSingleton()->GetFloatValue("BvHierarchy.Termination.maxCostRatio", mTermMaxCostRatio);
210
211        Environment::GetSingleton()->GetFloatValue("BvHierarchy.Termination.minGlobalCostRatio",
212                mTermMinGlobalCostRatio);
213        Environment::GetSingleton()->GetIntValue("BvHierarchy.Termination.globalCostMissTolerance",
214                mTermGlobalCostMissTolerance);
215
216        //-- factors for bsp tree split plane heuristics
217
218        // if only the driving axis is used for axis aligned split
219        Environment::GetSingleton()->GetBoolValue("BvHierarchy.splitUseOnlyDrivingAxis", mOnlyDrivingAxis);
220        Environment::GetSingleton()->GetFloatValue("BvHierarchy.maxStaticMemory", mMaxMemory);
221        Environment::GetSingleton()->GetBoolValue("BvHierarchy.useCostHeuristics", mUseCostHeuristics);
222
223        char subdivisionStatsLog[100];
224        Environment::GetSingleton()->GetStringValue("BvHierarchy.subdivisionStats", subdivisionStatsLog);
225        mSubdivisionStats.open(subdivisionStatsLog);
226
227        Environment::GetSingleton()->GetFloatValue(
228                "BvHierarchy.Construction.renderCostDecreaseWeight", mRenderCostDecreaseWeight);
229       
230
231        //-- debug output
232
233        Debug << "******* Bvh hierarchy options ******** " << endl;
234    Debug << "max depth: " << mTermMaxDepth << endl;
235        Debug << "min probabiliy: " << mTermMinProbability<< endl;
236        Debug << "min objects: " << mTermMinObjects << endl;
237        Debug << "max cost ratio: " << mTermMaxCostRatio << endl;
238        Debug << "miss tolerance: " << mTermMissTolerance << endl;
239        Debug << "max leaves: " << mTermMaxLeaves << endl;
240        Debug << "randomize: " << randomize << endl;
241        Debug << "min global cost ratio: " << mTermMinGlobalCostRatio << endl;
242        Debug << "global cost miss tolerance: " << mTermGlobalCostMissTolerance << endl;
243        Debug << "only driving axis: " << mOnlyDrivingAxis << endl;
244        Debug << "max memory: " << mMaxMemory << endl;
245        Debug << "use cost heuristics: " << mUseCostHeuristics << endl;
246        Debug << "subdivision stats log: " << subdivisionStatsLog << endl;
247       
248        Debug << "split borders: " << mSplitBorder << endl;
249        Debug << "render cost decrease weight: " << mRenderCostDecreaseWeight << endl;
250        Debug << endl;
251}
252
253
254void AssociateObjectsWithLeaf(BvhLeaf *leaf)
255{
256        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
257        for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
258        {
259                (*oit)->mBvhLeaf = leaf;
260        }
261}
262
263
264BvhInterior *BvHierarchy::SubdivideNode(const ObjectContainer &frontObjects,
265                                                                                const ObjectContainer &backObjects,
266                                                                                const BvhTraversalData &tData,
267                                                                                BvhTraversalData &frontData,
268                                                                                BvhTraversalData &backData)
269{
270        BvhLeaf *leaf = tData.mNode;
271       
272        // two new leaves
273    mBvhStats.nodes += 2;
274
275        // add the new nodes to the tree
276        BvhInterior *node = new BvhInterior(tData.mBoundingBox, leaf->GetParent());
277       
278
279        //-- the front and back traversal data is filled with the new values
280
281        frontData.mDepth = backData.mDepth = tData.mDepth + 1;
282
283        frontData.mBoundingBox = ComputeBoundingBox(frontObjects, &tData.mBoundingBox);
284        backData.mBoundingBox = ComputeBoundingBox(backObjects, &tData.mBoundingBox);
285       
286        /////////////
287        //-- create front and back leaf
288
289        BvhLeaf *back =
290                new BvhLeaf(backData.mBoundingBox, node, (int)backObjects.size());
291        BvhLeaf *front =
292                new BvhLeaf(frontData.mBoundingBox, node, (int)frontObjects.size());
293
294        BvhInterior *parent = leaf->GetParent();
295
296
297        // replace a link from node's parent
298        if (parent)
299        {
300                parent->ReplaceChildLink(leaf, node);
301                node->SetParent(parent);
302        }
303        else // new root
304        {
305                mRoot = node;
306        }
307
308        // and setup child links
309        node->SetupChildLinks(front, back);
310
311        ++ mBvhStats.splits;
312
313
314        ////////////////////////////////////
315
316        frontData.mNode = front;
317        backData.mNode = back;
318
319        back->mObjects = backObjects;
320        front->mObjects = frontObjects;
321
322        AssociateObjectsWithLeaf(back);
323        AssociateObjectsWithLeaf(front);
324   
325        // compute probability, i.e., volume of seen view cells
326        frontData.mProbability = EvalViewCellsVolume(frontObjects);
327        backData.mProbability = EvalViewCellsVolume(backObjects);
328
329        return node;
330}
331
332
333BvhNode *BvHierarchy::Subdivide(SplitQueue &tQueue,
334                                                                SubdivisionCandidate *splitCandidate,
335                                                                const bool globalCriteriaMet)
336{
337        BvhSubdivisionCandidate *sc =
338                dynamic_cast<BvhSubdivisionCandidate *>(splitCandidate);
339        BvhTraversalData &tData = sc->mParentData;
340
341        BvhNode *newNode = tData.mNode;
342
343        if (!LocalTerminationCriteriaMet(tData) && !globalCriteriaMet)
344        {       
345                //-- continue subdivision
346
347                BvhTraversalData tFrontData;
348                BvhTraversalData tBackData;
349                       
350                // create new interior node and two leaf node
351                newNode = SubdivideNode(sc->mFrontObjects,
352                                                                sc->mBackObjects,
353                                                                tData,
354                                                                tFrontData,
355                                                                tBackData);
356       
357                const int maxCostMisses = sc->mMaxCostMisses;
358
359        // how often was max cost ratio missed in this branch?
360                tFrontData.mMaxCostMisses = maxCostMisses;
361                tBackData.mMaxCostMisses = maxCostMisses;
362               
363                // decrease the weighted average cost of the subdivisoin
364                mTotalCost -= sc->GetRenderCostDecrease();
365
366                // subdivision statistics
367                if (1) PrintSubdivisionStats(*sc);
368
369                //-- push the new split candidates on the queue
370               
371                BvhSubdivisionCandidate *frontCandidate =
372                        new BvhSubdivisionCandidate(tFrontData);
373                BvhSubdivisionCandidate *backCandidate =
374                        new BvhSubdivisionCandidate(tBackData);
375
376                EvalSubdivisionCandidate(*frontCandidate);
377                EvalSubdivisionCandidate(*backCandidate);
378       
379                // cross reference
380                tFrontData.mNode->SetSubdivisionCandidate(frontCandidate);
381                tBackData.mNode->SetSubdivisionCandidate(backCandidate);
382Debug << "here125 candidate: " << tFrontData.mNode->GetSubdivisionCandidate() << " type: " << tFrontData.mNode->GetSubdivisionCandidate()->Type() << endl;
383Debug << "here129 candidate: " << tBackData.mNode->GetSubdivisionCandidate() << " type: " << tBackData.mNode->GetSubdivisionCandidate()->Type() << endl;
384                tQueue.Push(frontCandidate);
385                tQueue.Push(backCandidate);
386
387                // delete old leaf node
388                //DEL_PTR(tData.mNode);
389        }
390
391
392        //-- terminate traversal
393    if (newNode->IsLeaf())
394        {
395                //-- store additional info
396                EvaluateLeafStats(tData);
397       
398                const bool mStoreRays = true;
399                if (mStoreRays)
400                {
401                        BvhLeaf *leaf = dynamic_cast<BvhLeaf *>(newNode);
402                        CollectRays(leaf->mObjects, leaf->mVssRays);
403                }
404
405                // detach node so it won't get deleted
406                tData.mNode = NULL;
407        }
408       
409        return newNode;
410}
411
412
413void BvHierarchy::EvalSubdivisionCandidate(BvhSubdivisionCandidate &splitCandidate)
414{
415        // compute best object partition
416        const float ratio =     SelectObjectPartition(
417                                                        splitCandidate.mParentData,
418                                                        splitCandidate.mFrontObjects,
419                                                        splitCandidate.mBackObjects);
420       
421        BvhLeaf *leaf = splitCandidate.mParentData.mNode;
422
423        // cost ratio violated?
424        const bool maxCostRatioViolated = mTermMaxCostRatio < ratio;
425
426        splitCandidate.mMaxCostMisses = maxCostRatioViolated ?
427                splitCandidate.mParentData.mMaxCostMisses + 1 :
428                splitCandidate.mParentData.mMaxCostMisses;
429
430        const float viewSpaceVol = mVspTree->GetBoundingBox().GetVolume();
431        const float oldProp = EvalViewCellsVolume(leaf->mObjects);
432        const float oldProp2 = splitCandidate.mParentData.mProbability; //Debug << "here8 " << (oldProp - oldProp2) / viewSpaceVol << "  " << oldProp  / viewSpaceVol << " " << oldProp2  / viewSpaceVol << endl;
433
434        const float oldRenderCost = oldProp * (float)leaf->mObjects.size() / viewSpaceVol;
435
436        // compute global decrease in render cost
437        float newRenderCost = EvalRenderCost(splitCandidate.mParentData,
438                                                                             splitCandidate.mFrontObjects,
439                                                                                 splitCandidate.mBackObjects);
440
441        newRenderCost /=  viewSpaceVol;
442
443        const float renderCostDecr = oldRenderCost - newRenderCost;
444
445        Debug << "\nbvh render cost decr: " << renderCostDecr << endl;
446        splitCandidate.SetRenderCostDecrease(renderCostDecr);
447
448#if 1
449        const float priority = (float)-splitCandidate.mParentData.mDepth;
450#else   
451        // take render cost of node into account
452        // otherwise danger of being stuck in a local minimum!!
453        const float factor = mRenderCostDecreaseWeight;
454        const float priority = factor * renderCostDecr + (1.0f - factor) * oldRenderCost;
455#endif
456
457        // compute global decrease in render cost
458        splitCandidate.SetPriority(priority);
459}
460
461
462inline bool BvHierarchy::LocalTerminationCriteriaMet(const BvhTraversalData &data) const
463{
464        // matt: TODO
465        return ( 0
466                //|| ((int)data.mNode->mObjects.size() < mTermMinObjects)
467                //|| (data.mProbability <= mTermMinProbability)
468                //|| (data.mDepth >= mTermMaxDepth)
469                 );
470}
471
472
473inline bool BvHierarchy::GlobalTerminationCriteriaMet(const BvhTraversalData &data) const
474{
475        // matt: TODO
476        return (0
477                || (mBvhStats.Leaves() >= mTermMaxLeaves)
478                //|| (mGlobalCostMisses >= mTermGlobalCostMissTolerance)
479                //|| mOutOfMemory
480                );
481}
482
483
484void BvHierarchy::EvaluateLeafStats(const BvhTraversalData &data)
485{
486        // the node became a leaf -> evaluate stats for leafs
487        BvhLeaf *leaf = data.mNode;
488       
489        ++ mCreatedLeaves;
490
491        if (data.mDepth >= mTermMaxDepth)
492        {
493        ++ mBvhStats.maxDepthNodes;
494                //Debug << "new max depth: " << mVspStats.maxDepthNodes << endl;
495        }
496
497        if (data.mDepth < mTermMaxDepth)
498        {
499        ++ mBvhStats.minDepthNodes;
500        }
501
502        if (data.mProbability <= mTermMinProbability)
503                ++ mBvhStats.minProbabilityNodes;
504       
505        // accumulate depth to compute average depth
506        mBvhStats.accumDepth += data.mDepth;
507 
508        if ((int)(leaf->mObjects.size()) < mTermMinObjects)
509             ++ mBvhStats.minObjectsNodes;
510 
511        if ((int)(leaf->mObjects.size()) > mBvhStats.maxObjectRefs)
512                mBvhStats.maxObjectRefs = (int)leaf->mObjects.size();
513}
514
515
516#if 0
517float BvHierarchy::EvalLocalObjectPartition(const BvhTraversalData &tData,
518                                                                                        const int axis,
519                                                                                        ObjectContainer &objectsFront,
520                                                                                        ObjectContainer &objectsBack)
521{
522        const float maxBox = tData.mBoundingBox.Max(axis);
523        const float minBox = tData.mBoundingBox.Min(axis);
524
525        float midPoint = (maxBox + minBox) * 0.5f;
526
527        ObjectContainer::const_iterator oit, oit_end = tData.mNode->mObjects.end();
528       
529        for (oit = tData.mNode->mObjects.begin(); oit != oit_end; ++ oit)
530        {
531                Intersectable *obj = *oit;
532                const AxisAlignedBox3 box = obj->GetBox();
533
534                const float objMid = (box.Max(axis) + box.Min(axis)) * 0.5f;
535
536                // object mailed => belongs to back objects
537                if (objMid < midPoint)
538                        objectsBack.push_back(obj);
539                else
540                        objectsFront.push_back(obj);
541        }
542
543        const float oldRenderCost = tData.mProbability * (float)tData.mNode->mObjects.size();
544        const float newRenderCost =
545                EvalRenderCost(tData, objectsFront, objectsBack);
546
547        const float ratio = newRenderCost / oldRenderCost;
548        return ratio;
549}
550
551#else
552
553float BvHierarchy::EvalLocalObjectPartition(const BvhTraversalData &tData,
554                                                                                        const int axis,
555                                                                                        ObjectContainer &objectsFront,
556                                                                                        ObjectContainer &objectsBack)
557{
558        SortSubdivisionCandidates(tData, axis);
559       
560        vector<SortableEntry>::const_iterator cit, cit_end = mSubdivisionCandidates->end();
561
562        int i = 0;
563        const int border = (int)tData.mNode->mObjects.size() / 2;
564
565    for (cit = mSubdivisionCandidates->begin(); cit != cit_end; ++ cit, ++ i)
566        {
567                Intersectable *obj = (*cit).mObject;
568
569                // object mailed => belongs to back objects
570                if (i < border)
571                        objectsBack.push_back(obj);
572                else
573                        objectsFront.push_back(obj);
574        }
575
576        const float oldProp = EvalViewCellsVolume(tData.mNode->mObjects);
577        //const float oldProp2 = tData.mProbability; Debug << "here65 " << oldProp - oldProp2 << endl;
578
579        const float oldRenderCost = oldProp * (float)tData.mNode->mObjects.size();
580        const float newRenderCost = EvalRenderCost(tData, objectsFront, objectsBack);
581
582        const float ratio = newRenderCost / oldRenderCost;
583        return ratio;
584}
585#endif
586
587
588float BvHierarchy::EvalLocalCostHeuristics(const BvhTraversalData &tData,
589                                                                                   const int axis,
590                                                                                   ObjectContainer &objectsFront,
591                                                                                   ObjectContainer &objectsBack)
592{
593        // prepare the heuristics by setting mailboxes and counters.
594        const float totalVol = PrepareHeuristics(tData, axis);
595
596        // go through the lists, count the number of objects left and right
597        // and evaluate the cost funcion
598
599        // local helper variables
600        float volLeft = 0;
601        float volRight = totalVol;
602
603        int nObjectsLeft = 0;
604
605        const int nTotalObjects = (int)tData.mNode->mObjects.size();
606        const float viewSpaceVol = mVspTree->GetBoundingBox().GetVolume();
607
608        vector<SortableEntry>::const_iterator currentPos =
609                mSubdivisionCandidates->begin();
610
611        /////////////////////////////////
612        // the parameters for the current optimum
613
614        float volBack = volLeft;
615        float volFront = volRight;
616
617        float newRenderCost = nTotalObjects * totalVol;
618
619
620        /////////////////////////////
621        // the sweep heuristics
622       
623        //-- traverse through events and find best split plane
624
625        vector<SortableEntry>::const_iterator cit, cit_end = mSubdivisionCandidates->end();
626
627        for (cit = mSubdivisionCandidates->begin(); cit != cit_end; ++ cit)
628        {
629                Intersectable *object = (*cit).mObject;
630               
631                // evaluate change in l and r volume
632                // voll = view cells that see only left node (i.e., left pvs)
633                // volr = view cells that see only right node (i.e., right pvs)
634                EvalHeuristicsContribution(object, volLeft, volRight);
635
636                ++ nObjectsLeft;
637               
638                const int nObjectsRight = nTotalObjects - nObjectsLeft;
639
640                // the heuristics
641            const float sum = volLeft * (float)nObjectsLeft +
642                                                  volRight * (float)nObjectsRight;
643
644                if (sum < newRenderCost)
645                {
646                        newRenderCost = sum;
647
648                        volBack = volLeft;
649                        volFront = volRight;
650
651                        // objects belongs to left side now
652                        for (; currentPos != (cit + 1); ++ currentPos);
653                }
654        }
655
656        //-- assign object to front and back volume
657
658        // belongs to back bv
659        for (cit = mSubdivisionCandidates->begin(); cit != currentPos; ++ cit)
660                objectsBack.push_back((*cit).mObject);
661       
662        // belongs to front bv
663        for (cit = currentPos; cit != cit_end; ++ cit)
664                objectsFront.push_back((*cit).mObject);
665
666        tData.mNode->mObjects.end();
667
668        const float oldRenderCost = (float)nTotalObjects * totalVol + Limits::Small;
669        // the relative cost ratio
670        const float ratio = newRenderCost / oldRenderCost;
671
672        Debug << "\n§§§§ eval local cost §§§§" << endl
673                  << "back pvs: " << (int)objectsBack.size() << " front pvs: " << (int)objectsFront.size() << " total pvs: " << nTotalObjects << endl
674                  << "back p: " << volBack / viewSpaceVol << " front p " << volFront / viewSpaceVol << " p: " << totalVol / viewSpaceVol << endl
675                  << "old rc: " << oldRenderCost / viewSpaceVol << " new rc: " << newRenderCost / viewSpaceVol << endl
676                  << "render cost decrease: " << oldRenderCost / viewSpaceVol - newRenderCost / viewSpaceVol << endl;
677
678        return ratio;
679}
680
681
682void BvHierarchy::SortSubdivisionCandidates(const BvhTraversalData &tData,
683                                                                                        const int axis)                                                                                 
684{
685        mSubdivisionCandidates->clear();
686
687        //RayInfoContainer *rays = tData.mRays;
688        BvhLeaf *leaf = tData.mNode;
689
690        // compute requested size
691        const int requestedSize = (int)leaf->mObjects.size() * 2;
692       
693        // creates a sorted split candidates array
694        if (mSubdivisionCandidates->capacity() > 500000 &&
695                requestedSize < (int)(mSubdivisionCandidates->capacity() / 10) )
696        {
697        delete mSubdivisionCandidates;
698                mSubdivisionCandidates = new vector<SortableEntry>;
699        }
700
701        mSubdivisionCandidates->reserve(requestedSize);
702
703        //-- insert object queries
704        //-- These queries can induce a change in pvs size.
705        //-- Note that they cannot induce a change in view cell volume, as
706        //-- there is no ray associated with these events!!
707
708        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
709
710        for (oit = leaf->mObjects.begin(); oit < oit_end; ++ oit)
711        {
712                Intersectable *obj = *oit;
713               
714                Intersectable *object = *oit;
715                const AxisAlignedBox3 &box = object->GetBox();
716                const float midPt = (box.Min(axis) + box.Max(axis)) * 0.5f;
717
718                mSubdivisionCandidates->push_back(SortableEntry(object, midPt));
719        }
720
721        stable_sort(mSubdivisionCandidates->begin(), mSubdivisionCandidates->end());
722}
723
724
725const BvhStatistics &BvHierarchy::GetStatistics() const
726{
727        return mBvhStats;
728}
729
730
731float BvHierarchy::PrepareHeuristics(const BvhTraversalData &tData, const int axis)
732{       
733        //-- sort so we can use a sweep from right to left
734        SortSubdivisionCandidates(tData, axis);
735
736        float vol = 0;
737        BvhLeaf *leaf = tData.mNode;
738
739        // collect and mark the view cells as belonging to front pvs
740        ViewCellContainer viewCells;
741        CollectViewCells(tData.mNode->mObjects, viewCells, true);
742
743    ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
744
745        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
746        {
747                vol += (*vit)->GetVolume();
748        }
749
750        // mail view cells on the left side
751        ViewCell::NewMail();
752        // mail the objects on the left side
753        Intersectable::NewMail();
754
755        return vol;
756}
757///////////////////////////////////////////////////////////
758
759
760void BvHierarchy::EvalHeuristicsContribution(Intersectable *obj,
761                                                                                         float &volLeft,
762                                                                                         float &volRight)
763{
764        // collect all view cells associated with this objects
765        // (also multiple times, if they are pierced by several rays)
766
767        ViewCellContainer viewCells;
768       
769        const bool useMailboxing = false;
770        CollectViewCells(obj, viewCells, useMailboxing);
771
772
773        /// classify view cells and compute volume contri accordingly
774        /// possible view cell classifications:
775        /// view cell mailed => view cell can be seen from left child node
776        /// view cell counter > 0 view cell can be seen from right child node
777        /// combined: view cell volume belongs to both nodes
778        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
779       
780        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
781        {
782                // view cells can also be seen from left child node
783                ViewCell *viewCell = *vit;
784
785                const float vol = viewCell->GetVolume();
786
787                if (!viewCell->Mailed())
788                {
789                        viewCell->Mail();
790
791                        // we now see view cell from both nodes
792                        // => add volume to left node
793                        volLeft += vol;
794                }
795
796                // last reference into the right node
797                if (-- viewCell->mCounter == 0)
798                {
799                        // view cell was previously seen from both nodes  =>
800                        // remove volume from right node
801                        volRight -= vol;
802                }
803        }
804}
805
806
807void BvHierarchy::SetViewCellsManager(ViewCellsManager *vcm)
808{
809        mViewCellsManager = vcm;
810}
811
812
813AxisAlignedBox3 BvHierarchy::GetBoundingBox() const
814{
815        return mBoundingBox;
816}
817
818
819float BvHierarchy::SelectObjectPartition(const BvhTraversalData &tData,
820                                                                                 ObjectContainer &frontObjects,
821                                                                                 ObjectContainer &backObjects)
822{
823        ObjectContainer nFrontObjects[3];
824        ObjectContainer nBackObjects[3];
825
826        float nCostRatio[3];
827
828        // create bounding box of node geometry
829        AxisAlignedBox3 box = tData.mBoundingBox;
830               
831        int sAxis = 0;
832        int bestAxis = -1;
833
834        if (mOnlyDrivingAxis)
835        {
836                sAxis = box.Size().DrivingAxis();
837        }
838       
839        // -- evaluate split cost for all three axis
840       
841        for (int axis = 0; axis < 3; ++ axis)
842        {
843                if (!mOnlyDrivingAxis || (axis == sAxis))
844                {
845                        if (mUseCostHeuristics)
846                        {
847                                //-- partition objects using heuristics
848                                nCostRatio[axis] =
849                                        EvalLocalCostHeuristics(
850                                                                                        tData,
851                                                                                        axis,
852                                                                                        nFrontObjects[axis],
853                                                                                        nBackObjects[axis]);
854                        }
855                        else
856                        {
857                                nCostRatio[axis] =
858                                        EvalLocalObjectPartition(
859                                                                                         tData,
860                                                                                         axis,
861                                                                                         nFrontObjects[axis],
862                                                                                         nBackObjects[axis]);
863                        }
864
865                        if (bestAxis == -1)
866                        {
867                                bestAxis = axis;
868                        }
869                        else if (nCostRatio[axis] < nCostRatio[bestAxis])
870                        {
871                                bestAxis = axis;
872                        }
873                }
874        }
875
876        //-- assign values
877
878        frontObjects = nFrontObjects[bestAxis];
879        backObjects = nBackObjects[bestAxis];
880
881        //Debug << "val: " << nCostRatio[bestAxis] << " axis: " << bestAxis << endl;
882        return nCostRatio[bestAxis];
883}
884
885
886void BvHierarchy::AssociateObjectsWithRays(const VssRayContainer &rays)
887{
888
889        VssRayContainer::const_iterator rit, rit_end = rays.end();
890
891    for (rit = rays.begin(); rit != rays.end(); ++ rit)
892        {
893                VssRay *ray = (*rit);
894
895                if (ray->mTerminationObject)
896                {
897                        ray->mTerminationObject->mVssRays.push_back(ray);
898                }
899
900                if (0 && ray->mOriginObject)
901                {
902                        ray->mOriginObject->mVssRays.push_back(ray);
903                }
904        }
905}
906
907
908void BvHierarchy::PrintSubdivisionStats(const SubdivisionCandidate &sc)
909{
910        const float costDecr = sc.GetRenderCostDecrease();     
911
912        mSubdivisionStats
913                        << "#Leaves\n" << mBvhStats.Leaves()
914                        << "#RenderCostDecrease\n" << costDecr << endl
915                        << "#TotalRenderCost\n" << mTotalCost << endl;
916                        //<< "#AvgRenderCost\n" << avgRenderCost << endl;
917}
918
919
920void BvHierarchy::CollectRays(const ObjectContainer &objects,
921                                                          VssRayContainer &rays) const
922{
923        VssRay::NewMail();
924       
925        ObjectContainer::const_iterator oit, oit_end = objects.end();
926
927        // evaluate reverse pvs and view cell volume on left and right cell
928        // note: should I take all leaf objects or rather the objects hit by rays?
929        for (oit = objects.begin(); oit != oit_end; ++ oit)
930        {
931                Intersectable *obj = *oit;
932               
933                VssRayContainer::const_iterator rit, rit_end = obj->mVssRays.end();
934
935                for (rit = obj->mVssRays.begin(); rit < rit_end; ++ rit)
936                {
937                        VssRay *ray = (*rit);
938
939                        if (!ray->Mailed())
940                        {
941                                ray->Mail();
942                                rays.push_back(ray);
943                        }
944                }
945        }
946}
947
948
949float BvHierarchy::EvalRenderCost(const BvhTraversalData &tData,
950                                                                  const ObjectContainer &objectsFront,
951                                                                  const ObjectContainer &objectsBack) const
952{
953        BvhLeaf *leaf = tData.mNode;
954
955        // probability that view point lies in a view cell which sees this node
956        const float pFront = EvalViewCellsVolume(objectsFront);
957        const float pBack = EvalViewCellsVolume(objectsBack);
958               
959        const int totalObjects = (int)leaf->mObjects.size();
960        const int nObjectsFront = (int)objectsFront.size();
961        const int nObjectsBack = (int)objectsBack.size();
962
963        //-- pvs rendering heuristics
964        const float newRenderCost = nObjectsFront * pFront + nObjectsBack * pBack;
965        /*
966        const float viewSpaceVol = mVspTree->GetBoundingBox().GetVolume();
967        Debug << "\nbvh render cost\n"
968                  << "back p: " << pBack / viewSpaceVol << " front p " << pFront / viewSpaceVol << endl
969                  << "new rc: " << newRenderCost / viewSpaceVol << endl;*/
970
971        return newRenderCost;
972}
973
974
975AxisAlignedBox3 BvHierarchy::ComputeBoundingBox(const ObjectContainer &objects,
976                                                                                                const AxisAlignedBox3 *parentBox)
977{
978        if (parentBox && objects.empty())
979                return *parentBox;
980
981        AxisAlignedBox3 box;
982        box.Initialize();
983
984        ObjectContainer::const_iterator oit, oit_end = objects.end();
985
986        //-- compute bounding box
987        for (oit = objects.begin(); oit != oit_end; ++ oit)
988        {
989                Intersectable *obj = *oit;
990
991                // compute bounding box of view space
992                box.Include(obj->GetBox());
993        }
994
995        return box;
996}
997
998
999void BvHierarchy::CollectLeaves(vector<BvhLeaf *> &leaves) const
1000{
1001        stack<BvhNode *> nodeStack;
1002        nodeStack.push(mRoot);
1003
1004        while (!nodeStack.empty())
1005        {
1006                BvhNode *node = nodeStack.top();
1007                nodeStack.pop();
1008
1009                if (node->IsLeaf())
1010                {
1011                        BvhLeaf *leaf = (BvhLeaf *)node;
1012                        leaves.push_back(leaf);
1013                }
1014                else
1015                {
1016                        BvhInterior *interior = (BvhInterior *)node;
1017
1018                        nodeStack.push(interior->GetBack());
1019                        nodeStack.push(interior->GetFront());
1020                }
1021        }
1022}
1023
1024
1025AxisAlignedBox3 BvHierarchy::GetBoundingBox(BvhNode *node) const
1026{
1027        return node->GetBoundingBox();
1028}
1029
1030
1031void BvHierarchy::CollectViewCells(const ObjectContainer &objects,
1032                                                                   ViewCellContainer &viewCells,
1033                                                                   const bool setCounter) const
1034{
1035        ViewCell::NewMail();
1036        ObjectContainer::const_iterator oit, oit_end = objects.end();
1037
1038        // loop through all object and collect view cell pvs of this node
1039        for (oit = objects.begin(); oit != oit_end; ++ oit)
1040        {
1041                CollectViewCells(*oit, viewCells, true, setCounter);
1042        }
1043}
1044
1045
1046void BvHierarchy::CollectViewCells(Intersectable *obj,
1047                                                                   ViewCellContainer &viewCells,
1048                                                                   const bool useMailBoxing,
1049                                                                   const bool setCounter) const
1050{
1051        VssRayContainer::const_iterator rit, rit_end = obj->mVssRays.end();
1052
1053        for (rit = obj->mVssRays.begin(); rit < rit_end; ++ rit)
1054        {
1055                VssRay *ray = (*rit);
1056                ViewCellContainer tmpViewCells;
1057       
1058                mVspTree->GetViewCells(*ray, tmpViewCells);
1059
1060                ViewCellContainer::const_iterator vit, vit_end = tmpViewCells.end();
1061
1062                for (vit = tmpViewCells.begin(); vit != vit_end; ++ vit)
1063                {
1064                        VspViewCell *vc = dynamic_cast<VspViewCell *>(*vit);
1065
1066                        // store view cells
1067                        if (!useMailBoxing || !vc->Mailed())
1068                        {
1069                                if (useMailBoxing)
1070                                {
1071                                        vc->Mail();
1072                                        if (setCounter)
1073                                                vc->mCounter = 0;
1074                                }
1075                               
1076                                viewCells.push_back(vc);
1077                        }
1078                       
1079                        if (setCounter)
1080                        {
1081                                ++ vc->mCounter;
1082                        }
1083                }
1084        }
1085}
1086
1087
1088void BvHierarchy::CollectDirtyCandidates(BvhSubdivisionCandidate *sc,
1089                                                                                 vector<SubdivisionCandidate *> &dirtyList)
1090{
1091        BvhTraversalData &tData = sc->mParentData;
1092        BvhLeaf *node = tData.mNode;
1093       
1094        ViewCellContainer viewCells;
1095        CollectViewCells(node->mObjects, viewCells);
1096
1097        // split candidates handling
1098        // these view cells  are thrown into dirty list
1099        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
1100
1101        Debug << "collecting " << (int)viewCells.size() << " dirty candidates" << endl;
1102
1103        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
1104        {
1105                VspViewCell *vc = dynamic_cast<VspViewCell *>(*vit);
1106                VspLeaf *leaf = vc->mLeaf;
1107                SubdivisionCandidate *candidate = leaf->GetSubdivisionCandidate();
1108                Debug << "here100 candidate: " << candidate << " type: " << candidate->Type() << endl;
1109               
1110                dirtyList.push_back(leaf->GetSubdivisionCandidate());
1111        }
1112}
1113
1114
1115BvhNode *BvHierarchy::GetRoot() const
1116{
1117        return mRoot;
1118}
1119
1120
1121bool BvHierarchy::IsObjectInLeaf(BvhLeaf *leaf, Intersectable *object) const
1122{
1123        ObjectContainer::const_iterator oit =
1124                lower_bound(leaf->mObjects.begin(), leaf->mObjects.end(), object, ilt);
1125                               
1126        // objects sorted by id
1127        if ((oit != leaf->mObjects.end()) && ((*oit)->GetId() == object->GetId()))
1128        {
1129                return true;
1130        }
1131        else
1132        {
1133                return false;
1134        }
1135}
1136
1137
1138BvhLeaf *BvHierarchy::GetLeaf(Intersectable *object, BvhNode *node) const
1139{
1140        // rather use the simple version
1141        if (!object) return NULL;
1142        return object->mBvhLeaf;
1143       
1144        ///////////////////////////////////////
1145        // start from root of tree
1146       
1147        if (node == NULL)
1148                node = mRoot;
1149       
1150        vector<BvhLeaf *> leaves;
1151
1152        stack<BvhNode *> nodeStack;
1153        nodeStack.push(node);
1154 
1155        BvhLeaf *leaf = NULL;
1156 
1157        while (!nodeStack.empty()) 
1158        {
1159                BvhNode *node = nodeStack.top();
1160                nodeStack.pop();
1161       
1162                if (node->IsLeaf())
1163                {
1164                        leaf = dynamic_cast<BvhLeaf *>(node);
1165
1166                        if (IsObjectInLeaf(leaf, object))
1167                        {
1168                                return leaf;
1169                        }
1170                }
1171                else   
1172                {       
1173                        // find point
1174                        BvhInterior *interior = dynamic_cast<BvhInterior *>(node);
1175       
1176                        if (interior->GetBack()->GetBoundingBox().Includes(object->GetBox()))
1177                        {
1178                                nodeStack.push(interior->GetBack());
1179                        }
1180                       
1181                        // search both sides as we are using bounding volumes
1182                        if (interior->GetFront()->GetBoundingBox().Includes(object->GetBox()))
1183                        {
1184                                nodeStack.push(interior->GetFront());
1185                        }
1186                }
1187        }
1188 
1189        return leaf;
1190}
1191
1192
1193BvhIntersectable *BvHierarchy::GetOrCreateBvhIntersectable(BvhNode *node)
1194{
1195        // search nodes
1196        std::map<BvhNode *, BvhIntersectable *>::
1197                const_iterator it = mBvhIntersectables.find(node);
1198
1199        if (it != mBvhIntersectables.end())
1200        {
1201                return (*it).second;
1202        }
1203
1204        // not in map => create new entry
1205        BvhIntersectable *bvhObj = new BvhIntersectable(node);
1206        mBvhIntersectables[node] = bvhObj;
1207
1208        return bvhObj;
1209}
1210
1211
1212bool BvHierarchy::Export(OUT_STREAM &stream)
1213{
1214        ExportNode(mRoot, stream);
1215
1216        return true;
1217}
1218
1219
1220void BvHierarchy::ExportObjects(BvhLeaf *leaf, OUT_STREAM &stream)
1221{
1222        ObjectContainer::const_iterator oit, oit_end = leaf->mObjects.end();
1223        for (oit = leaf->mObjects.begin(); oit != oit_end; ++ oit)
1224        {
1225                stream << (*oit)->GetId() << " ";
1226        }
1227}
1228
1229
1230void BvHierarchy::ExportNode(BvhNode *node, OUT_STREAM &stream)
1231{
1232        if (node->IsLeaf())
1233        {
1234                BvhLeaf *leaf = dynamic_cast<BvhLeaf *>(node);
1235                const AxisAlignedBox3 box = leaf->GetBoundingBox();
1236                stream << "<Leaf"
1237                           << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
1238                           << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\""
1239                           << " objects=\"";
1240               
1241                //-- export objects
1242                ExportObjects(leaf, stream);
1243               
1244                stream << "\" />" << endl;
1245        }
1246        else
1247        {       
1248                BvhInterior *interior = dynamic_cast<BvhInterior *>(node);
1249                const AxisAlignedBox3 box = interior->GetBoundingBox();
1250
1251                stream << "<Interior"
1252                           << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
1253                           << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z
1254                           << "\">" << endl;
1255
1256                ExportNode(interior->GetBack(), stream);
1257                ExportNode(interior->GetFront(), stream);
1258
1259                stream << "</Interior>" << endl;
1260        }
1261}
1262
1263
1264float BvHierarchy::EvalViewCellsVolume(const ObjectContainer &objects) const
1265{
1266        float vol = 0;
1267
1268        ViewCellContainer viewCells;
1269        CollectViewCells(objects, viewCells);
1270
1271        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
1272
1273        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
1274        {
1275                vol += (*vit)->GetVolume();
1276        }
1277
1278        return vol;
1279}
1280
1281void BvHierarchy::CreateRoot(const ObjectContainer &objects)
1282{
1283        //-- create new root
1284        AxisAlignedBox3 box = ComputeBoundingBox(objects);
1285        BvhLeaf *bvhleaf = new BvhLeaf(box, NULL, (int)objects.size());
1286        bvhleaf->mObjects = objects;
1287
1288        mRoot = bvhleaf;
1289
1290        // associate root with current objects
1291        AssociateObjectsWithLeaf(bvhleaf);
1292}
1293
1294
1295SubdivisionCandidate *BvHierarchy::PrepareConstruction(const VssRayContainer &sampleRays,
1296                                                                                                           const ObjectContainer &objects)
1297{
1298        // note matt: we assume that we have objects sorted by their id
1299
1300        // store pointer to this tree
1301        BvhSubdivisionCandidate::sBvHierarchy = this;
1302        mBvhStats.nodes = 1;
1303
1304        // compute bounding box from objects
1305        // note: we assume that root was already created
1306        mBoundingBox = mRoot->GetBoundingBox();
1307        BvhLeaf *bvhleaf = dynamic_cast<BvhLeaf *>(mRoot);
1308
1309        mTermMinProbability *= mBoundingBox.GetVolume();
1310        mGlobalCostMisses = 0;
1311       
1312        // only rays intersecting objects in node are interesting
1313        AssociateObjectsWithRays(sampleRays);
1314       
1315        // probabilty is voume of all "seen" view cells
1316#if 1
1317        const float prop = EvalViewCellsVolume(objects);
1318#else
1319        const float prop = GetBoundingBox().GetVolume();
1320#endif
1321
1322        // create bvh traversal data
1323        BvhTraversalData oData(bvhleaf, 0, mBoundingBox, prop);
1324
1325        //-- add first candidate for object space partition     
1326        BvhSubdivisionCandidate *oSubdivisionCandidate =
1327                new BvhSubdivisionCandidate(oData);
1328
1329        EvalSubdivisionCandidate(*oSubdivisionCandidate);
1330        bvhleaf->SetSubdivisionCandidate(oSubdivisionCandidate);
1331
1332        const float viewSpaceVol = mVspTree->GetBoundingBox().GetVolume();
1333        mTotalCost = (float)objects.size() * prop / viewSpaceVol;
1334
1335        PrintSubdivisionStats(*oSubdivisionCandidate);
1336
1337        return oSubdivisionCandidate;
1338}
1339
1340
1341bool BvHierarchy::AddLeafToPvs(BvhLeaf *leaf,
1342                                                           ViewCell *vc,
1343                                                           const float pdf,
1344                                                           float &contribution)
1345{
1346        // add kd intersecable to pvs
1347        BvhIntersectable *bvhObj = GetOrCreateBvhIntersectable(leaf);
1348       
1349        return vc->AddPvsSample(bvhObj, pdf, contribution);
1350}
1351
1352
1353void BvhStatistics::Print(ostream &app) const
1354{
1355        app << "=========== BvHierarchy statistics ===============\n";
1356
1357        app << setprecision(4);
1358
1359        app << "#N_CTIME  ( Construction time [s] )\n" << Time() << " \n";
1360
1361        app << "#N_NODES ( Number of nodes )\n" << nodes << "\n";
1362
1363        app << "#N_INTERIORS ( Number of interior nodes )\n" << Interior() << "\n";
1364
1365        app << "#N_LEAVES ( Number of leaves )\n" << Leaves() << "\n";
1366
1367        app << "#AXIS_ALIGNED_SPLITS (number of axis aligned splits)\n" << splits << endl;
1368
1369        app << "#N_PMINDEPTHLEAVES ( Percentage of leaves at minimum depth )\n"
1370                <<      minDepthNodes * 100 / (double)Leaves() << endl;
1371
1372        app << "#N_PMAXDEPTHLEAVES ( Percentage of leaves at maximum depth )\n"
1373                <<      maxDepthNodes * 100 / (double)Leaves() << endl;
1374
1375        app << "#N_MAXCOSTNODES  ( Percentage of leaves with terminated because of max cost ratio )\n"
1376                << maxCostNodes * 100 / (double)Leaves() << endl;
1377
1378        app << "#N_PMINPROBABILITYLEAVES  ( Percentage of leaves with mininum probability )\n"
1379                << minProbabilityNodes * 100 / (double)Leaves() << endl;
1380
1381        app << "#N_PMINOBJECTSLEAVES  ( Percentage of leaves with mininum objects )\n"
1382                << minObjectsNodes * 100 / (double)Leaves() << endl;
1383
1384        app << "#N_PMAXDEPTH ( Maximal reached depth )\n" << maxDepth << endl;
1385
1386        app << "#N_PMINDEPTH ( Minimal reached depth )\n" << minDepth << endl;
1387
1388        app << "#AVGDEPTH ( average depth )\n" << AvgDepth() << endl;
1389
1390        app << "#N_INVALIDLEAVES (number of invalid leaves )\n" << invalidLeaves << endl;
1391
1392        app << "#N_MAXOBJECTREFS  ( Max number of object refs / leaf )\n" << maxObjectRefs << "\n";
1393
1394        //app << "#N_RAYS (number of rays / leaf)\n" << AvgRays() << endl;
1395       
1396        app << "========== END OF VspTree statistics ==========\n";
1397}
1398
1399
1400}
Note: See TracBrowser for help on using the repository browser.