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

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