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

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