source: GTP/trunk/Lib/Vis/Preprocessing/src/ViewCellsManager.cpp @ 1900

Revision 1900, 155.5 KB checked in by bittner, 18 years ago (diff)

experiments with different contribution computations

Line 
1#include "ViewCellsManager.h"
2#include "RenderSimulator.h"
3#include "Mesh.h"
4#include "Triangle3.h"
5#include "ViewCell.h"
6#include "Environment.h"
7#include "X3dParser.h"
8#include "ViewCellBsp.h"
9#include "KdTree.h"
10#include "HierarchyManager.h"
11#include "Exporter.h"
12#include "VspBspTree.h"
13#include "ViewCellsParser.h"
14#include "Beam.h"
15#include "VssPreprocessor.h"
16#include "RssPreprocessor.h"
17#include "BoundingBoxConverter.h"
18#include "GlRenderer.h"
19#include "ResourceManager.h"
20#include "IntersectableWrapper.h"
21#include "VspTree.h"
22#include "OspTree.h"
23#include "BvHierarchy.h"
24#include "SamplingStrategy.h"
25#include "SceneGraph.h"
26
27
28// $$JB HACK
29#define USE_KD_PVS 1
30
31#define KD_PVS_AREA (1e-5f)
32
33#define USE_RAY_LENGTH_AS_CONTRIBUTION 0
34#define DIST_WEIGHTED_CONTRIBUTION 1
35
36namespace GtpVisibilityPreprocessor {
37
38
39// HACK
40const static bool SAMPLE_AFTER_SUBDIVISION = true;
41//const static bool CLAMP_TO_BOX = false;
42const static bool CLAMP_TO_BOX = true;
43
44
45int ViewCellsManager::sRenderCostEvaluationType = 0;
46
47
48template <typename T> class myless
49{
50public:
51        //bool operator() (HierarchyNode *v1, HierarchyNode *v2) const
52        bool operator() (T v1, T v2) const
53        {
54                return (v1->GetMergeCost() < v2->GetMergeCost());
55        }
56};
57
58
59ViewCellsManager::ViewCellsManager(ViewCellsTree *viewCellsTree):
60mRenderer(NULL),
61mInitialSamples(0),
62mConstructionSamples(0),
63mPostProcessSamples(0),
64mVisualizationSamples(0),
65mTotalAreaValid(false),
66mTotalArea(0.0f),
67mViewCellsFinished(false),
68mMaxPvsSize(9999999),
69mMinPvsSize(0),
70mMaxPvsRatio(1.0),
71mViewCellPvsIsUpdated(false),
72mPreprocessor(NULL),
73mViewCellsTree(viewCellsTree),
74mUsePredefinedViewCells(false)
75{
76        mViewSpaceBox.Initialize();
77        ParseEnvironment();
78
79        mViewCellsTree->SetViewCellsManager(this);
80}
81
82
83void ViewCellsManager::ParseEnvironment()
84{
85        // visualization stuff
86        Environment::GetSingleton()->GetBoolValue("ViewCells.Visualization.exportRays", mExportRays);
87        Environment::GetSingleton()->GetBoolValue("ViewCells.Visualization.exportGeometry", mExportGeometry);
88        Environment::GetSingleton()->GetFloatValue("ViewCells.maxPvsRatio", mMaxPvsRatio);
89       
90        Environment::GetSingleton()->GetBoolValue("ViewCells.processOnlyValidViewCells", mOnlyValidViewCells);
91
92        Environment::GetSingleton()->GetIntValue("ViewCells.Construction.samples", mConstructionSamples);
93        Environment::GetSingleton()->GetIntValue("ViewCells.PostProcess.samples", mPostProcessSamples);
94        Environment::GetSingleton()->GetBoolValue("ViewCells.PostProcess.useRaysForMerge", mUseRaysForMerge);
95
96        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.samples", mVisualizationSamples);
97
98        Environment::GetSingleton()->GetIntValue("ViewCells.Construction.samplesPerPass", mSamplesPerPass);
99        Environment::GetSingleton()->GetBoolValue("ViewCells.exportToFile", mExportViewCells);
100       
101        Environment::GetSingleton()->GetIntValue("ViewCells.active", mNumActiveViewCells);
102        Environment::GetSingleton()->GetBoolValue("ViewCells.PostProcess.compress", mCompressViewCells);
103        Environment::GetSingleton()->GetBoolValue("ViewCells.Visualization.useClipPlane", mUseClipPlaneForViz);
104        Environment::GetSingleton()->GetBoolValue("ViewCells.PostProcess.merge", mMergeViewCells);
105        Environment::GetSingleton()->GetBoolValue("ViewCells.evaluateViewCells", mEvaluateViewCells);
106        Environment::GetSingleton()->GetBoolValue("ViewCells.showVisualization", mShowVisualization);
107        Environment::GetSingleton()->GetIntValue("ViewCells.Filter.maxSize", mMaxFilterSize);
108        Environment::GetSingleton()->GetFloatValue("ViewCells.Filter.width", mFilterWidth);
109        Environment::GetSingleton()->GetIntValue("ViewCells.renderCostEvaluationType", sRenderCostEvaluationType);
110
111        Environment::GetSingleton()->GetBoolValue("ViewCells.exportBboxesForPvs", mExportBboxesForPvs);
112        Environment::GetSingleton()->GetBoolValue("ViewCells.exportPvs", mExportPvs);
113       
114        char buf[100];
115        Environment::GetSingleton()->GetStringValue("ViewCells.samplingType", buf);
116
117        // mix of sampling strategies
118        if (1)
119        {
120                mStrategies.push_back(SamplingStrategy::OBJECT_BASED_DISTRIBUTION);
121                //mStrategies.push_back(SamplingStrategy::SPATIAL_BOX_BASED_DISTRIBUTION);
122                mStrategies.push_back(SamplingStrategy::REVERSE_VIEWSPACE_BORDER_BASED_DISTRIBUTION);
123                mStrategies.push_back(SamplingStrategy::REVERSE_OBJECT_BASED_DISTRIBUTION);
124        }
125        else
126        {
127                mStrategies.push_back(SamplingStrategy::OBJECT_BASED_DISTRIBUTION);
128                //mStrategies.push_back(SamplingStrategy::VIEWSPACE_BORDER_BASED_DISTRIBUTION);
129                mStrategies.push_back(SamplingStrategy::REVERSE_VIEWSPACE_BORDER_BASED_DISTRIBUTION);
130                //mStrategies.push_back(SamplingStrategy::REVERSE_VIEWSPACE_BORDER_BASED_DISTRIBUTION);
131                //mStrategies.push_back(SamplingStrategy::REVERSE_VIEWSPACE_BORDER_BASED_DISTRIBUTION);
132        }
133
134       
135    Debug << "casting strategies: ";
136        for (int i = 0; i < (int)mStrategies.size(); ++ i)
137                Debug << mStrategies[i] << " ";
138        Debug << endl;
139
140        // sampling type for view cells construction samples
141        if (strcmp(buf, "object") == 0)
142        {
143                mSamplingType = SamplingStrategy::OBJECT_BASED_DISTRIBUTION;
144        }
145        else if (strcmp(buf, "box") == 0)
146        {
147                mSamplingType = SamplingStrategy::SPATIAL_BOX_BASED_DISTRIBUTION;
148        }
149        else if (strcmp(buf, "directional") == 0)
150        {
151                mSamplingType = SamplingStrategy::DIRECTION_BASED_DISTRIBUTION;
152        }
153        else if (strcmp(buf, "object_directional") == 0)
154        {
155                mSamplingType = SamplingStrategy::OBJECT_DIRECTION_BASED_DISTRIBUTION;
156        }
157        else if (strcmp(buf, "reverse_object") == 0)
158        {
159                mSamplingType = SamplingStrategy::REVERSE_OBJECT_BASED_DISTRIBUTION;
160        }
161        /*else if (strcmp(buf, "interior") == 0)
162        {
163                mSamplingType = Preprocessor::OBJECTS_INTERIOR_DISTRIBUTION;
164        }*/
165        else
166        {
167                Debug << "error! wrong sampling type" << endl;
168                exit(0);
169        }
170
171        // sampling type for evaluation samples
172        Environment::GetSingleton()->GetStringValue("ViewCells.Evaluation.samplingType", buf);
173       
174        if (strcmp(buf, "object") == 0)
175        {
176                mEvaluationSamplingType = SamplingStrategy::OBJECT_BASED_DISTRIBUTION;
177        }
178        else if (strcmp(buf, "box") == 0)
179        {
180                mEvaluationSamplingType = SamplingStrategy::SPATIAL_BOX_BASED_DISTRIBUTION;
181        }
182        else if (strcmp(buf, "directional") == 0)
183        {
184                mEvaluationSamplingType = SamplingStrategy::DIRECTION_BASED_DISTRIBUTION;
185        }
186        else if (strcmp(buf, "object_directional") == 0)
187        {
188                mEvaluationSamplingType = SamplingStrategy::OBJECT_DIRECTION_BASED_DISTRIBUTION;
189        }
190        else if (strcmp(buf, "reverse_object") == 0)
191        {
192                mEvaluationSamplingType = SamplingStrategy::REVERSE_OBJECT_BASED_DISTRIBUTION;
193        }
194        /*else if (strcmp(buf, "interior") == 0)
195        {
196                mEvaluationSamplingType = SamplingStrategy::OBJECTS_INTERIOR_DISTRIBUTION;
197        }*/
198        else
199        {
200                mEvaluationSamplingType = -1;
201                Debug << "error! wrong sampling type" << endl;
202                exit(0);
203        }
204
205        Environment::GetSingleton()->GetStringValue("ViewCells.renderCostEvaluationType", buf);
206       
207        if (strcmp(buf, "perobject") == 0)
208        {
209                sRenderCostEvaluationType = ViewCellsManager::PER_OBJECT;
210        }
211        else if (strcmp(buf, "pertriangle") == 0)
212        {
213                sRenderCostEvaluationType = ViewCellsManager::PER_TRIANGLE;
214        }
215        else
216        {
217                Debug << "error! wrong sampling type" << endl;
218                exit(0);
219        }
220
221    Environment::GetSingleton()->GetStringValue("ViewCells.Visualization.colorCode", buf);
222
223        if (strcmp(buf, "PVS") == 0)
224                mColorCode = 1;
225        else if (strcmp(buf, "MergedLeaves") == 0)
226                mColorCode = 2;
227        else if (strcmp(buf, "MergedTreeDiff") == 0)
228                mColorCode = 3;
229        else
230                mColorCode = 0;
231
232
233        Debug << "************ View Cells Manager options ***************" << endl;
234        Debug << "color code: " << mColorCode << endl;
235
236        Debug << "export rays: " << mExportRays << endl;
237        Debug << "export geometry: " << mExportGeometry << endl;
238        Debug << "max pvs ratio: " << mMaxPvsRatio << endl;
239       
240        Debug << "process only valid view cells: " << mOnlyValidViewCells << endl;
241        Debug << "construction samples: " << mConstructionSamples << endl;
242        Debug << "post process samples: " << mPostProcessSamples << endl;
243        Debug << "post process use rays for merge: " << mUseRaysForMerge << endl;
244        Debug << "visualization samples: " << mVisualizationSamples << endl;
245        Debug << "construction samples per pass: " << mSamplesPerPass << endl;
246        Debug << "export to file: " << mExportViewCells << endl;
247       
248        Debug << "active view cells: " << mNumActiveViewCells << endl;
249        Debug << "post process compress: " << mCompressViewCells << endl;
250        Debug << "visualization use clipPlane: " << mUseClipPlaneForViz << endl;
251        Debug << "post process merge: " << mMergeViewCells << endl;
252        Debug << "evaluate view cells: " << mEvaluateViewCells << endl;
253        Debug << "sampling type: " << mSamplingType << endl;
254        Debug << "render cost evaluation type: " << sRenderCostEvaluationType << endl;
255        Debug << "evaluation sampling type: " << mEvaluationSamplingType << endl;
256        Debug << "show visualization: " << mShowVisualization << endl;
257        Debug << "filter width: " << mFilterWidth << endl;
258        Debug << "sample after subdivision: " << SAMPLE_AFTER_SUBDIVISION << endl;
259
260        Debug << "export bounding boxes: " << mExportBboxesForPvs << endl;
261        Debug << "export pvs for view cells: " << mExportPvs << endl;
262        Debug << endl;
263}
264
265
266ViewCellsManager::~ViewCellsManager()
267{
268        // HACK: if view cells tree does not
269        // handle view cells, we have to do it here
270        // question: rather create view cells resource manager?
271        if (!ViewCellsTreeConstructed())
272        {
273                CLEAR_CONTAINER(mViewCells);
274        }
275        else
276        {
277                DEL_PTR(mViewCellsTree);
278        }
279}
280
281Intersectable *
282ViewCellsManager::GetIntersectable(const VssRay &ray, const bool isTermination) const
283{
284#if USE_KD_PVS
285  float area = GetPreprocessor()->mKdTree->GetBox().SurfaceArea()*KD_PVS_AREA;
286  KdNode *node = GetPreprocessor()->mKdTree->GetNode(isTermination ?
287                                                                                                         ray.mTermination : ray.mOrigin,
288                                                                                                         area);
289  return
290        GetPreprocessor()->mKdTree->
291        GetOrCreateKdIntersectable(node);
292#else
293  return isTermination ? ray.mTerminationObject : ray.mOriginObject;
294#endif
295}
296
297void
298ViewCellsManager::CollectObjects(const AxisAlignedBox3 &box, ObjectContainer &objects)
299{
300  GetPreprocessor()->mKdTree->CollectObjects(box, objects);
301}
302
303AxisAlignedBox3 ViewCellsManager::GetViewCellBox(ViewCell *vc)
304{
305  Mesh *m = vc->GetMesh();
306 
307  if (m)
308  {
309          m->ComputeBoundingBox();
310          return m->mBox;
311  }
312
313  AxisAlignedBox3 box;
314  box.Initialize();
315 
316  if (!vc->IsLeaf()) {
317        ViewCellInterior *vci = (ViewCellInterior *) vc;
318       
319        ViewCellContainer::iterator it = vci->mChildren.begin();
320        for (; it != vci->mChildren.end(); ++it) {
321          box.Include(GetViewCellBox(*it));
322        }
323  }
324 
325  return box;
326}
327
328
329int ViewCellsManager::CastPassSamples(const int samplesPerPass,
330                                                                          const vector<int> &strategies,
331                                                                          VssRayContainer &passSamples
332                                                                          ) const
333{
334        long startTime = GetTime();
335
336        SimpleRayContainer simpleRays;
337       
338        simpleRays.reserve(samplesPerPass);
339        passSamples.reserve(samplesPerPass * 2); // always creates double rays
340
341        // create one third of each type
342        int castRays = 0;
343       
344        const int numRaysPerPass = samplesPerPass / (int)strategies.size();
345        vector<int>::const_iterator iit, iit_end = strategies.end();
346
347        for (iit = strategies.begin(); iit != iit_end; ++ iit)
348        {
349                const int stype = *iit;
350                const int newRays =
351                        mPreprocessor->GenerateRays(numRaysPerPass, stype, simpleRays);
352
353                cout << "cast " << newRays << " rays of strategy " << stype << endl;
354                castRays += newRays;
355        }
356
357        cout << "generated " << samplesPerPass << " samples in "
358                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
359
360        startTime = GetTime();
361
362        // shoot simple ray and add it to importance samples
363        mPreprocessor->CastRays(simpleRays, passSamples, true);
364        cout << "cast " <<  samplesPerPass << " samples in "
365                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
366
367        return (int)passSamples.size();
368}
369
370
371/// helper function which destroys rays or copies them into the output ray container
372inline void disposeRays(VssRayContainer &rays, VssRayContainer *outRays)
373{
374        cout << "disposing samples ... ";
375        long startTime = GetTime();
376        int n = (int)rays.size();
377
378        if (outRays)
379        {
380                VssRayContainer::const_iterator it, it_end = rays.end();
381                for (it = rays.begin(); it != it_end; ++ it)
382                {
383                        outRays->push_back(*it);
384                }
385        }
386        else
387        {
388                VssRayContainer::const_iterator it, it_end = rays.end();
389                for (it = rays.begin(); it != it_end; ++ it)
390                {
391                        if (!(*it)->IsActive())
392                                delete (*it);
393                }
394        }
395
396        cout << "finished" << endl;
397        Debug << "disposed " << n << " samples in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
398}
399
400
401int ViewCellsManager::Construct(Preprocessor *preprocessor, VssRayContainer *outRays)
402{
403        int numSamples = 0;
404
405        SimpleRayContainer simpleRays;
406        VssRayContainer initialSamples;
407
408        // store pointer to preprocessor for further use during construction
409        mPreprocessor = preprocessor;
410       
411
412        ///////////////////////////////////////////////////////
413        //-- Initial sampling for the construction of the view cell hierarchy.
414        //-- We use uniform sampling / box based sampling.
415       
416        long startTime = GetTime();
417        cout << "view cell construction: casting " << mInitialSamples << " initial samples ... " << endl;
418
419        // cast initial samples
420       
421        // mix of sampling strategies
422        vector<int>dummy;
423        //dummy.push_back(SamplingStrategy::OBJECT_BASED_DISTRIBUTION);
424        //dummy.push_back(SamplingStrategy::SPATIAL_BOX_BASED_DISTRIBUTION);
425        //dummy.push_back(SamplingStrategy::REVERSE_OBJECT_BASED_DISTRIBUTION);
426
427        CastPassSamples(mInitialSamples, mStrategies, initialSamples);
428
429        cout << "finished in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
430
431        // construct view cells
432        ConstructSubdivision(preprocessor->mObjects, initialSamples);
433
434        // initial samples count for overall samples ...
435        numSamples += mInitialSamples;
436
437        // rays can be passed or deleted
438        disposeRays(initialSamples, outRays);
439
440        cout << "time needed for initial construction: "
441                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
442
443        Debug << "time needed for initial construction: "
444                  << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
445
446        // collect view cells and compute statistics
447        ResetViewCells();
448
449
450        ///////////////////
451        //-- Initial hierarchy construction finished.
452        //-- We can do some stats and visualization
453       
454        if (0)
455        {
456                //-- export initial view cell partition
457                Debug << "\nView cells after initial sampling:\n" << mCurrentViewCellsStats << endl;
458
459                const string filename("viewcells.wrl");
460                Exporter *exporter = Exporter::GetExporter(filename.c_str());
461       
462                if (exporter)
463                {
464                        cout << "exporting initial view cells (=leaves) to " << filename.c_str() << " ... ";
465
466                        if (mExportGeometry)
467                        {
468                                exporter->ExportGeometry(preprocessor->mObjects);
469                        }
470
471                        exporter->SetWireframe();
472                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
473
474                        delete exporter;
475                        cout << "finished" << endl;
476                }
477        }
478
479
480        //////////////////////
481        //-- Cast some more sampling after initial construction.
482        //-- The additional rays can be used to gain
483        //-- some more information before the bottom-up merge
484        //-- note: guided rays could be used for this task
485
486        // time spent after construction of the initial partition
487        startTime = GetTime();
488        const int n = mConstructionSamples; //+initialSamples;
489
490        while (numSamples < n)
491        {
492                cout << "casting " << mSamplesPerPass << " samples of " << n << " ... ";
493                Debug << "casting " << mSamplesPerPass << " samples of " << n << " ... ";
494
495                VssRayContainer constructionSamples;
496
497                // cast new samples
498                numSamples += CastPassSamples(mSamplesPerPass,
499                                                                          mStrategies,
500                                                                          constructionSamples);
501
502                cout << "finished" << endl;
503                cout << "computing sample contribution for " << (int)constructionSamples.size() << " samples ... ";
504
505                // computes sample contribution of cast rays TODO: leak?
506                if (SAMPLE_AFTER_SUBDIVISION)
507                        ComputeSampleContributions(constructionSamples, true, false);
508
509                cout << "finished" << endl;
510
511                disposeRays(constructionSamples, outRays);
512                cout << "total samples: " << numSamples << endl;
513        }
514
515        if (0)
516        {
517                ///////////////
518                //-- Get stats after the additional sampling step
519                //-- and before the bottom-up merge step
520
521                EvaluateViewCellsStats();
522                Debug << "\noriginal view cell partition before post process:\n"
523                          << mCurrentViewCellsStats << endl;
524       
525                mRenderer->RenderScene();
526                SimulationStatistics ss;
527                dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
528
529                Debug << ss << endl;
530        }
531
532        ////////////////////
533        //-- post processing of the initial construction
534        //-- We can bottom-up merge the view cells in this step
535        //-- We can additionally cast some post processing sample rays.
536        //-- These rays can be used to store the view cells with the rays
537
538        VssRayContainer postProcessSamples;
539        cout << "casting " << mPostProcessSamples << " post processing samples ... ";
540       
541        CastPassSamples(mPostProcessSamples, mStrategies, postProcessSamples);
542
543        cout << "finished" << endl;
544        cout << "starting post processing and visualization" << endl;
545
546        // store view cells with rays for post processing?
547        const bool storeViewCells = true;
548
549        if (SAMPLE_AFTER_SUBDIVISION)
550                ComputeSampleContributions(postProcessSamples, true, storeViewCells);
551
552        PostProcess(preprocessor->mObjects, postProcessSamples);
553
554        const float secs = TimeDiff(startTime, GetTime()) * 1e-3f;
555        cout << "post processing (=merge) finished in " << secs << " secs" << endl;
556
557        Debug << "post processing time: " << secs << endl;
558        disposeRays(postProcessSamples, outRays);
559
560
561        ////////////////
562        //-- Evaluation of the resulting view cell partition.
563        //-- We cast a number of new samples and measure the render cost
564
565        if (mEvaluateViewCells)
566        {
567                EvalViewCellPartition();
568        }
569       
570        /////////////////
571        //-- Show some visualizations
572
573        if (mShowVisualization)
574        {
575                if (0)
576                {
577                        mStrategies.clear();
578                        mStrategies.push_back(SamplingStrategy::VIEWCELL_BORDER_BASED_DISTRIBUTION);
579                }
580
581                ///////////////
582                //-- visualization rays, e.g., to show some samples in the scene
583               
584                VssRayContainer visSamples;
585                int numSamples = CastPassSamples(mVisualizationSamples,
586                                                                                 mStrategies,
587                                                                                 visSamples);
588
589                if (SAMPLE_AFTER_SUBDIVISION)
590                        ComputeSampleContributions(visSamples, true, storeViewCells);
591
592                // various visualizations
593                Visualize(preprocessor->mObjects, visSamples);
594
595                disposeRays(visSamples, outRays);
596        }
597
598        // recalculate view cells
599        EvaluateViewCellsStats();
600
601        if (1) CompressViewCells();
602
603        // write view cells to disc
604        if (mExportViewCells)
605        {
606                char filename[100];
607                Environment::GetSingleton()->GetStringValue("ViewCells.filename", filename);
608                ExportViewCells(filename, mExportPvs, mPreprocessor->mObjects);
609        }
610
611        return numSamples;
612}
613
614
615AxisAlignedPlane *ViewCellsManager::GetClipPlane()
616{
617        return mUseClipPlaneForViz ? &mClipPlaneForViz : NULL;
618}
619
620
621void ViewCellsManager::EvalViewCellHistogram(const string filename,
622                                                                                         const int nViewCells)
623{
624        std::ofstream outstream;
625        outstream.open(filename.c_str());
626
627        ViewCellContainer viewCells;
628        // $$ JB hack - the collect best viewcells does not work?
629#if 1
630        mViewCellsTree->CollectBestViewCellSet(viewCells, nViewCells);
631#else
632        viewCells = mViewCells;
633#endif
634
635        float maxRenderCost, minRenderCost;
636
637        // sort by render cost
638        sort(viewCells.begin(), viewCells.end(), ViewCell::SmallerRenderCost);
639
640        minRenderCost = viewCells.front()->GetRenderCost();
641        maxRenderCost = viewCells.back()->GetRenderCost();
642
643        Debug << "histogram min rc: " << minRenderCost << " max rc: " << maxRenderCost << endl;
644
645    int histoIntervals;
646        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.intervals", histoIntervals);
647        const int intervals = min(histoIntervals, (int)viewCells.size());
648
649        int histoMaxVal;
650        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.maxValue", histoMaxVal);
651        maxRenderCost = max((float)histoMaxVal, maxRenderCost);
652
653       
654        const float range = maxRenderCost - minRenderCost;
655        const float stepSize = range / (float)intervals;
656
657        float currentRenderCost = minRenderCost;//(int)ceil(minRenderCost);
658
659        const float totalRenderCost = mViewCellsTree->GetRoot()->GetRenderCost();
660        const float totalVol = GetViewSpaceBox().GetVolume();
661        //const float totalVol = mViewCellsTree->GetRoot()->GetVolume();
662
663        int j = 0;
664        int i = 0;
665       
666        ViewCellContainer::const_iterator it = viewCells.begin(), it_end = viewCells.end();             
667
668        // count for integral
669        float volSum = 0;
670        int smallerCostSum = 0;
671       
672        // note can skip computations for view cells already evaluated and delete them from vector ...
673    while (1)
674        {
675                // count for histogram value
676                float volDif = 0;
677                int smallerCostDif = 0;
678
679                while ((i < (int)viewCells.size()) && (viewCells[i]->GetRenderCost() < currentRenderCost))
680                {
681                        volSum += viewCells[i]->GetVolume();
682                        volDif += viewCells[i]->GetVolume();
683
684                        ++ i;
685                        ++ smallerCostSum;
686                        ++ smallerCostDif;
687                }
688               
689                if ((i >= (int)viewCells.size()) || (currentRenderCost >= maxRenderCost))
690                        break;
691               
692                const float rcRatio = currentRenderCost / maxRenderCost;
693                const float volRatioSum = volSum / totalVol;
694                const float volRatioDif = volDif / totalVol;
695
696                outstream << "#Pass\n" << j ++ << endl;
697                outstream << "#RenderCostRatio\n" << rcRatio << endl;
698                outstream << "#WeightedCost\n" << currentRenderCost / totalVol << endl;
699                outstream << "#ViewCellsDif\n" << smallerCostDif << endl;
700                outstream << "#ViewCellsSum\n" << smallerCostSum << endl;       
701                outstream << "#VolumeDif\n" << volRatioDif << endl << endl;
702                outstream << "#VolumeSum\n" << volRatioSum << endl << endl;
703
704                // increase current render cost
705                currentRenderCost += stepSize;
706        }
707
708        outstream.close();
709}
710
711
712
713ViewCellsManager *ViewCellsManager::LoadViewCells(const string &filename,
714                                                                                                  ObjectContainer *objects,
715                                                                                                  bool finalizeViewCells,
716                                                                                                  BoundingBoxConverter *bconverter)
717                                                                                                 
718{
719        ViewCellsParser parser;
720        ViewCellsManager *vm = NULL;
721
722        const long startTime = GetTime();
723        bool success = parser.ParseViewCellsFile(filename, &vm, objects, bconverter);
724
725        cout<<"viewcells parsed "<<endl<<flush;
726       
727        if (success)
728        {
729                //vm->ResetViewCells();
730                //hack
731                vm->mViewCells.clear();
732                ViewCellContainer leaves;
733                vm->mViewCellsTree->CollectLeaves(vm->mViewCellsTree->GetRoot(), leaves);
734
735                ViewCellContainer::const_iterator it, it_end = leaves.end();
736
737                for (it = leaves.begin(); it != it_end; ++ it)
738                {
739                        vm->mViewCells.push_back(*it);
740                }
741                vm->mViewCellsFinished = true;
742                vm->mMaxPvsSize = (int)objects->size();
743
744                if (finalizeViewCells)
745                {
746                        // create the meshes and compute volumes
747                        vm->FinalizeViewCells(true);
748                        // vm->mViewCellsTree->AssignRandomColors();
749                }
750
751                Debug << (int)vm->mViewCells.size() << " view cells loaded in "
752                          << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
753        }
754        else
755        {
756                Debug << "Error: loading view cells failed!" << endl;
757                DEL_PTR(vm);
758        }
759
760        return vm;
761}
762
763
764bool VspBspViewCellsManager::ExportViewCells(const string filename,
765                                                                                         const bool exportPvs,
766                                                                                         const ObjectContainer &objects)
767{
768        if (!ViewCellsConstructed() || !ViewCellsTreeConstructed())
769        {
770                return false;
771        }
772
773        cout << "exporting view cells to xml ... ";
774
775        OUT_STREAM stream(filename.c_str());
776
777        // for output we need unique ids for each view cell
778        CreateUniqueViewCellIds();
779
780        stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<endl;
781        stream << "<VisibilitySolution>" << endl;
782
783        if (exportPvs)
784        {
785                //-- export bounding boxes
786                stream << "<BoundingBoxes>" << endl;
787#if USE_KD_PVS
788                vector<KdIntersectable *>::iterator kit, kit_end = GetPreprocessor()->mKdTree->mKdIntersectables.end();
789
790                int id = 0;
791                for (kit = GetPreprocessor()->mKdTree->mKdIntersectables.begin(); kit != kit_end; ++ kit, ++ id)
792                {
793                  Intersectable *obj = *kit;
794                  const AxisAlignedBox3 box = obj->GetBox();
795                 
796                  obj->SetId(id);
797                 
798                  stream << "<BoundingBox" << " id=\"" << id << "\""
799                                 << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
800                                 << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\" />" << endl;
801                }
802#else
803                ObjectContainer::const_iterator oit, oit_end = objects.end();
804               
805                for (oit = objects.begin(); oit != oit_end; ++ oit)
806                {
807                        const AxisAlignedBox3 box = (*oit)->GetBox();
808
809                        ////////////
810                        //-- the bounding boxes
811                        stream << "<BoundingBox" << " id=\"" << (*oit)->GetId() << "\""
812                                   << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
813                                   << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\" />" << endl;
814                }
815#endif
816                stream << "</BoundingBoxes>" << endl;
817        }
818
819       
820        /////////////
821        //-- export the view cells and the pvs
822
823        const int numViewCells = mCurrentViewCellsStats.viewCells;
824        stream << "<ViewCells number=\"" << numViewCells << "\" >" << endl;
825
826        mViewCellsTree->Export(stream, exportPvs);
827
828        stream << "</ViewCells>" << endl;
829
830
831        //////////
832        //-- export the view space hierarchy
833       
834        stream << "<ViewSpaceHierarchy type=\"bsp\""
835                   << " min=\"" << mViewSpaceBox.Min().x << " " << mViewSpaceBox.Min().y << " " << mViewSpaceBox.Min().z << "\""
836                   << " max=\"" << mViewSpaceBox.Max().x << " " << mViewSpaceBox.Max().y << " " << mViewSpaceBox.Max().z << "\">" << endl;
837
838        mVspBspTree->Export(stream);
839        stream << "</ViewSpaceHierarchy>" << endl;
840
841        stream << "</VisibilitySolution>" << endl;
842
843        stream.close();
844        cout << "finished" << endl;
845
846        return true;
847}
848
849
850void ViewCellsManager::EvalViewCellHistogramForPvsSize(const string filename,
851                                                                                                           const int nViewCells)
852{
853        std::ofstream outstream;
854        outstream.open(filename.c_str());
855
856        ViewCellContainer viewCells;
857       
858        // $$ JB hack - the collect best viewcells does not work?
859#if 0
860        mViewCellsTree->CollectBestViewCellSet(viewCells, nViewCells);
861#else
862        viewCells = mViewCells;
863#endif
864        ViewCellContainer::iterator it = viewCells.begin(),
865          it_end = viewCells.end();             
866        for (; it != it_end; ++it) {
867          //(*it)->UpdatePvsCost();
868          (*it)->SetPvsCost((float)(*it)->GetFilteredPvsSize());
869        }
870
871        float maxPvs, maxVal, minVal;
872       
873        // sort by pvs size
874        sort(viewCells.begin(), viewCells.end(), ViewCell::SmallerPvs);
875
876        maxPvs = viewCells.back()->GetPvsCost();
877        minVal = 0;
878
879        // hack: normalize pvs size
880        int histoMaxVal;
881        Environment::GetSingleton()->GetIntValue(
882                                                                                         "Preprocessor.histogram.maxValue", histoMaxVal);
883        maxVal = max((float)histoMaxVal, maxPvs);
884               
885        Debug << "histogram minpvssize: " << minVal << " maxpvssize: " << maxVal
886                << " real maxpvs " << maxPvs << endl;
887
888        int histoIntervals;
889        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.intervals", histoIntervals);
890        const int intervals = min(histoIntervals, (int)viewCells.size());
891
892        const float range = maxVal - minVal;
893        int stepSize = (int)(range / intervals);
894
895        // set step size to avoid endless loop
896        if (!stepSize) stepSize = 1;
897       
898        Debug << "stepsize: " << stepSize << endl;
899       
900        const float totalRenderCost = mViewCellsTree->GetRoot()->GetRenderCost();
901        const float totalVol = GetViewSpaceBox().GetVolume();
902
903        float currentPvs = minVal;
904       
905        int i = 0;
906        int j = 0;
907        float volSum = 0;
908        int smallerSum = 0;
909
910        it = viewCells.begin();
911       
912        for (int j = 0; j < intervals; ++ j)
913        {
914                float volDif = 0;
915                int smallerDif = 0;
916
917                while ((i < (int)viewCells.size()) &&
918                           (viewCells[i]->GetPvsCost() < currentPvs))
919                {
920                        volDif += viewCells[i]->GetVolume();
921                        volSum += viewCells[i]->GetVolume();
922
923                        ++ i;
924                        ++ smallerDif;
925                        ++ smallerSum;
926                }
927               
928                //              if (0 && (i < (int)viewCells.size()))
929                //                Debug << "new pvs cost increase: " << mViewCellsTree->GetPvsCost(viewCells[i])
930                //                              << " " << currentPvs << endl;
931               
932                const float volRatioDif = volDif / totalVol;
933                const float volRatioSum = volSum / totalVol;
934
935                outstream << "#Pass\n" << j << endl;
936                outstream << "#Pvs\n" << currentPvs << endl;
937                outstream << "#ViewCellsDif\n" << smallerDif << endl;
938                outstream << "#ViewCellsSum\n" << smallerSum << endl;   
939                outstream << "#VolumeDif\n" << volRatioDif << endl << endl;
940                outstream << "#VolumeSum\n" << volRatioSum << endl << endl;
941       
942                //-- increase current pvs size to define next interval
943                currentPvs += stepSize;
944        }
945
946        outstream.close();
947
948}
949
950
951bool ViewCellsManager::GetExportPvs() const
952{
953        return mExportPvs;
954}
955
956
957void ViewCellsManager::ResetPvs()
958{
959        if (ViewCellsTreeConstructed())
960        {
961                mViewCellsTree->ResetPvs();
962        }
963        else
964        {
965                cout << "view cells tree not constructed" << endl;
966        }
967}
968
969
970void ViewCellsManager::ExportStats(const string &fileName)
971{
972        mViewCellsTree->ExportStats(fileName);
973}
974
975
976void ViewCellsManager::EvalViewCellPartition()
977{
978        int samplesPerPass;
979        int numSamples;
980        int castSamples = 0;
981        char str[64];
982        int oldSamples = 0;
983
984        int samplesForStats;
985
986        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesPerPass", samplesPerPass);
987        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesForStats", samplesForStats);
988        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samples", numSamples);
989
990        char statsPrefix[100];
991        Environment::GetSingleton()->GetStringValue("ViewCells.Evaluation.statsPrefix", statsPrefix);
992
993        Debug << "view cell evaluation samples per pass: " << samplesPerPass << endl;
994        Debug << "view cell evaluation samples: " << numSamples << endl;
995        Debug << "view cell stats prefix: " << statsPrefix << endl;
996
997        cout << "reseting pvs ... ";
998               
999        const bool startFromZero = true;
1000
1001        // reset pvs and start over from zero
1002        if (startFromZero)
1003        {
1004                mViewCellsTree->ResetPvs();
1005        }
1006        else // start from current sampless
1007        {
1008                // statistics before casting more samples
1009                cout << "compute new statistics ... ";
1010                sprintf(str, "-%09d-eval.log", castSamples);
1011                string fName = string(statsPrefix) + string(str);
1012
1013                mViewCellsTree->ExportStats(fName);
1014                cout << "finished" << endl;
1015        }
1016
1017        cout << "finished" << endl;
1018    cout << "Evaluating view cell partition ... " << endl;
1019
1020        while (castSamples < numSamples)
1021        {               
1022                ///////////////
1023                //-- we have to use uniform sampling strategy for construction rays
1024
1025                VssRayContainer evaluationSamples;
1026                const int samplingType = mEvaluationSamplingType;
1027
1028                long startTime = GetTime();
1029
1030                cout << "casting " << samplesPerPass << " samples ... ";
1031                Debug << "casting " << samplesPerPass << " samples ... ";
1032
1033                CastPassSamples(samplesPerPass, mStrategies, evaluationSamples);
1034               
1035                castSamples += samplesPerPass;
1036
1037                Real timeDiff = TimeDiff(startTime, GetTime());
1038               
1039                cout << "finished in " << timeDiff * 1e-3f << " secs" << endl;
1040                cout << "computing sample contributions of " << (int)evaluationSamples.size()  << " samples ... ";
1041               
1042                Debug << "finished in " << timeDiff * 1e-3f << " secs" << endl;
1043                Debug << "computing sample contributions of " << (int)evaluationSamples.size()  << " samples ... ";
1044
1045                startTime = GetTime();
1046
1047                ComputeSampleContributions(evaluationSamples, true, false);
1048
1049                timeDiff = TimeDiff(startTime, GetTime());
1050                cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
1051                Debug << "finished in " << timeDiff * 1e-3 << " secs" << endl;
1052
1053                if ((castSamples >= samplesForStats + oldSamples) || (castSamples >= numSamples))
1054                {
1055                        oldSamples += samplesForStats;
1056
1057                        ///////////
1058                        //-- output stats
1059
1060                        sprintf(str, "-%09d-eval.log", castSamples);
1061                        string fileName = string(statsPrefix) + string(str);
1062
1063                        ///////////////
1064                        //-- propagate pvs or pvs size information
1065
1066                        startTime = GetTime();
1067                        ObjectPvs pvs;
1068
1069                        cout << "updating pvs for evaluation ... " << endl;
1070
1071                        UpdatePvsForEvaluation(mViewCellsTree->GetRoot(), pvs);
1072
1073                        timeDiff = TimeDiff(startTime, GetTime());
1074                        cout << "finished updating the pvs in " << timeDiff * 1e-3 << " secs" << endl;
1075                        Debug << "pvs evaluated in " << timeDiff * 1e-3 << " secs" << endl;
1076               
1077                        startTime = GetTime();
1078                        cout << "compute new statistics ... " << endl;
1079
1080                        ExportStats(fileName);
1081
1082                        timeDiff = TimeDiff(startTime, GetTime());
1083                        cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
1084                        Debug << "statistis computed in " << timeDiff * 1e-3 << " secs" << endl;
1085                }
1086
1087                disposeRays(evaluationSamples, NULL);
1088        }
1089       
1090
1091        ////////////
1092        //-- histogram
1093
1094        const int numLeaves = mViewCellsTree->GetNumInitialViewCells(mViewCellsTree->GetRoot());
1095        bool useHisto;
1096        int histoStepSize;
1097
1098        Environment::GetSingleton()->GetBoolValue("ViewCells.Evaluation.histogram", useHisto);
1099        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.histoStepSize", histoStepSize);
1100
1101        if (useHisto)
1102        {
1103                // evaluate view cells in a histogram           
1104                char s[64];
1105
1106                for (int pass = histoStepSize; pass <= numLeaves; pass += histoStepSize)
1107                {
1108                        string filename;
1109
1110                        cout << "computing histogram for " << pass << " view cells" << endl;
1111#if 0
1112                        //-- evaluate histogram for render cost
1113                        sprintf(s, "-%09d-histo.log", pass);
1114                        filename = string(statsPrefix) + string(s);
1115
1116                        EvalViewCellHistogram(filename, pass);
1117
1118#endif
1119                        //////////////////////////////////////////
1120            //-- evaluate histogram for pvs size
1121
1122                        cout << "computing pvs histogram for " << pass << " view cells" << endl;
1123
1124                        sprintf(s, "-%09d-histo-pvs.log", pass);
1125                        filename = string(statsPrefix) + string(s);
1126
1127                        EvalViewCellHistogramForPvsSize(filename, pass);
1128                }
1129        }
1130}
1131
1132
1133inline float EvalMergeCost(ViewCell *root, ViewCell *candidate)
1134{
1135        return root->GetPvs().GetPvsHomogenity(candidate->GetPvs());
1136}
1137
1138
1139/// Returns index of the best view cells of the neighborhood
1140static int GetBestViewCellIdx(ViewCell *root, const ViewCellContainer &neighborhood)
1141{
1142        int bestViewCellIdx = 0;
1143
1144        float mergeCost = Limits::Infinity;
1145        int i = 0;
1146
1147        ViewCellContainer::const_iterator vit, vit_end = neighborhood.end();
1148
1149        for (vit = neighborhood.begin(); vit != vit_end; ++ vit, ++ i)
1150        {
1151                const float mc = EvalMergeCost(root, *vit);
1152               
1153                if (mc < mergeCost)
1154                {
1155                        mergeCost = mc;
1156                        bestViewCellIdx = i;
1157                }
1158        }
1159
1160        return bestViewCellIdx;
1161}
1162
1163
1164void ViewCellsManager::SetMaxFilterSize(const int size)
1165{
1166        mMaxFilterSize = size;
1167}
1168
1169
1170float ViewCellsManager::EvalRenderCost(Intersectable *obj) //const
1171{
1172        switch (sRenderCostEvaluationType)
1173        {
1174        case PER_OBJECT:
1175                return 1.0f;
1176       
1177        case PER_TRIANGLE:
1178                {
1179                        return (float)obj->NumberOfFaces();
1180                }
1181        default:
1182                cout << "default" << endl;
1183                return 1.0f;
1184        }
1185
1186        // should not come here
1187        return 0.0f;
1188}
1189
1190
1191ViewCell *ViewCellsManager::ConstructLocalMergeTree(ViewCell *currentViewCell,
1192                                                                                                        const ViewCellContainer &viewCells)
1193{
1194        ViewCell *root = currentViewCell;
1195        ViewCellContainer neighborhood = viewCells;
1196
1197        ViewCellContainer::const_iterator it, it_end = neighborhood.end();
1198
1199        const int n = min(mMaxFilterSize, (int)neighborhood.size());
1200       
1201        /////////////////
1202        //-- use priority queue to merge leaf pairs
1203       
1204        for (int nMergedViewCells = 0; nMergedViewCells < n; ++ nMergedViewCells)
1205        {
1206                const int bestViewCellIdx = GetBestViewCellIdx(root, neighborhood);
1207               
1208                ViewCell *bestViewCell = neighborhood[bestViewCellIdx];
1209       
1210                // remove from vector
1211                swap(neighborhood[bestViewCellIdx], neighborhood.back());
1212                neighborhood.pop_back();
1213       
1214                if (!bestViewCell || !root)
1215            cout << "warning!!" << endl;
1216               
1217                // create new root of the hierarchy
1218                root = MergeViewCells(root, bestViewCell);
1219        }
1220
1221        return root;   
1222}
1223
1224
1225struct SortableViewCellEntry {
1226
1227        SortableViewCellEntry() {}
1228        SortableViewCellEntry(const float v, ViewCell *cell):mValue(v), mViewCell(cell) {}
1229
1230        float mValue;
1231        ViewCell *mViewCell;
1232
1233        friend bool operator<(const SortableViewCellEntry &a, const SortableViewCellEntry &b) {
1234                return a.mValue < b.mValue;
1235        }
1236};
1237
1238
1239ViewCell * ViewCellsManager::ConstructLocalMergeTree2(ViewCell *currentViewCell,
1240                                                                                                          const ViewCellContainer &viewCells)
1241{
1242 
1243  vector<SortableViewCellEntry> neighborhood(viewCells.size());
1244  int i, j;
1245  for (i = 0, j = 0; i < viewCells.size(); i++) {
1246        if (viewCells[i] != currentViewCell)
1247          neighborhood[j++] = SortableViewCellEntry(
1248                                                                                                EvalMergeCost(currentViewCell, viewCells[i]),
1249                                                                                                viewCells[i]);
1250  }
1251  neighborhood.resize(j);
1252 
1253  sort(neighborhood.begin(), neighborhood.end());
1254 
1255  ViewCell *root = currentViewCell;
1256 
1257  vector<SortableViewCellEntry>::const_iterator it, it_end = neighborhood.end();
1258 
1259  const int n = min(mMaxFilterSize, (int)neighborhood.size());
1260  //-- use priority queue to merge leaf pairs
1261 
1262  //cout << "neighborhood: " << neighborhood.size() << endl;
1263  for (int nMergedViewCells = 0; nMergedViewCells < n; ++ nMergedViewCells)
1264  {
1265          ViewCell *bestViewCell = neighborhood[nMergedViewCells].mViewCell;
1266          //cout <<nMergedViewCells<<":"<<"homogenity=" <<neighborhood[nMergedViewCells].mValue<<endl;
1267          // create new root of the hierarchy
1268          root = MergeViewCells(root, bestViewCell);
1269          // set negative cost so that this view cell gets deleted
1270          root->SetMergeCost(-1.0f);
1271  }
1272 
1273  return root; 
1274}
1275
1276void
1277ViewCellsManager::DeleteLocalMergeTree(ViewCell *vc
1278                                                                           ) const
1279{
1280        if (!vc->IsLeaf() && vc->GetMergeCost() < 0.0f)
1281        {       
1282                ViewCellInterior *vci = (ViewCellInterior *) vc;
1283                ViewCellContainer::const_iterator it, it_end = vci->mChildren.end();
1284
1285        for (it = vci->mChildren.begin(); it != it_end; ++ it)
1286                        DeleteLocalMergeTree(*it);
1287               
1288                vci->mChildren.clear();
1289               
1290                delete vci;
1291  }
1292}
1293
1294
1295bool ViewCellsManager::CheckValidity(ViewCell *vc,
1296                                                                         int minPvsSize,
1297                                                                         int maxPvsSize) const
1298{
1299
1300        if ((vc->GetPvs().EvalPvsCost() > maxPvsSize) ||
1301                (vc->GetPvs().EvalPvsCost() < minPvsSize))
1302        {
1303                return false;
1304        }
1305
1306        return true;
1307}
1308
1309
1310int ViewCellsManager::ComputeBoxIntersections(const AxisAlignedBox3 &box,
1311                                                                                          ViewCellContainer &viewCells) const
1312{
1313        return 0;
1314};
1315
1316
1317AxisAlignedBox3 ViewCellsManager::GetFilterBBox(const Vector3 &viewPoint,
1318                                                                                                const float width) const
1319{
1320  float w = Magnitude(mViewSpaceBox.Size())*width;
1321  Vector3 min = viewPoint - w * 0.5f;
1322  Vector3 max = viewPoint + w * 0.5f;
1323 
1324  return AxisAlignedBox3(min, max);
1325}
1326
1327
1328void ViewCellsManager::GetPrVS(const Vector3 &viewPoint,
1329                                                           PrVs &prvs,
1330                                                           const float filterWidth)
1331{
1332  ViewCell *currentViewCell = GetViewCell(viewPoint);
1333
1334  if (mMaxFilterSize < 1) {
1335        prvs.mViewCell = currentViewCell;
1336        return;
1337  }
1338 
1339  const AxisAlignedBox3 box = GetFilterBBox(viewPoint, filterWidth);
1340 
1341  if (currentViewCell)
1342        {
1343          ViewCellContainer viewCells;
1344          ComputeBoxIntersections(box, viewCells);
1345         
1346          ViewCell *root = ConstructLocalMergeTree2(currentViewCell, viewCells);
1347          prvs.mViewCell = root;
1348         
1349        }
1350  else
1351        {
1352          prvs.mViewCell = NULL;
1353          //prvs.mPvs = root->GetPvs();
1354        }
1355}
1356
1357
1358bool ViewCellsManager::ViewCellsTreeConstructed() const
1359{
1360    return (mViewCellsTree && mViewCellsTree->GetRoot());
1361}
1362
1363
1364void ViewCellsManager::SetValidity(ViewCell *vc,
1365                                                                   int minPvs,
1366                                                                   int maxPvs) const
1367{
1368        vc->SetValid(CheckValidity(vc, minPvs, maxPvs));
1369}
1370
1371
1372void
1373ViewCellsManager::SetValidity(
1374                                                          int minPvsSize,
1375                                                          int maxPvsSize) const
1376{
1377        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1378
1379
1380        for (it = mViewCells.begin(); it != it_end; ++ it)
1381        {
1382                SetValidity(*it, minPvsSize, maxPvsSize);
1383        }
1384}
1385
1386void
1387ViewCellsManager::SetValidityPercentage(
1388                                                                                const float minValid,
1389                                                                                const float maxValid
1390                                                                                )
1391{
1392  ObjectPvs dummyPvs;
1393  // update pvs sizes
1394  for (int i = 0; i < (int)mViewCells.size(); ++ i) {
1395        UpdatePvsForEvaluation(mViewCells[i], dummyPvs);
1396  }
1397 
1398  sort(mViewCells.begin(), mViewCells.end(), ViewCell::SmallerPvs);
1399 
1400  int start = (int)(mViewCells.size() * minValid);
1401  int end = (int)(mViewCells.size() * maxValid);
1402 
1403  for (int i = 0; i < (int)mViewCells.size(); ++ i)
1404        {
1405          //      cout<<"pvs:"<<mViewCells[i]->GetCachedPvsCost()<<endl;
1406          mViewCells[i]->SetValid(i >= start && i <= end);
1407        }
1408}
1409
1410
1411int ViewCellsManager::CountValidViewcells() const
1412{
1413        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1414        int valid = 0;
1415
1416        for (it = mViewCells.begin(); it != it_end; ++ it)
1417        {       
1418                if ((*it)->GetValid())
1419                        ++ valid;
1420        }
1421
1422        return valid;
1423}
1424
1425
1426bool ViewCellsManager::LoadViewCellsGeometry(const string filename,
1427                                                                                         const bool extrudeBaseTriangles)
1428{
1429        /// we use predefined view cells from now on
1430        mUsePredefinedViewCells = true;
1431        X3dParser parser;
1432       
1433        if (extrudeBaseTriangles)
1434        {
1435                Environment::GetSingleton()->GetFloatValue("ViewCells.height", parser.mViewCellHeight);
1436                const bool success = parser.ParseFile(filename, *this);
1437
1438                if (!success)
1439                        return false;
1440        }
1441        else
1442        {
1443                // hack: use standard mesh loading
1444                // create temporary scene graph for loading the view cells geometry
1445                // note: delete the meshes as they are created two times for transformed mesh instances.
1446                SceneGraphNode *root = new SceneGraphNode();
1447                const bool success = parser.ParseFile(filename, root, true);
1448               
1449                if (!success)
1450                {
1451                        DEL_PTR(root);
1452                        return false;
1453                }
1454
1455                ObjectContainer::const_iterator oit, oit_end = root->mGeometry.end();
1456               
1457                for (oit = root->mGeometry.begin(); oit != oit_end; ++ oit)
1458                {
1459                        Mesh *mesh;
1460                        if ((*oit)->Type() == Intersectable::TRANSFORMED_MESH_INSTANCE)
1461                        {
1462                                TransformedMeshInstance *mit = dynamic_cast<TransformedMeshInstance *>(*oit);
1463                                mesh = MeshManager::GetSingleton()->CreateResource();
1464                                mit->GetTransformedMesh(*mesh);
1465                        }
1466                        else if ((*oit)->Type() == Intersectable::MESH_INSTANCE)
1467                        {
1468                                MeshInstance *mit = dynamic_cast<MeshInstance *>(*oit);
1469                                mesh = mit->GetMesh();
1470                        }
1471                        mesh->ComputeBoundingBox();
1472                        mViewCells.push_back(GenerateViewCell(mesh));
1473                }
1474
1475                DEL_PTR(root);
1476        }
1477
1478        // set view space box to bounding box of the view cells
1479        AxisAlignedBox3 bbox;
1480        bbox.Initialize();
1481        ViewCellContainer::iterator it = mViewCells.begin(), it_end = mViewCells.end();
1482
1483        for (; it != it_end; ++ it)
1484        {
1485                bbox.Include((*it)->GetMesh()->mBox);
1486        }
1487
1488        SetViewSpaceBox(bbox);
1489        cout << "view space box: " << bbox << endl;
1490        cout << "generated " << (int)mViewCells.size() << " view cells using the geometry " << filename << endl;
1491
1492        return true;
1493}
1494
1495
1496bool ViewCellsManager::GetViewPoint(Vector3 &viewPoint) const
1497{
1498  viewPoint = mViewSpaceBox.GetRandomPoint();
1499  return true;
1500}
1501
1502bool ViewCellsManager::GetViewPoint(Vector3 &viewPoint, const Vector3 &params) const
1503{
1504  viewPoint = mViewSpaceBox.GetRandomPoint(params);
1505  return true;
1506}
1507
1508
1509float ViewCellsManager::GetViewSpaceVolume()
1510{
1511        return mViewSpaceBox.GetVolume() * (2.0f * sqr((float)M_PI));
1512}
1513
1514
1515bool ViewCellsManager::ViewPointValid(const Vector3 &viewPoint) const
1516{
1517        if (!ViewCellsConstructed())
1518        {
1519                return mViewSpaceBox.IsInside(viewPoint);
1520        }
1521        else
1522        {
1523                if (!mViewSpaceBox.IsInside(viewPoint))
1524                        return false;
1525
1526                ViewCell *viewcell = GetViewCell(viewPoint);
1527
1528                if (!viewcell || !viewcell->GetValid())
1529                        return false;
1530        }
1531
1532        return true;
1533}
1534
1535
1536float
1537ViewCellsManager::ComputeSampleContributions(const VssRayContainer &rays,
1538                                                                                         const bool addRays,
1539                                                                                         const bool storeViewCells)
1540{
1541  float sum = 0.0f;
1542
1543  VssRayContainer::const_iterator it, it_end = rays.end();
1544 
1545  for (it = rays.begin(); it != it_end; ++ it)
1546        {
1547          if (!ViewCellsConstructed()) {
1548                // view cells not yet constructed
1549                // just take the lenghts of the rays as contributions
1550                if ((*it)->mTerminationObject)
1551                  sum += (*it)->Length();
1552          } else {
1553                sum += ComputeSampleContribution(*(*it), addRays, storeViewCells);
1554          }
1555        }
1556 
1557  return sum;
1558}
1559
1560
1561void ViewCellsManager::EvaluateViewCellsStats()
1562{
1563        mCurrentViewCellsStats.Reset();
1564        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1565
1566        for (it = mViewCells.begin(); it != it_end; ++ it)
1567        {
1568                mViewCellsTree->UpdateViewCellsStats(*it, mCurrentViewCellsStats);
1569        }
1570}
1571
1572
1573void ViewCellsManager::EvaluateRenderStatistics(float &totalRenderCost,
1574                                                                                                float &expectedRenderCost,
1575                                                                                                float &deviation,
1576                                                                                                float &variance,
1577                                                                                                float &totalCost,
1578                                                                                                float &avgRenderCost)
1579{
1580        ////////////
1581        //-- compute expected value
1582
1583        totalRenderCost = 0;
1584        totalCost = 0;
1585
1586        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1587
1588        for (it = mViewCells.begin(); it != it_end; ++ it)
1589        {
1590                ViewCell *vc = *it;
1591                totalRenderCost += vc->GetPvs().EvalPvsCost() * vc->GetVolume();
1592                totalCost += (int)vc->GetPvs().EvalPvsCost();
1593        }
1594
1595        // normalize with view space box
1596        totalRenderCost /= mViewSpaceBox.GetVolume();
1597        expectedRenderCost = totalRenderCost / (float)mViewCells.size();
1598        avgRenderCost = totalCost / (float)mViewCells.size();
1599
1600
1601        ///////////
1602        //-- compute standard defiation
1603
1604        variance = 0;
1605        deviation = 0;
1606
1607        for (it = mViewCells.begin(); it != it_end; ++ it)
1608        {
1609                ViewCell *vc = *it;
1610
1611                float renderCost = vc->GetPvs().EvalPvsCost() * vc->GetVolume();
1612                float dev;
1613
1614                if (1)
1615                        dev = fabs(avgRenderCost - (float)vc->GetPvs().EvalPvsCost());
1616                else
1617                        dev = fabs(expectedRenderCost - renderCost);
1618
1619                deviation += dev;
1620                variance += dev * dev;
1621        }
1622
1623        variance /= (float)mViewCells.size();
1624        deviation /= (float)mViewCells.size();
1625}
1626
1627
1628float ViewCellsManager::GetArea(ViewCell *viewCell) const
1629{
1630        return viewCell->GetArea();
1631}
1632
1633
1634float ViewCellsManager::GetVolume(ViewCell *viewCell) const
1635{
1636        return viewCell->GetVolume();
1637}
1638
1639
1640void ViewCellsManager::CompressViewCells()
1641{
1642        if (!(ViewCellsTreeConstructed() && mCompressViewCells))
1643                return;
1644
1645        ////////////
1646        //-- compression
1647       
1648        int pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
1649
1650        cout << "number of entries before compress: " << pvsEntries << endl;
1651        Debug << "number of entries before compress: " << pvsEntries << endl;
1652
1653        mViewCellsTree->SetViewCellsStorage(ViewCellsTree::COMPRESSED);
1654
1655        pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
1656
1657        Debug << "number of entries after compress: " << pvsEntries << endl;
1658        cout << "number of entries after compress: " << pvsEntries << endl;
1659}
1660
1661
1662ViewCell *ViewCellsManager::ExtrudeViewCell(const Triangle3 &baseTri,
1663                                                                                        const float height) const
1664{
1665        // one mesh per view cell
1666        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
1667
1668        ////////////
1669        //-- construct prism
1670
1671        // bottom
1672        mesh->mFaces.push_back(new Face(2,1,0));
1673        // top
1674    mesh->mFaces.push_back(new Face(3,4,5));
1675        // sides
1676        mesh->mFaces.push_back(new Face(1, 4, 3, 0));
1677        mesh->mFaces.push_back(new Face(2, 5, 4, 1));
1678        mesh->mFaces.push_back(new Face(3, 5, 2, 0));
1679
1680
1681        /////////////
1682        //-- extrude new vertices for top of prism
1683
1684        const Vector3 triNorm = baseTri.GetNormal();
1685        Triangle3 topTri;
1686
1687        // add base vertices and calculate top vertices
1688        for (int i = 0; i < 3; ++ i)
1689        {
1690                mesh->mVertices.push_back(baseTri.mVertices[i]);
1691        }
1692
1693        // add top vertices
1694        for (int i = 0; i < 3; ++ i)
1695        {
1696                mesh->mVertices.push_back(baseTri.mVertices[i] + height * triNorm);
1697        }
1698
1699        // do we have to preprocess this mesh (we don't want to trace view cells!)?
1700        mesh->ComputeBoundingBox();
1701       
1702        return GenerateViewCell(mesh);
1703}
1704
1705
1706void ViewCellsManager::FinalizeViewCells(const bool createMesh)
1707{
1708        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1709
1710        // volume and area of the view cells are recomputed
1711        // a view cell mesh is created
1712        for (it = mViewCells.begin(); it != it_end; ++ it)
1713        {
1714                Finalize(*it, createMesh);
1715        }
1716
1717        mViewCellsTree->AssignRandomColors();
1718
1719        mTotalAreaValid = false;
1720}
1721
1722
1723void ViewCellsManager::Finalize(ViewCell *viewCell, const bool createMesh)
1724{
1725        // implemented in subclasses
1726}
1727
1728
1729/** fast way of merging 2 view cells.
1730*/
1731ViewCellInterior *ViewCellsManager::MergeViewCells(ViewCell *left, ViewCell *right) const
1732{
1733        // generate parent view cell
1734        ViewCellInterior *vc = new ViewCellInterior();
1735
1736        vc->GetPvs().Clear();
1737        ObjectPvs::Merge(vc->GetPvs(), left->GetPvs(), right->GetPvs());
1738
1739        // set only links to child (not from child to parent, maybe not wished!!)
1740        vc->mChildren.push_back(left);
1741        vc->mChildren.push_back(right);
1742
1743        // update pvs size
1744        UpdateScalarPvsSize(vc, vc->GetPvs().EvalPvsCost(), vc->GetPvs().GetSize());
1745
1746        return vc;
1747}
1748
1749
1750ViewCellInterior *ViewCellsManager::MergeViewCells(ViewCellContainer &children) const
1751{
1752        ViewCellInterior *vc = new ViewCellInterior();
1753        ViewCellContainer::const_iterator it, it_end = children.end();
1754
1755        for (it = children.begin(); it != it_end; ++ it)
1756        {
1757                vc->GetPvs().MergeInPlace((*it)->GetPvs());
1758       
1759                vc->mChildren.push_back(*it);
1760        }
1761
1762        return vc;
1763}
1764
1765
1766void ViewCellsManager::SetRenderer(Renderer *renderer)
1767{
1768        mRenderer = renderer;
1769}
1770
1771
1772ViewCellsTree *ViewCellsManager::GetViewCellsTree()
1773{
1774        return mViewCellsTree;
1775}
1776
1777
1778void ViewCellsManager::SetVisualizationSamples(const int visSamples)
1779{
1780        mVisualizationSamples = visSamples;
1781}
1782
1783
1784void ViewCellsManager::SetConstructionSamples(const int constructionSamples)
1785{
1786        mConstructionSamples = constructionSamples;
1787}
1788
1789
1790void ViewCellsManager::SetInitialSamples(const int initialSamples)
1791{
1792        mInitialSamples = initialSamples;
1793}
1794
1795
1796void ViewCellsManager::SetPostProcessSamples(const int postProcessSamples)
1797{
1798        mPostProcessSamples = postProcessSamples;
1799}
1800
1801
1802int ViewCellsManager::GetVisualizationSamples() const
1803{
1804        return mVisualizationSamples;
1805}
1806
1807
1808int ViewCellsManager::GetConstructionSamples() const
1809{
1810        return mConstructionSamples;
1811}
1812
1813
1814int ViewCellsManager::GetPostProcessSamples() const
1815{
1816        return mPostProcessSamples;
1817}
1818
1819
1820void ViewCellsManager::UpdatePvs()
1821{
1822  if (mViewCellPvsIsUpdated || !ViewCellsTreeConstructed())
1823        return;
1824 
1825  mViewCellPvsIsUpdated = true;
1826 
1827  ViewCellContainer leaves;
1828  mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
1829 
1830  ViewCellContainer::const_iterator it, it_end = leaves.end();
1831 
1832  for (it = leaves.begin(); it != it_end; ++ it)
1833        {
1834          mViewCellsTree->PropagatePvs(*it);
1835        }
1836}
1837
1838
1839void ViewCellsManager::GetPvsStatistics(PvsStatistics &stat)
1840{
1841  // update pvs of view cells tree if necessary
1842  UpdatePvs();
1843 
1844  ViewCellContainer::const_iterator it = mViewCells.begin();
1845 
1846  stat.viewcells = 0;
1847  stat.minPvs = 100000000;
1848  stat.maxPvs = 0;
1849  stat.avgPvs = 0.0f;
1850  stat.avgFilteredPvs = 0.0f;
1851  stat.avgFilterContribution = 0.0f;
1852  stat.avgFilterRadius = 0;
1853  stat.avgFilterRatio = 0;
1854 
1855  for (; it != mViewCells.end(); ++ it)
1856        {
1857          ViewCell *viewcell = *it;
1858          if (viewcell->GetValid()) {
1859                const float pvsCost = mViewCellsTree->GetPvsCost(viewcell);
1860               
1861                if (pvsCost < stat.minPvs)
1862                  stat.minPvs = pvsCost;
1863                if (pvsCost > stat.maxPvs)
1864                  stat.maxPvs = pvsCost;
1865               
1866                stat.avgPvs += pvsCost;
1867
1868                bool evaluateFilter;
1869                Environment::GetSingleton()->GetBoolValue("Preprocessor.evaluateFilter", evaluateFilter);
1870               
1871               
1872                if (evaluateFilter) {
1873                  ObjectPvs filteredPvs;
1874                  PvsFilterStatistics fstat = ApplyFilter2(viewcell,
1875                                                                                                   false,
1876                                                                                                   2.0f,
1877                                                                                                   filteredPvs);
1878                 
1879                  float filteredCost = filteredPvs.EvalPvsCost();
1880                  stat.avgFilteredPvs += filteredCost;
1881                  stat.avgFilterContribution += filteredCost - pvsCost;
1882                 
1883                  stat.avgFilterRadius += fstat.mAvgFilterRadius;
1884                  int sum = fstat.mGlobalFilterCount + fstat.mLocalFilterCount;
1885                  if (sum) {
1886                        stat.avgFilterRatio += fstat.mLocalFilterCount /
1887                          (float) sum;
1888                  }
1889                 
1890                } else {
1891                  stat.avgFilteredPvs += pvsCost;
1892                  stat.avgFilterContribution += 0;
1893                }
1894               
1895                ++ stat.viewcells;
1896          }
1897        }
1898 
1899  if (stat.viewcells) {
1900        stat.avgPvs/=stat.viewcells;
1901        stat.avgFilteredPvs/=stat.viewcells;
1902        stat.avgFilterContribution/=stat.viewcells;
1903        stat.avgFilterRadius/=stat.viewcells;
1904        stat.avgFilterRatio/=stat.viewcells;
1905  }
1906}
1907
1908
1909void ViewCellsManager::PrintPvsStatistics(ostream &s)
1910{
1911  s<<"############# Viewcell PVS STAT ##################\n";
1912  PvsStatistics pvsStat;
1913  GetPvsStatistics(pvsStat);
1914  s<<"#AVG_PVS\n"<<pvsStat.avgPvs<<endl;
1915  s<<"#AVG_FILTERED_PVS\n"<<pvsStat.avgFilteredPvs<<endl;
1916  s<<"#AVG_FILTER_CONTRIBUTION\n"<<pvsStat.avgFilterContribution<<endl;
1917  s<<"#AVG_FILTER_RADIUS\n"<<pvsStat.avgFilterRadius<<endl;
1918  s<<"#AVG_FILTER_RATIO\n"<<pvsStat.avgFilterRatio<<endl;
1919  s<<"#MAX_PVS\n"<<pvsStat.maxPvs<<endl;
1920  s<<"#MIN_PVS\n"<<pvsStat.minPvs<<endl;
1921}
1922
1923
1924int ViewCellsManager::CastBeam(Beam &beam)
1925{
1926        return 0;
1927}
1928
1929
1930ViewCellContainer &ViewCellsManager::GetViewCells()
1931{
1932        return mViewCells;
1933}
1934
1935
1936void ViewCellsManager::SetViewSpaceBox(const AxisAlignedBox3 &box)
1937{
1938        mViewSpaceBox = box;
1939       
1940        // hack: create clip plane relative to new view space box
1941        CreateClipPlane();
1942        // the total area of the view space has changed
1943        mTotalAreaValid = false;
1944}
1945
1946
1947void ViewCellsManager::CreateClipPlane()
1948{
1949        int axis = 0;
1950        float pos;
1951        bool orientation;
1952        Vector3 absPos;
1953
1954        Environment::GetSingleton()->GetFloatValue("ViewCells.Visualization.clipPlanePos", pos);
1955        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.clipPlaneAxis", axis);
1956
1957        if (axis < 0)
1958        {
1959                axis = -axis;
1960                orientation = false;
1961                absPos = mViewSpaceBox.Max() -  mViewSpaceBox.Size() * pos;
1962        }
1963        else
1964        {
1965                orientation = true;
1966                absPos = mViewSpaceBox.Min() +  mViewSpaceBox.Size() * pos;
1967        }
1968
1969        mClipPlaneForViz = AxisAlignedPlane(axis, absPos[axis]);
1970        mClipPlaneForViz.mOrientation = orientation;
1971}
1972
1973
1974AxisAlignedBox3 ViewCellsManager::GetViewSpaceBox() const
1975{
1976        return mViewSpaceBox;
1977}
1978
1979
1980void ViewCellsManager::ResetViewCells()
1981{
1982        // recollect view cells
1983        mViewCells.clear();
1984        CollectViewCells();
1985       
1986        // stats are computed once more
1987        EvaluateViewCellsStats();
1988
1989        // has to be recomputed
1990        mTotalAreaValid = false;
1991}
1992
1993
1994int ViewCellsManager::GetMaxPvsSize() const
1995{
1996        return mMaxPvsSize;
1997}
1998
1999
2000int ViewCellsManager::GetMinPvsSize() const
2001{
2002        return mMinPvsSize;
2003}
2004
2005
2006
2007float ViewCellsManager::GetMaxPvsRatio() const
2008{
2009        return mMaxPvsRatio;
2010}
2011
2012
2013
2014#define PVS_ADD_DIRTY 1
2015
2016float
2017ViewCellsManager::ComputeSampleContribution(VssRay &ray,
2018                                                                                        const bool addRays,
2019                                                                                        const bool storeViewCells)
2020{
2021  ray.mPvsContribution = 0;
2022  ray.mRelativePvsContribution = 0.0f;
2023 
2024  if (ray.mTerminationObject==NULL)
2025        return 0.0f;
2026 
2027  ViewCellContainer viewcells;
2028 
2029  static Ray hray;
2030  hray.Init(ray);
2031
2032  float tmin = 0, tmax = 1.0;
2033 
2034  if (!GetViewSpaceBox().GetRaySegment(hray, tmin, tmax) || (tmin > tmax))
2035        return 0;
2036 
2037  Vector3 origin = hray.Extrap(tmin);
2038  Vector3 termination = hray.Extrap(tmax);
2039 
2040  ViewCell::NewMail();
2041 
2042  // traverse the view space subdivision
2043  CastLineSegment(origin, termination, viewcells);
2044 
2045  if (storeViewCells)
2046        {       
2047          // copy viewcells memory efficiently
2048          ray.mViewCells.reserve(viewcells.size());
2049          ray.mViewCells = viewcells;
2050        }
2051 
2052  ViewCellContainer::const_iterator it = viewcells.begin();
2053 
2054  Intersectable *terminationObj = GetIntersectable(ray, true);
2055 
2056 
2057  for (; it != viewcells.end(); ++ it)
2058        {
2059          ViewCell *viewcell = *it;
2060         
2061          if (viewcell->GetValid())
2062                {       // if ray not outside of view space
2063                  float contribution;
2064                 
2065                  if (terminationObj)
2066                        {
2067                          // todo: maybe not correct for kd node pvs
2068                          bool absContribution = viewcell->GetPvs().GetSampleContribution(
2069                                                                                                                                                          terminationObj,
2070                                                                                                                                                          ray.mPdf,
2071                                                                                                                                                          contribution);
2072#if DIST_WEIGHTED_CONTRIBUTION
2073                          // clear the relative contribution
2074                          contribution = 0.0f;
2075#endif
2076                          if (absContribution)
2077                                {
2078                                  ++ ray.mPvsContribution;
2079                                  if (addRays) {
2080#if PVS_ADD_DIRTY
2081                                        viewcell->GetPvs().AddSampleDirtyCheck(terminationObj, ray.mPdf);
2082                                        if (viewcell->GetPvs().RequiresResort()) {
2083                                          viewcell->GetPvs().SimpleSort();
2084                                        }
2085#else
2086                                        viewcell->GetPvs().AddSample(terminationObj, ray.mPdf);
2087#endif
2088                                  }
2089#if DIST_WEIGHTED_CONTRIBUTION
2090                                  // recalculate the contribution - weight the 1.0f contribution by the sqr distance to the
2091                                  // object-> a new contribution in the proximity of the viewcell has a larger weight!
2092                                  contribution = 1.0f/SqrDistance(GetViewCellBox(viewcell).Center(),
2093                                                                                                  ray.mTermination);
2094#endif
2095                                }
2096                         
2097                          ray.mRelativePvsContribution += contribution;
2098                        }
2099                }
2100        }
2101
2102#if USE_RAY_LENGTH_AS_CONTRIBUTION
2103  float c = 0.0f;
2104  if (terminationObj)
2105        c = ray.Length();
2106  ray.mRelativePvsContribution = ray.mPvsContribution = c;
2107  return c;
2108#else
2109  return ABS_CONTRIBUTION_WEIGHT*ray.mPvsContribution +
2110        (1.0f - ABS_CONTRIBUTION_WEIGHT)*ray.mRelativePvsContribution;
2111#endif
2112}
2113
2114
2115
2116void ViewCellsManager::GetRaySets(const VssRayContainer &sourceRays,
2117                                                                  const int maxSize,
2118                                                                  VssRayContainer &usedRays,
2119                                                                  VssRayContainer *savedRays) const
2120{
2121        const int limit = min(maxSize, (int)sourceRays.size());
2122        const float prop = (float)limit / ((float)sourceRays.size() + Limits::Small);
2123
2124        VssRayContainer::const_iterator it, it_end = sourceRays.end();
2125        for (it = sourceRays.begin(); it != it_end; ++ it)
2126        {
2127                if (Random(1.0f) < prop)
2128                        usedRays.push_back(*it);
2129                else if (savedRays)
2130                        savedRays->push_back(*it);
2131        }
2132}
2133
2134
2135float ViewCellsManager::GetRendercost(ViewCell *viewCell) const
2136{
2137        return (float)mViewCellsTree->GetPvsCost(viewCell);
2138}
2139
2140
2141float ViewCellsManager::GetAccVcArea()
2142{
2143        // if already computed
2144        if (mTotalAreaValid)
2145        {
2146                return mTotalArea;
2147        }
2148
2149        mTotalArea = 0;
2150        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
2151
2152        for (it = mViewCells.begin(); it != it_end; ++ it)
2153        {
2154                //Debug << "area: " << GetArea(*it);
2155        mTotalArea += GetArea(*it);
2156        }
2157
2158        mTotalAreaValid = true;
2159
2160        return mTotalArea;
2161}
2162
2163
2164void ViewCellsManager::PrintStatistics(ostream &s) const
2165{
2166        s << mCurrentViewCellsStats << endl;
2167}
2168
2169
2170void ViewCellsManager::CreateUniqueViewCellIds()
2171{
2172        if (ViewCellsTreeConstructed())
2173        {
2174                mViewCellsTree->CreateUniqueViewCellsIds();
2175        }
2176        else // no view cells tree, handle view cells "myself"
2177        {
2178                int i = 0;
2179                ViewCellContainer::const_iterator vit, vit_end = mViewCells.end();
2180                for (vit = mViewCells.begin(); vit != vit_end; ++ vit)
2181                {
2182                        if ((*vit)->GetId() != OUT_OF_BOUNDS_ID)
2183                        {
2184                                mViewCells[i]->SetId(i ++);
2185                        }
2186                }
2187        }
2188}
2189
2190
2191void ViewCellsManager::ExportViewCellsForViz(Exporter *exporter,
2192                                                                                         const AxisAlignedBox3 *sceneBox,
2193                                                                                         const bool colorCode,
2194                                                                                         const AxisAlignedPlane *clipPlane
2195                                                                                         ) const
2196{
2197        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
2198
2199        for (it = mViewCells.begin(); it != it_end; ++ it)
2200        {
2201                if (!mOnlyValidViewCells || (*it)->GetValid())
2202                {
2203                        ExportColor(exporter, *it, colorCode); 
2204                        ExportViewCellGeometry(exporter, *it, sceneBox, clipPlane);
2205                }
2206        }
2207}
2208
2209
2210void ViewCellsManager::CreateViewCellMeshes()
2211{
2212        // convert to meshes
2213        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
2214
2215        for (it = mViewCells.begin(); it != it_end; ++ it)
2216        {
2217                if (!(*it)->GetMesh())
2218                {
2219                        CreateMesh(*it);
2220                }
2221        }
2222}
2223
2224
2225bool ViewCellsManager::ExportViewCells(const string filename,
2226                                                                           const bool exportPvs,
2227                                                                           const ObjectContainer &objects)
2228{
2229        return false;
2230}
2231
2232
2233void ViewCellsManager::CollectViewCells(const int n)
2234{
2235        mNumActiveViewCells = n;
2236        mViewCells.clear();
2237        // implemented in subclasses
2238        CollectViewCells();
2239}
2240
2241
2242void ViewCellsManager::SetViewCellActive(ViewCell *vc) const
2243{
2244        ViewCellContainer leaves;
2245        // sets the pointers to the currently active view cells
2246        mViewCellsTree->CollectLeaves(vc, leaves);
2247
2248        ViewCellContainer::const_iterator lit, lit_end = leaves.end();
2249        for (lit = leaves.begin(); lit != lit_end; ++ lit)
2250        {
2251                dynamic_cast<ViewCellLeaf *>(*lit)->SetActiveViewCell(vc);
2252        }
2253}
2254
2255
2256void ViewCellsManager::SetViewCellsActive()
2257{
2258        // collect leaf view cells and set the pointers to
2259        // the currently active view cells
2260        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
2261
2262        for (it = mViewCells.begin(); it != it_end; ++ it)
2263        {
2264                SetViewCellActive(*it);
2265        }
2266}
2267
2268
2269int ViewCellsManager::GetMaxFilterSize() const
2270{
2271        return mMaxFilterSize; 
2272}
2273
2274
2275static const bool USE_ASCII = true;
2276
2277
2278bool ViewCellsManager::ExportBoundingBoxes(const string filename,
2279                                                                                   const ObjectContainer &objects) const
2280{
2281        ObjectContainer::const_iterator it, it_end = objects.end();
2282       
2283        if (USE_ASCII)
2284        {
2285                ofstream boxesOut(filename.c_str());
2286                if (!boxesOut.is_open())
2287                        return false;
2288
2289                for (it = objects.begin(); it != it_end; ++ it)
2290                {
2291                        MeshInstance *mi = dynamic_cast<MeshInstance *>(*it);
2292                        const AxisAlignedBox3 box = mi->GetBox();
2293
2294                        boxesOut << mi->GetId() << " "
2295                                         << box.Min().x << " "
2296                                         << box.Min().y << " "
2297                                         << box.Min().z << " "
2298                                         << box.Max().x << " "
2299                                         << box.Max().y << " "
2300                     << box.Max().z << endl;   
2301                }
2302
2303                boxesOut.close();
2304        }
2305        else
2306        {
2307                ofstream boxesOut(filename.c_str(), ios::binary);
2308
2309                if (!boxesOut.is_open())
2310                        return false;
2311
2312                for (it = objects.begin(); it != it_end; ++ it)
2313                {       
2314                        MeshInstance *mi = dynamic_cast<MeshInstance *>(*it);
2315                        const AxisAlignedBox3 box = mi->GetBox();
2316                        Vector3 bmin = box.Min();
2317                        Vector3 bmax = box.Max();
2318                        int id = mi->GetId();
2319
2320                        boxesOut.write(reinterpret_cast<char *>(&id), sizeof(int));
2321                        boxesOut.write(reinterpret_cast<char *>(&bmin), sizeof(Vector3));
2322                        boxesOut.write(reinterpret_cast<char *>(&bmax), sizeof(Vector3));
2323                }
2324               
2325                boxesOut.close();
2326        }
2327
2328        return true;
2329}
2330
2331
2332bool ViewCellsManager::LoadBoundingBoxes(const string filename,
2333                                                                                 IndexedBoundingBoxContainer &boxes) const
2334{
2335        Vector3 bmin, bmax;
2336        int id;
2337
2338        if (USE_ASCII)
2339        {
2340                ifstream boxesIn(filename.c_str());
2341               
2342                if (!boxesIn.is_open())
2343                {
2344                        cout << "failed to open file " << filename << endl;
2345                        return false;
2346                }
2347
2348                string buf;
2349                while (!(getline(boxesIn, buf)).eof())
2350                {
2351                        sscanf(buf.c_str(), "%d %f %f %f %f %f %f",
2352                                   &id, &bmin.x, &bmin.y, &bmin.z,
2353                                   &bmax.x, &bmax.y, &bmax.z);
2354               
2355                        AxisAlignedBox3 box(bmin, bmax);
2356                        //      MeshInstance *mi = new MeshInstance();
2357                        // HACK: set bounding box to new box
2358                        //mi->mBox = box;
2359
2360                        boxes.push_back(IndexedBoundingBox(id, box));
2361                }
2362
2363                boxesIn.close();
2364        }
2365        else
2366        {
2367                ifstream boxesIn(filename.c_str(), ios::binary);
2368
2369                if (!boxesIn.is_open())
2370                        return false;
2371
2372                while (1)
2373                {
2374                        boxesIn.read(reinterpret_cast<char *>(&id), sizeof(Vector3));
2375                        boxesIn.read(reinterpret_cast<char *>(&bmin), sizeof(Vector3));
2376                        boxesIn.read(reinterpret_cast<char *>(&bmax), sizeof(Vector3));
2377                       
2378                        if (boxesIn.eof())
2379                                break;
2380
2381                       
2382                        AxisAlignedBox3 box(bmin, bmax);
2383                        MeshInstance *mi = new MeshInstance(NULL);
2384
2385                        // HACK: set bounding box to new box
2386                        //mi->mBox = box;
2387                        //boxes.push_back(mi);
2388                        boxes.push_back(IndexedBoundingBox(id, box));
2389                }
2390
2391                boxesIn.close();
2392        }
2393
2394        return true;
2395}
2396
2397
2398float ViewCellsManager::GetFilterWidth()
2399{
2400        return mFilterWidth;
2401}
2402
2403
2404float ViewCellsManager::GetAbsFilterWidth()
2405{
2406        return Magnitude(mViewSpaceBox.Size()) * mFilterWidth;
2407}
2408
2409
2410void ViewCellsManager::UpdateScalarPvsSize(ViewCell *vc,
2411                                                                                   const float pvsCost,
2412                                                                                   const int entriesInPvs) const
2413{
2414        vc->mPvsCost = pvsCost;
2415        vc->mEntriesInPvs = entriesInPvs;
2416
2417        vc->mPvsSizeValid = true;
2418}
2419
2420
2421void
2422ViewCellsManager::ApplyFilter(ViewCell *viewCell,
2423                                                          KdTree *kdTree,
2424                                                          const float viewSpaceFilterSize,
2425                                                          const float spatialFilterSize,
2426                                                          ObjectPvs &pvs
2427                                                          )
2428{
2429  // extend the pvs of the viewcell by pvs of its neighbors
2430  // and apply spatial filter by including all neighbors of the objects
2431  // in the pvs
2432
2433  // get all viewcells intersecting the viewSpaceFilterBox
2434  // and compute the pvs union
2435 
2436  //Vector3 center = viewCell->GetBox().Center();
2437  //  Vector3 center = m->mBox.Center();
2438
2439        //  AxisAlignedBox3 box(center - Vector3(viewSpaceFilterSize/2),
2440        //                                        center + Vector3(viewSpaceFilterSize/2));
2441        if (!ViewCellsConstructed())
2442                return;
2443
2444        if (viewSpaceFilterSize >= 0.0f) {
2445
2446                const bool usePrVS = false;
2447
2448                if (!usePrVS) {
2449                        AxisAlignedBox3 box = GetViewCellBox(viewCell);
2450                        box.Enlarge(Vector3(viewSpaceFilterSize/2));
2451
2452                        ViewCellContainer viewCells;
2453                        ComputeBoxIntersections(box, viewCells);
2454
2455                        //  cout<<"box="<<box<<endl;
2456                        ViewCellContainer::const_iterator it = viewCells.begin(), it_end = viewCells.end();
2457
2458                        for (; it != it_end; ++ it)
2459                        {
2460                                ObjectPvs interPvs;
2461                                //cout<<"v"<<i<<" pvs="<<(*it)->GetPvs().mEntries.size()<<endl;
2462                                ObjectPvs::Merge(interPvs, pvs, (*it)->GetPvs());
2463
2464                                pvs = interPvs;
2465                        }
2466                } else
2467                {
2468                        PrVs prvs;
2469                        AxisAlignedBox3 box = GetViewCellBox(viewCell);
2470
2471                        //  mViewCellsManager->SetMaxFilterSize(1);
2472                        GetPrVS(box.Center(), prvs, viewSpaceFilterSize);
2473                        pvs = prvs.mViewCell->GetPvs();
2474                        DeleteLocalMergeTree(prvs.mViewCell);
2475                }
2476        }
2477        else
2478        {
2479                pvs = viewCell->GetPvs();
2480        }
2481
2482        if (spatialFilterSize >=0.0f)
2483                ApplySpatialFilter(kdTree, spatialFilterSize, pvs);
2484
2485}
2486
2487
2488
2489void
2490ViewCellsManager::ApplyFilter(KdTree *kdTree,
2491                                                          const float relViewSpaceFilterSize,
2492                                                          const float relSpatialFilterSize
2493                                                          )
2494{
2495
2496        if (!ViewCellsConstructed())
2497                return;
2498
2499        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
2500
2501        ObjectPvs *newPvs;
2502        newPvs = new ObjectPvs[mViewCells.size()];
2503
2504        float viewSpaceFilterSize = Magnitude(mViewSpaceBox.Size())*relViewSpaceFilterSize;
2505        float spatialFilterSize = Magnitude(kdTree->GetBox().Size())*relSpatialFilterSize;
2506       
2507        int i;
2508        for (i=0, it = mViewCells.begin(); it != it_end; ++ it, ++ i) {
2509          ApplyFilter(*it,
2510                                  kdTree,
2511                                  viewSpaceFilterSize,
2512                                  spatialFilterSize,
2513                                  newPvs[i]
2514                                  );
2515        }
2516       
2517        // now replace all pvss
2518        for (i = 0, it = mViewCells.begin(); it != it_end; ++ it, ++ i) {
2519         
2520          ObjectPvs &pvs = (*it)->GetPvs();
2521          pvs.Clear();
2522          pvs = newPvs[i];
2523          newPvs[i].Clear();
2524        }
2525
2526        delete [] newPvs;
2527}
2528
2529
2530void
2531ViewCellsManager::ApplySpatialFilter(
2532                                                                         KdTree *kdTree,
2533                                                                         const float spatialFilterSize,
2534                                                                         ObjectPvs &pvs
2535                                                                         )
2536{
2537  // now compute a new Pvs by including also objects intersecting the
2538  // extended boxes of visible objects
2539  Intersectable::NewMail();
2540
2541  ObjectPvsIterator pit = pvs.GetIterator();
2542
2543  while (pit.HasMoreEntries())
2544  {             
2545          ObjectPvsEntry entry = pit.Next();
2546 
2547          Intersectable *object = entry.mObject;
2548      object->Mail();
2549  }
2550
2551  ObjectPvs nPvs;
2552  int nPvsSize = 0;
2553 
2554  ObjectPvsIterator pit2 = pvs.GetIterator();
2555
2556  while (pit2.HasMoreEntries())
2557  {             
2558          // now go through the pvs again
2559          ObjectPvsEntry entry = pit2.Next();
2560          Intersectable *object = entry.mObject;
2561
2562          //    Vector3 center = object->GetBox().Center();
2563          //    AxisAlignedBox3 box(center - Vector3(spatialFilterSize/2),
2564          //                                            center + Vector3(spatialFilterSize/2));
2565
2566          AxisAlignedBox3 box = object->GetBox();
2567          box.Enlarge(Vector3(spatialFilterSize/2));
2568
2569          ObjectContainer objects;
2570
2571          // $$ warning collect objects takes only unmailed ones!
2572          kdTree->CollectObjects(box, objects);
2573          //    cout<<"collected objects="<<objects.size()<<endl;
2574          ObjectContainer::const_iterator noi = objects.begin();
2575          for (; noi != objects.end(); ++ noi)
2576          {
2577                  Intersectable *o = *noi;
2578                 
2579                  // $$ JB warning: pdfs are not correct at this point!   
2580                  nPvs.AddSample(o, Limits::Small);
2581                  nPvsSize ++;
2582          }
2583  }
2584
2585  // cout<<"nPvs size = "<<nPvsSize<<endl;
2586  pvs.MergeInPlace(nPvs);
2587}
2588
2589
2590void ViewCellsManager::MergeViewCellsRecursivly(ObjectPvs &pvs,
2591                                                                                                const ViewCellContainer &viewCells) const
2592{
2593        MergeViewCellsRecursivly(pvs, viewCells, 0, (int)viewCells.size() - 1);
2594}
2595
2596
2597void ViewCellsManager::MergeViewCellsRecursivly(ObjectPvs &pvs,
2598                                                                                                const ViewCellContainer &viewCells,
2599                                                                                                const int leftIdx,
2600                                                                                                const int rightIdx) const
2601{
2602        if (leftIdx == rightIdx)
2603        {
2604                pvs = viewCells[leftIdx]->GetPvs();
2605        }
2606        else
2607        {
2608                const int midSplit = (leftIdx + rightIdx) / 2;
2609       
2610                ObjectPvs leftPvs, rightPvs;
2611                MergeViewCellsRecursivly(leftPvs, viewCells, leftIdx, midSplit);
2612                MergeViewCellsRecursivly(rightPvs, viewCells, midSplit, rightIdx);
2613
2614        ObjectPvs::Merge(pvs, leftPvs, rightPvs);
2615        }
2616}
2617
2618
2619PvsFilterStatistics
2620ViewCellsManager::ApplyFilter2(ViewCell *viewCell,
2621                                                           const bool useViewSpaceFilter,
2622                                                           const float filterSize,
2623                                                           ObjectPvs &pvs,
2624                                                           vector<AxisAlignedBox3> *filteredBoxes
2625                                                           )
2626{
2627  //cout<<"y";
2628  PvsFilterStatistics stats;
2629
2630  AxisAlignedBox3 vbox = GetViewCellBox(viewCell);
2631  Vector3 center = vbox.Center();
2632  // copy the PVS
2633  Intersectable::NewMail();
2634  ObjectPvs basePvs = viewCell->GetPvs();
2635  ObjectPvsIterator pit = basePvs.GetIterator();
2636
2637  pvs.Reserve(viewCell->GetFilteredPvsSize());
2638
2639#if !USE_KD_PVS
2640  // first mark all objects from this pvs
2641  while (pit.HasMoreEntries()) {               
2642        ObjectPvsEntry entry = pit.Next();
2643       
2644        Intersectable *object = entry.mObject;
2645        object->Mail();
2646  }
2647#endif
2648 
2649  int pvsSize = 0;
2650  int nPvsSize = 0;
2651  float samples = (float)basePvs.GetSamples();
2652 
2653  Debug<<"f #s="<<samples<<"  pvs size = "<<basePvs.GetSize();
2654  //  cout<<"Filter size = "<<filterSize<<endl;
2655  //  cout<<"vbox = "<<vbox<<endl;
2656  //  cout<<"center = "<<center<<endl;
2657
2658
2659   // Minimal number of local samples to take into account
2660   // the local sampling density.
2661   // The size of the filter is a minimum of the conservative
2662   // local sampling density estimate (#rays intersecting teh viewcell and
2663   // the object)
2664   // and gobal estimate for the view cell
2665   // (total #rays intersecting the viewcell)
2666  int minLocalSamples = 2;
2667 
2668  float viewCellRadius = 0.5f*Magnitude(vbox.Diagonal());
2669 
2670  // now compute the filter box around the current viewCell
2671 
2672  if (useViewSpaceFilter) {
2673        //      float radius = Max(viewCellRadius/100.0f, avgRadius - viewCellRadius);
2674        float radius = viewCellRadius/100.0f;
2675        vbox.Enlarge(radius);
2676        cout<<"vbox = "<<vbox<<endl;
2677        ViewCellContainer viewCells;
2678        ComputeBoxIntersections(vbox, viewCells);
2679       
2680        ViewCellContainer::const_iterator it = viewCells.begin(),
2681          it_end = viewCells.end();
2682        int i = 0;
2683        for (i=0; it != it_end; ++ it, ++ i)
2684          if ((*it) != viewCell) {
2685                //cout<<"v"<<i<<" pvs="<<(*it)->GetPvs().mEntries.size()<<endl;
2686                basePvs.MergeInPlace((*it)->GetPvs());
2687          }
2688       
2689        // update samples and globalC
2690        samples = (float)pvs.GetSamples();
2691        //      cout<<"neighboring viewcells = "<<i-1<<endl;
2692        //      cout<<"Samples' = "<<samples<<endl;
2693  }
2694 
2695  // Minimal number of samples so that filtering takes place
2696#define MIN_SAMPLES  50
2697 
2698  if (samples > MIN_SAMPLES) {
2699        float globalC = 2.0f*filterSize/sqrt(samples);
2700       
2701        pit = basePvs.GetIterator();
2702       
2703        ObjectContainer objects;
2704       
2705        while (pit.HasMoreEntries()) {         
2706          ObjectPvsEntry entry = pit.Next();
2707         
2708          Intersectable *object = entry.mObject;
2709          // compute filter size based on the distance and the numebr of samples
2710          AxisAlignedBox3 box = object->GetBox();
2711         
2712          float distance = Distance(center, box.Center());
2713          float globalRadius = distance*globalC;
2714         
2715          int objectSamples = (int)entry.mData.mSumPdf;
2716          float localRadius = MAX_FLOAT;
2717         
2718          localRadius = filterSize*0.5f*Magnitude(box.Diagonal())/
2719                sqrt((float)objectSamples);
2720         
2721          //    cout<<"lr="<<localRadius<<" gr="<<globalRadius<<endl;
2722         
2723          // now compute the filter size
2724          float radius;
2725         
2726#if 0
2727          if (objectSamples <= 1) {
2728                if (localRadius > globalRadius) {
2729                  radius = 0.5flRadius;
2730                  stats.mLocalFilterCount++;
2731                } else {
2732                  radius = globalRadius;
2733                  stats.mGlobalFilterCount++;
2734                }
2735          } else {
2736                radius = localRadius;
2737                stats.mLocalFilterCount++;
2738          }
2739#else
2740          radius = 0.5f*globalRadius + 0.5f*localRadius;
2741          stats.mLocalFilterCount++;
2742          stats.mGlobalFilterCount++;
2743#endif
2744         
2745          stats.mAvgFilterRadius += radius;
2746         
2747          // cout<<"box = "<<box<<endl;
2748          //    cout<<"distance = "<<distance<<endl;
2749          //    cout<<"radiues = "<<radius<<endl;
2750         
2751          box.Enlarge(Vector3(radius));
2752
2753          if (filteredBoxes)
2754                filteredBoxes->push_back(box);
2755
2756          objects.clear();
2757          // $$ warning collect objects takes only unmailed ones!
2758          CollectObjects(box, objects);
2759          //    cout<<"collected objects="<<objects.size()<<endl;
2760          ObjectContainer::const_iterator noi = objects.begin();
2761          for (; noi != objects.end(); ++ noi) {
2762                Intersectable *o = *noi;
2763                // $$ JB warning: pdfs are not correct at this point!     
2764                pvs.AddSampleDirty(o, Limits::Small);
2765          }
2766        }
2767        stats.mAvgFilterRadius /= (stats.mLocalFilterCount + stats.mGlobalFilterCount);
2768  }
2769 
2770  Debug<<" nPvs size = "<<pvs.GetSize()<<endl;
2771 
2772#if !USE_KD_PVS
2773  // copy the base pvs to the new pvs
2774  pit = basePvs.GetIterator();
2775  while (pit.HasMoreEntries()) {               
2776        ObjectPvsEntry entry = pit.Next();
2777        pvs.AddSampleDirty(entry.mObject, entry.mData.mSumPdf);
2778  }
2779#endif
2780 
2781  pvs.SimpleSort();
2782  viewCell->SetFilteredPvsSize(pvs.GetSize());
2783 
2784  Intersectable::NewMail();
2785  return stats;
2786}
2787
2788
2789
2790void ViewCellsManager::ExportColor(Exporter *exporter,
2791                                                                   ViewCell *vc,
2792                                                                   bool colorCode) const
2793{
2794        const bool vcValid = CheckValidity(vc, mMinPvsSize, mMaxPvsSize);
2795
2796        float importance = 0;
2797        static Material m;
2798        //cout << "color code: " << colorCode << endl;
2799        switch (mColorCode)
2800        {
2801        case 0: // Random
2802                {
2803                        if (vcValid)
2804                        {
2805                                m.mDiffuseColor.r = 0.2f + RandomValue(0.0f, 0.8f);
2806                                m.mDiffuseColor.g = 0.2f + RandomValue(0.0f, 0.8f);
2807                                m.mDiffuseColor.b = 0.2f + RandomValue(0.0f, 0.8f);
2808                        }
2809                        else
2810                        {
2811                                m.mDiffuseColor.r = 0.0f;
2812                                m.mDiffuseColor.g = 1.0f;
2813                                m.mDiffuseColor.b = 0.0f;
2814                        }
2815
2816                        exporter->SetForcedMaterial(m);
2817                        return;
2818                }
2819               
2820        case 1: // pvs
2821                {
2822                        if (mCurrentViewCellsStats.maxPvs)
2823                        {
2824                                importance = (float)mViewCellsTree->GetPvsCost(vc) /
2825                                                         (float)mCurrentViewCellsStats.maxPvs;
2826                        }
2827                }
2828                break;
2829        case 2: // merges
2830                {
2831            const int lSize = mViewCellsTree->GetNumInitialViewCells(vc);
2832                        importance = (float)lSize / (float)mCurrentViewCellsStats.maxLeaves;
2833                }
2834                break;
2835#if 0
2836        case 3: // merge tree differene
2837                {
2838                        importance = (float)GetMaxTreeDiff(vc) /
2839                                (float)(mVspBspTree->GetStatistics().maxDepth * 2);
2840
2841                }
2842                break;
2843#endif
2844        default:
2845                break;
2846        }
2847
2848        // special color code for invalid view cells
2849        m.mDiffuseColor.r = importance;
2850        m.mDiffuseColor.g = vcValid ? 0.0f : 1.0f;
2851        m.mDiffuseColor.b = 1.0f - importance;
2852
2853        //Debug << "importance: " << importance << endl;
2854        exporter->SetForcedMaterial(m);
2855}
2856
2857
2858void ViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
2859                                                                                          vector<MergeCandidate> &candidates)
2860{
2861        // implemented in subclasses
2862}
2863
2864
2865void ViewCellsManager::UpdatePvsForEvaluation()
2866{
2867        ObjectPvs objPvs;
2868        UpdatePvsForEvaluation(mViewCellsTree->GetRoot(), objPvs);
2869}
2870
2871void ViewCellsManager::UpdatePvsForEvaluation(ViewCell *root, ObjectPvs &pvs)
2872{
2873        // terminate traversal
2874        if (root->IsLeaf())
2875        {
2876                //cout << "updating leaf" << endl;
2877                // we assume that pvs is explicitly stored in leaves
2878                pvs = root->GetPvs();
2879                UpdateScalarPvsSize(root, pvs.EvalPvsCost(), pvs.GetSize());
2880                return;
2881        }
2882
2883        ////////////////
2884        //-- interior node => propagate pvs up the tree
2885
2886        ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(root);
2887
2888        // reset interior pvs
2889        interior->GetPvs().Clear();
2890        // reset recursive pvs
2891        pvs.Clear();
2892
2893        // pvss of child nodes
2894        vector<ObjectPvs> pvsList;
2895        pvsList.resize((int)interior->mChildren.size());
2896
2897        ViewCellContainer::const_iterator vit, vit_end = interior->mChildren.end();
2898       
2899        int i = 0;
2900
2901        for (vit = interior->mChildren.begin(); vit != vit_end; ++ vit, ++ i)
2902        {
2903                //////////////////
2904                //-- recursivly compute child pvss
2905                UpdatePvsForEvaluation(*vit, pvsList[i]/*objPvs*/);
2906        }
2907
2908#if 1
2909        Intersectable::NewMail();
2910
2911        //-- faster way of computing pvs:
2912        //-- construct merged pvs by adding
2913        //-- and only those of the next pvs which were not mailed.
2914        //-- note: sumpdf is not correct!!
2915
2916        vector<ObjectPvs>::iterator oit = pvsList.begin();
2917
2918        for (vit = interior->mChildren.begin(); vit != vit_end; ++ vit, ++ oit)
2919        {
2920                ObjectPvsIterator pit = (*oit).GetIterator();
2921               
2922                // first mark all object from this pvs
2923                while (pit.HasMoreEntries())
2924                {               
2925                        ObjectPvsEntry entry = pit.Next();
2926
2927                        Intersectable *intersect = entry.mObject;
2928
2929                        if (!intersect->Mailed())
2930                        {
2931                                pvs.AddSample(intersect, entry.mData.mSumPdf);
2932                                intersect->Mail();
2933                        }
2934                }
2935        }
2936
2937        // store pvs in this node
2938        if (mViewCellsTree->ViewCellsStorage() == ViewCellsTree::PVS_IN_INTERIORS)
2939        {
2940                interior->SetPvs(pvs);
2941        }
2942       
2943        // set new pvs size
2944        UpdateScalarPvsSize(interior, pvs.EvalPvsCost(), pvs.GetSize());
2945       
2946#else
2947        // really merge cells: slow put sumPdf is correct
2948        viewCellInterior->GetPvs().Merge(backVc->GetPvs());
2949        viewCellInterior->GetPvs().Merge(frontVc->GetPvs());
2950#endif
2951}
2952
2953
2954
2955/*******************************************************************/
2956/*               BspViewCellsManager implementation                */
2957/*******************************************************************/
2958
2959
2960BspViewCellsManager::BspViewCellsManager(ViewCellsTree *vcTree, BspTree *bspTree):
2961ViewCellsManager(vcTree), mBspTree(bspTree)
2962{
2963        Environment::GetSingleton()->GetIntValue("BspTree.Construction.samples", mInitialSamples);
2964
2965        mBspTree->SetViewCellsManager(this);
2966        mBspTree->SetViewCellsTree(mViewCellsTree);
2967}
2968
2969
2970bool BspViewCellsManager::ViewCellsConstructed() const
2971{
2972        return mBspTree->GetRoot() != NULL;
2973}
2974
2975
2976ViewCell *BspViewCellsManager::GenerateViewCell(Mesh *mesh) const
2977{
2978        return new BspViewCell(mesh);
2979}
2980
2981
2982int BspViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
2983                                                                                          const VssRayContainer &rays)
2984{
2985        // if view cells were already constructed, we can finish
2986        if (ViewCellsConstructed())
2987                return 0;
2988
2989        int sampleContributions = 0;
2990
2991        // construct view cells using the collected samples
2992        RayContainer constructionRays;
2993        VssRayContainer savedRays;
2994
2995        // choose a a number of rays based on the ratio of cast rays / requested rays
2996        const int limit = min(mInitialSamples, (int)rays.size());
2997        VssRayContainer::const_iterator it, it_end = rays.end();
2998
2999        const float prop = (float)limit / ((float)rays.size() + Limits::Small);
3000
3001        for (it = rays.begin(); it != it_end; ++ it)
3002        {
3003                if (Random(1.0f) < prop)
3004                        constructionRays.push_back(new Ray(*(*it)));
3005                else
3006                        savedRays.push_back(*it);
3007        }
3008
3009    if (!mUsePredefinedViewCells)
3010        {
3011                // no view cells loaded
3012                mBspTree->Construct(objects, constructionRays, &mViewSpaceBox);
3013                // collect final view cells
3014                mBspTree->CollectViewCells(mViewCells);
3015        }
3016        else
3017        {       
3018                // use predefined view cells geometry =>
3019                // contruct bsp hierarchy over them
3020                mBspTree->Construct(mViewCells);
3021        }
3022
3023        // destroy rays created only for construction
3024        CLEAR_CONTAINER(constructionRays);
3025
3026        Debug << mBspTree->GetStatistics() << endl;
3027        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
3028
3029        // recast rest of the rays
3030        if (SAMPLE_AFTER_SUBDIVISION)
3031                ComputeSampleContributions(savedRays, true, false);
3032
3033        // real meshes are contructed at this stage
3034        if (0)
3035        {
3036                cout << "finalizing view cells ... ";
3037                FinalizeViewCells(true);
3038                cout << "finished" << endl;     
3039        }
3040
3041        return sampleContributions;
3042}
3043
3044
3045void BspViewCellsManager::CollectViewCells()
3046{       
3047        if (!ViewCellsTreeConstructed())
3048        {       // view cells tree constructed 
3049                mBspTree->CollectViewCells(mViewCells);
3050        }
3051        else
3052        {       // we can use the view cells tree hierarchy to get the right set
3053                mViewCellsTree->CollectBestViewCellSet(mViewCells, mNumActiveViewCells);
3054        }
3055}
3056
3057
3058float BspViewCellsManager::GetProbability(ViewCell *viewCell)
3059{
3060        if (1)
3061                return GetVolume(viewCell) / GetViewSpaceBox().GetVolume();
3062        else
3063                // compute view cell area as subsititute for probability
3064                return GetArea(viewCell) / GetAccVcArea();
3065}
3066
3067
3068
3069int BspViewCellsManager::CastLineSegment(const Vector3 &origin,
3070                                                                                 const Vector3 &termination,
3071                                                                                 ViewCellContainer &viewcells)
3072{
3073        return mBspTree->CastLineSegment(origin, termination, viewcells);
3074}
3075
3076
3077void ViewCellsManager::ExportMergedViewCells(const ObjectContainer &objects)
3078{
3079        // save color code
3080        const int savedColorCode = mColorCode;
3081
3082        Exporter *exporter;
3083
3084#if 0
3085        // export merged view cells
3086        mColorCode = 0; // use random colors
3087
3088        exporter = Exporter::GetExporter("merged_view_cells.wrl");
3089
3090        cout << "exporting view cells after merge ... ";
3091
3092        if (exporter)
3093        {
3094                if (mExportGeometry)
3095                {
3096                        exporter->ExportGeometry(objects);
3097                }
3098
3099                exporter->SetFilled();
3100                ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
3101
3102                delete exporter;
3103        }
3104        cout << "finished" << endl;
3105#endif
3106
3107        // export merged view cells using pvs color coding
3108        exporter = Exporter::GetExporter("merged_view_cells_pvs.wrl");
3109        cout << "exporting view cells after merge (pvs size) ... ";     
3110
3111        if (exporter)
3112        {
3113                if (mExportGeometry)
3114                {
3115                        exporter->ExportGeometry(objects);
3116                }
3117
3118                exporter->SetFilled();
3119                mColorCode = 1;
3120
3121                ExportViewCellsForViz(exporter, NULL,  mColorCode, GetClipPlane());
3122
3123                delete exporter;
3124        }
3125        cout << "finished" << endl;
3126       
3127        mColorCode = savedColorCode;
3128}
3129
3130
3131int BspViewCellsManager::PostProcess(const ObjectContainer &objects,
3132                                                                         const VssRayContainer &rays)
3133{
3134        if (!ViewCellsConstructed())
3135        {
3136                Debug << "view cells not constructed" << endl;
3137                return 0;
3138        }
3139       
3140        // view cells already finished before post processing step,
3141        // i.e., because they were loaded from disc
3142        if (mViewCellsFinished)
3143        {
3144                FinalizeViewCells(true);
3145                EvaluateViewCellsStats();
3146
3147                return 0;
3148        }
3149
3150        //////////////////
3151        //-- merge leaves of the view cell hierarchy   
3152       
3153        cout << "starting post processing using " << mPostProcessSamples << " samples ... ";
3154        long startTime = GetTime();
3155       
3156        VssRayContainer postProcessRays;
3157        GetRaySets(rays, mPostProcessSamples, postProcessRays);
3158
3159        if (mMergeViewCells)
3160        {
3161                cout << "constructing visibility based merge tree" << endl;
3162                mViewCellsTree->ConstructMergeTree(rays, objects);
3163        }
3164        else
3165        {
3166                cout << "constructing spatial merge tree" << endl;
3167                ViewCell *root;
3168                // the spatial merge tree is difficult to build for
3169                // this type of construction, as view cells cover several
3170                // leaves => create dummy tree which is only 2 levels deep
3171                if (mUsePredefinedViewCells)
3172                {
3173                        root = ConstructDummyMergeTree(mBspTree->GetRoot());
3174                }
3175                else
3176                {
3177                        // create spatial merge hierarchy
3178                        root = ConstructSpatialMergeTree(mBspTree->GetRoot());
3179                }
3180               
3181                mViewCellsTree->SetRoot(root);
3182
3183                // recompute pvs in the whole hierarchy
3184                ObjectPvs pvs;
3185                UpdatePvsForEvaluation(root, pvs);
3186        }
3187
3188        cout << "finished" << endl;
3189        cout << "merged view cells in "
3190                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
3191
3192        Debug << "Postprocessing: Merged view cells in "
3193                << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl << endl;
3194
3195       
3196        ////////////////////////
3197        //-- visualization and statistics after merge
3198
3199        if (1)
3200        {
3201                char mstats[100];
3202                Environment::GetSingleton()->GetStringValue("ViewCells.mergeStats", mstats);
3203                mViewCellsTree->ExportStats(mstats);
3204        }
3205
3206        // recompute view cells and stats
3207        ResetViewCells();
3208        Debug << "\nView cells after merge:\n" << mCurrentViewCellsStats << endl;
3209
3210        //  visualization of the view cells
3211        if (1) ExportMergedViewCells(objects);
3212
3213        // compute final meshes and volume / area
3214        if (1) FinalizeViewCells(true);
3215       
3216        return 0;
3217}
3218
3219
3220BspViewCellsManager::~BspViewCellsManager()
3221{
3222}
3223
3224
3225int BspViewCellsManager::GetType() const
3226{
3227        return BSP;
3228}
3229
3230
3231void BspViewCellsManager::Visualize(const ObjectContainer &objects,
3232                                                                        const VssRayContainer &sampleRays)
3233{
3234        if (!ViewCellsConstructed())
3235                return;
3236       
3237        const int savedColorCode = mColorCode;
3238       
3239        if (1) // export final view cells
3240        {
3241                mColorCode = 1; // hack color code
3242                Exporter *exporter = Exporter::GetExporter("final_view_cells.wrl");
3243       
3244                cout << "exporting view cells after merge (pvs size) ... ";     
3245
3246                if (exporter)
3247                {
3248                        if (mExportGeometry)
3249                        {
3250                                exporter->ExportGeometry(objects);
3251                        }
3252
3253                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
3254                        delete exporter;
3255                }
3256                cout << "finished" << endl;
3257        }
3258
3259        // reset color code
3260        mColorCode = savedColorCode;
3261
3262
3263        //////////////////
3264        //-- visualization of the BSP splits
3265
3266        bool exportSplits = false;
3267        Environment::GetSingleton()->GetBoolValue("BspTree.Visualization.exportSplits", exportSplits);
3268
3269        if (exportSplits)
3270        {
3271                cout << "exporting splits ... ";
3272                ExportSplits(objects);
3273                cout << "finished" << endl;
3274        }
3275
3276        int leafOut;
3277        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.maxOutput", leafOut);
3278        const int raysOut = 100;
3279        ExportSingleViewCells(objects, leafOut, false, true, false, raysOut, "");
3280}
3281
3282
3283void BspViewCellsManager::ExportSplits(const ObjectContainer &objects)
3284{
3285        Exporter *exporter = Exporter::GetExporter("bsp_splits.x3d");
3286
3287        if (exporter)
3288        {
3289                //exporter->SetFilled();
3290                if (mExportGeometry)
3291                {
3292                        exporter->ExportGeometry(objects);
3293                }
3294
3295                Material m;
3296                m.mDiffuseColor = RgbColor(1, 0, 0);
3297                exporter->SetForcedMaterial(m);
3298                exporter->SetWireframe();
3299
3300                exporter->ExportBspSplits(*mBspTree, true);
3301
3302                // NOTE: take forced material, else big scenes cannot be viewed
3303                m.mDiffuseColor = RgbColor(0, 1, 0);
3304                exporter->SetForcedMaterial(m);
3305                //exporter->ResetForcedMaterial();
3306
3307                delete exporter;
3308        }
3309}
3310
3311
3312void BspViewCellsManager::ExportSingleViewCells(const ObjectContainer &objects,
3313                                                                                                const int maxViewCells,
3314                                                                                                const bool sortViewCells,
3315                                                                                                const bool exportPvs,
3316                                                                                                const bool exportRays,
3317                                                                                                const int maxRays,
3318                                                                                                const string prefix,
3319                                                                                                VssRayContainer *visRays)
3320{
3321        if (sortViewCells)
3322        {       // sort view cells to visualize the largest view cells
3323                sort(mViewCells.begin(), mViewCells.end(), ViewCell::LargerRenderCost);
3324        }
3325
3326        //////////
3327        //-- some view cells for output
3328
3329        ViewCell::NewMail();
3330        const int limit = min(maxViewCells, (int)mViewCells.size());
3331       
3332        for (int i = 0; i < limit; ++ i)
3333        {
3334                const int idx = sortViewCells ? (int)RandomValue(0, (float)mViewCells.size() - 0.5f) : i;
3335                ViewCell *vc = mViewCells[idx];
3336
3337                if (vc->Mailed() || vc->GetId() == OUT_OF_BOUNDS_ID)
3338                        continue;
3339
3340                vc->Mail();
3341
3342                ObjectPvs pvs;
3343                mViewCellsTree->GetPvs(vc, pvs);
3344
3345                char s[64]; sprintf(s, "%sviewcell-%04d.wrl", prefix.c_str(), i);
3346                Exporter *exporter = Exporter::GetExporter(s);
3347               
3348                cout << "view cell " << idx << ": pvs cost=" << (int)mViewCellsTree->GetPvsCost(vc) << endl;
3349
3350                if (exportRays)
3351                {
3352                        ////////////
3353                        //-- export rays piercing this view cell
3354
3355                        // use rays stored with the view cells
3356                        VssRayContainer vcRays, vcRays2, vcRays3;
3357            VssRayContainer collectRays;
3358
3359                        // collect initial view cells
3360                        ViewCellContainer leaves;
3361                        mViewCellsTree->CollectLeaves(vc, leaves);
3362
3363                        ViewCellContainer::const_iterator vit, vit_end = leaves.end();
3364                for (vit = leaves.begin(); vit != vit_end; ++ vit)
3365                        {       
3366                                // prepare some rays for output
3367                                VssRayContainer::const_iterator rit, rit_end = (*vit)->GetOrCreateRays()->end();
3368                                for (rit = (*vit)->GetOrCreateRays()->begin(); rit != rit_end; ++ rit)
3369                                {
3370                                        collectRays.push_back(*rit);
3371                                }
3372                        }
3373
3374                        const int raysOut = min((int)collectRays.size(), maxRays);
3375
3376                        // prepare some rays for output
3377                        VssRayContainer::const_iterator rit, rit_end = collectRays.end();
3378                        for (rit = collectRays.begin(); rit != rit_end; ++ rit)
3379                        {
3380                                const float p = RandomValue(0.0f, (float)collectRays.size());
3381                                if (p < raysOut)
3382                                {
3383                                        if ((*rit)->mFlags & VssRay::BorderSample)
3384                                        {
3385                                                vcRays.push_back(*rit);
3386                                        }
3387                                        else if ((*rit)->mFlags & VssRay::ReverseSample)
3388                                                vcRays2.push_back(*rit);
3389                                        else
3390                                                vcRays3.push_back(*rit);
3391                                               
3392                                }
3393                        }
3394
3395                        exporter->ExportRays(vcRays, RgbColor(1, 0, 0));
3396                        exporter->ExportRays(vcRays2, RgbColor(0, 1, 0));
3397                        exporter->ExportRays(vcRays3, RgbColor(1, 1, 1));
3398                }
3399               
3400                ////////////////
3401                //-- export view cell geometry
3402
3403                exporter->SetWireframe();
3404
3405                Material m;//= RandomMaterial();
3406                m.mDiffuseColor = RgbColor(0, 1, 0);
3407                exporter->SetForcedMaterial(m);
3408
3409                ExportViewCellGeometry(exporter, vc, NULL, NULL);
3410                exporter->SetFilled();
3411
3412                if (exportPvs)
3413                {
3414                        Intersectable::NewMail();
3415                        ObjectPvsIterator pit = pvs.GetIterator();
3416
3417                        while (pit.HasMoreEntries())
3418                        {               
3419                                ObjectPvsEntry entry = pit.Next();
3420
3421                // output PVS of view cell
3422                                Intersectable *intersect = entry.mObject;
3423                               
3424                                if (!intersect->Mailed())
3425                                {
3426                                        intersect->Mail();
3427
3428                                        m = RandomMaterial();
3429                                        exporter->SetForcedMaterial(m);
3430                                        exporter->ExportIntersectable(intersect);
3431                                }
3432                        }
3433                        cout << endl;
3434                }
3435               
3436                DEL_PTR(exporter);
3437                cout << "finished" << endl;
3438        }
3439}
3440
3441
3442void BspViewCellsManager::TestSubdivision()
3443{
3444        ViewCellContainer leaves;
3445        mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
3446
3447        ViewCellContainer::const_iterator it, it_end = leaves.end();
3448
3449        const float vol = mViewSpaceBox.GetVolume();
3450        float subdivVol = 0;
3451        float newVol = 0;
3452
3453        for (it = leaves.begin(); it != it_end; ++ it)
3454        {
3455                BspNodeGeometry geom;
3456                mBspTree->ConstructGeometry(*it, geom);
3457
3458                const float lVol = geom.GetVolume();
3459                newVol += lVol;
3460                subdivVol += (*it)->GetVolume();
3461
3462                const float thres = 0.9f;
3463                if ((lVol < ((*it)->GetVolume() * thres)) ||
3464                        (lVol * thres > ((*it)->GetVolume())))
3465                        Debug << "warning: " << lVol << " " << (*it)->GetVolume() << endl;
3466        }
3467       
3468        Debug << "exact volume: " << vol << endl;
3469        Debug << "subdivision volume: " << subdivVol << endl;
3470        Debug << "new volume: " << newVol << endl;
3471}
3472
3473
3474void BspViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
3475                                                                                                 ViewCell *vc,
3476                                                                                                 const AxisAlignedBox3 *sceneBox,
3477                                                                                                 const AxisAlignedPlane *clipPlane
3478                                                                                                 ) const
3479{
3480        if (clipPlane)
3481        {
3482                const Plane3 plane = clipPlane->GetPlane();
3483
3484                ViewCellContainer leaves;
3485                mViewCellsTree->CollectLeaves(vc, leaves);
3486                ViewCellContainer::const_iterator it, it_end = leaves.end();
3487
3488                for (it = leaves.begin(); it != it_end; ++ it)
3489                {
3490                        BspNodeGeometry geom;
3491                        BspNodeGeometry front;
3492                        BspNodeGeometry back;
3493
3494                        mBspTree->ConstructGeometry(*it, geom);
3495
3496                        const float eps = 0.0001f;
3497                        const int cf = geom.Side(plane, eps);
3498
3499                        if (cf == -1)
3500                        {
3501                                exporter->ExportPolygons(geom.GetPolys());
3502                        }
3503                        else if (cf == 0)
3504                        {
3505                                geom.SplitGeometry(front,
3506                                                                   back,
3507                                                                   plane,
3508                                                                   mViewSpaceBox,
3509                                                                   eps);
3510
3511                                if (back.Valid())
3512                                {
3513                                        exporter->ExportPolygons(back.GetPolys());
3514                                }                       
3515                        }
3516                }
3517        }
3518        else
3519        {
3520                // export mesh if available
3521                // TODO: some bug here?
3522                if (1 && vc->GetMesh())
3523                {
3524                        exporter->ExportMesh(vc->GetMesh());
3525                }
3526                else
3527                {
3528                        BspNodeGeometry geom;
3529                        mBspTree->ConstructGeometry(vc, geom);
3530                        exporter->ExportPolygons(geom.GetPolys());
3531                }
3532        }
3533}
3534
3535
3536void BspViewCellsManager::CreateMesh(ViewCell *vc)
3537{
3538        // note: should previous mesh be deleted (via mesh manager?)
3539        BspNodeGeometry geom;
3540        mBspTree->ConstructGeometry(vc, geom);
3541
3542        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
3543
3544        IncludeNodeGeomInMesh(geom, *mesh);
3545        vc->SetMesh(mesh);
3546}
3547
3548
3549void BspViewCellsManager::Finalize(ViewCell *viewCell,
3550                                                                   const bool createMesh)
3551{
3552        float area = 0;
3553        float volume = 0;
3554
3555        ViewCellContainer leaves;
3556        mViewCellsTree->CollectLeaves(viewCell, leaves);
3557
3558        ViewCellContainer::const_iterator it, it_end = leaves.end();
3559
3560    for (it = leaves.begin(); it != it_end; ++ it)
3561        {
3562                BspNodeGeometry geom;
3563
3564                mBspTree->ConstructGeometry(*it, geom);
3565
3566                const float lVol = geom.GetVolume();
3567                const float lArea = geom.GetArea();
3568
3569                area += lArea;
3570                volume += lVol;
3571       
3572                CreateMesh(*it);
3573        }
3574
3575        viewCell->SetVolume(volume);
3576        viewCell->SetArea(area);
3577}
3578
3579
3580ViewCell *BspViewCellsManager::GetViewCell(const Vector3 &point, const bool active) const
3581{
3582        if (!ViewCellsConstructed())
3583        {
3584                return NULL;
3585        }
3586        if (!mViewSpaceBox.IsInside(point))
3587        {
3588                return NULL;
3589        }
3590        return mBspTree->GetViewCell(point);
3591}
3592
3593
3594void BspViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
3595                                                                                                 vector<MergeCandidate> &candidates)
3596{
3597        cout << "collecting merge candidates ... " << endl;
3598
3599        if (mUseRaysForMerge)
3600        {
3601                mBspTree->CollectMergeCandidates(rays, candidates);
3602        }
3603        else
3604        {
3605                vector<BspLeaf *> leaves;
3606                mBspTree->CollectLeaves(leaves);
3607                mBspTree->CollectMergeCandidates(leaves, candidates);
3608        }
3609
3610        cout << "fininshed collecting candidates" << endl;
3611}
3612
3613
3614
3615bool BspViewCellsManager::ExportViewCells(const string filename,
3616                                                                                  const bool exportPvs,
3617                                                                                  const ObjectContainer &objects)
3618{
3619        if (!ViewCellsConstructed() || !ViewCellsTreeConstructed())
3620        {
3621                return false;
3622        }
3623
3624        cout << "exporting view cells to xml ... ";
3625
3626        OUT_STREAM stream(filename.c_str());
3627
3628        // for output we need unique ids for each view cell
3629        CreateUniqueViewCellIds();
3630
3631        stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<endl;
3632        stream << "<VisibilitySolution>" << endl;
3633
3634        if (exportPvs)
3635        {
3636                //////////
3637                //-- export bounding boxes: they are used to identify the objects from the pvs and
3638                //-- assign them to the entities in the rendering engine
3639
3640                stream << "<BoundingBoxes>" << endl;
3641                ObjectContainer::const_iterator oit, oit_end = objects.end();
3642
3643                for (oit = objects.begin(); oit != oit_end; ++ oit)
3644                {
3645                        const AxisAlignedBox3 box = (*oit)->GetBox();
3646                       
3647                        stream << "<BoundingBox" << " id=\"" << (*oit)->GetId() << "\""
3648                                   << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
3649                                   << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\" />" << endl;
3650                }
3651
3652                stream << "</BoundingBoxes>" << endl;
3653        }
3654
3655        ///////////
3656        //-- export the view cells and the pvs
3657
3658        const int numViewCells = mCurrentViewCellsStats.viewCells;
3659        stream << "<ViewCells number=\"" << numViewCells << "\" >" << endl;
3660
3661        mViewCellsTree->Export(stream, exportPvs);
3662       
3663        stream << "</ViewCells>" << endl;
3664
3665        /////////////
3666        //-- export the view space hierarchy
3667        stream << "<ViewSpaceHierarchy type=\"bsp\""
3668                   << " min=\"" << mViewSpaceBox.Min().x << " " << mViewSpaceBox.Min().y << " " << mViewSpaceBox.Min().z << "\""
3669                   << " max=\"" << mViewSpaceBox.Max().x << " " << mViewSpaceBox.Max().y << " " << mViewSpaceBox.Max().z << "\">" << endl;
3670
3671        mBspTree->Export(stream);
3672
3673        // end tags
3674        stream << "</ViewSpaceHierarchy>" << endl;
3675        stream << "</VisibilitySolution>" << endl;
3676
3677        stream.close();
3678        cout << "finished" << endl;
3679
3680        return true;
3681}
3682
3683
3684ViewCell *BspViewCellsManager::ConstructDummyMergeTree(BspNode *root)
3685{
3686        ViewCellInterior *vcRoot = new ViewCellInterior();
3687               
3688        // evaluate merge cost for priority traversal
3689        const float mergeCost =  -(float)root->mTimeStamp;
3690        vcRoot->SetMergeCost(mergeCost);
3691
3692        float volume = 0;
3693        vector<BspLeaf *> leaves;
3694        mBspTree->CollectLeaves(leaves);
3695        vector<BspLeaf *>::const_iterator lit, lit_end = leaves.end();
3696        ViewCell::NewMail();
3697
3698        for (lit = leaves.begin(); lit != lit_end; ++ lit)
3699        {
3700                BspLeaf *leaf = *lit;
3701                ViewCell *vc = leaf->GetViewCell();
3702
3703                if (!vc->Mailed())
3704                {
3705                        vc->Mail();
3706                        vc->SetMergeCost(0.0f);
3707                        vcRoot->SetupChildLink(vc);
3708
3709                        volume += vc->GetVolume();
3710                        volume += vc->GetVolume();     
3711                        vcRoot->SetVolume(volume);
3712                }
3713        }
3714       
3715        return vcRoot;
3716}
3717
3718
3719ViewCell *BspViewCellsManager::ConstructSpatialMergeTree(BspNode *root)
3720{
3721        // terminate recursion
3722        if (root->IsLeaf())
3723        {
3724                BspLeaf *leaf = dynamic_cast<BspLeaf *>(root);
3725                leaf->GetViewCell()->SetMergeCost(0.0f);
3726                return leaf->GetViewCell();
3727        }
3728       
3729        BspInterior *interior = dynamic_cast<BspInterior *>(root);
3730        ViewCellInterior *viewCellInterior = new ViewCellInterior();
3731               
3732        // evaluate merge cost for priority traversal
3733        const float mergeCost = -(float)root->mTimeStamp;
3734        viewCellInterior->SetMergeCost(mergeCost);
3735
3736        float volume = 0;
3737       
3738        BspNode *front = interior->GetFront();
3739        BspNode *back = interior->GetBack();
3740
3741
3742        ////////////
3743        //-- recursivly compute child hierarchies
3744
3745        ViewCell *backVc = ConstructSpatialMergeTree(back);
3746        ViewCell *frontVc = ConstructSpatialMergeTree(front);
3747
3748        viewCellInterior->SetupChildLink(backVc);
3749        viewCellInterior->SetupChildLink(frontVc);
3750
3751        volume += backVc->GetVolume();
3752        volume += frontVc->GetVolume();
3753
3754        viewCellInterior->SetVolume(volume);
3755
3756        return viewCellInterior;
3757}
3758
3759
3760/************************************************************************/
3761/*                   KdViewCellsManager implementation                  */
3762/************************************************************************/
3763
3764
3765
3766KdViewCellsManager::KdViewCellsManager(ViewCellsTree *vcTree, KdTree *kdTree):
3767ViewCellsManager(vcTree), mKdTree(kdTree), mKdPvsDepth(100)
3768{
3769}
3770
3771
3772float KdViewCellsManager::GetProbability(ViewCell *viewCell)
3773{
3774        // compute view cell area / volume as subsititute for probability
3775        if (0)
3776                return GetArea(viewCell) / GetViewSpaceBox().SurfaceArea();
3777        else
3778                return GetVolume(viewCell) / GetViewSpaceBox().GetVolume();
3779}
3780
3781
3782
3783
3784void KdViewCellsManager::CollectViewCells()
3785{
3786        //mKdTree->CollectViewCells(mViewCells); TODO
3787}
3788
3789
3790int KdViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
3791                                                                  const VssRayContainer &rays)
3792{
3793        // if view cells already constructed
3794        if (ViewCellsConstructed())
3795                return 0;
3796
3797        mKdTree->Construct();
3798
3799        mTotalAreaValid = false;
3800        // create the view cells
3801        mKdTree->CreateAndCollectViewCells(mViewCells);
3802        // cast rays
3803        ComputeSampleContributions(rays, true, false);
3804
3805        EvaluateViewCellsStats();
3806        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
3807
3808        return 0;
3809}
3810
3811
3812bool KdViewCellsManager::ViewCellsConstructed() const
3813{
3814        return mKdTree->GetRoot() != NULL;
3815}
3816
3817
3818int KdViewCellsManager::PostProcess(const ObjectContainer &objects,
3819                                                                        const VssRayContainer &rays)
3820{
3821        return 0;
3822}
3823
3824
3825void KdViewCellsManager::ExportSingleViewCells(const ObjectContainer &objects,
3826                                                                                           const int maxViewCells,
3827                                                                                           const bool sortViewCells,
3828                                                                                           const bool exportPvs,
3829                                                                                           const bool exportRays,
3830                                                                                           const int maxRays,
3831                                                                                           const string prefix,
3832                                                                                           VssRayContainer *visRays)
3833{
3834        // TODO
3835}
3836
3837
3838void KdViewCellsManager::Visualize(const ObjectContainer &objects,
3839                                                                   const VssRayContainer &sampleRays)
3840{
3841        if (!ViewCellsConstructed())
3842                return;
3843
3844        // using view cells instead of the kd PVS of objects
3845        const bool useViewCells = true;
3846        bool exportRays = false;
3847
3848        int limit = min(mVisualizationSamples, (int)sampleRays.size());
3849        const int pvsOut = min((int)objects.size(), 10);
3850        VssRayContainer *rays = new VssRayContainer[pvsOut];
3851
3852        if (useViewCells)
3853        {
3854                const int leafOut = 10;
3855
3856                ViewCell::NewMail();
3857
3858                //-- some rays for output
3859                const int raysOut = min((int)sampleRays.size(), mVisualizationSamples);
3860                Debug << "visualization using " << raysOut << " samples" << endl;
3861
3862                //-- some random view cells and rays for output
3863                vector<KdLeaf *> kdLeaves;
3864
3865                for (int i = 0; i < leafOut; ++ i)
3866                        kdLeaves.push_back(dynamic_cast<KdLeaf *>(mKdTree->GetRandomLeaf()));
3867
3868                for (int i = 0; i < kdLeaves.size(); ++ i)
3869                {
3870                        KdLeaf *leaf = kdLeaves[i];
3871                        RayContainer vcRays;
3872
3873                        cout << "creating output for view cell " << i << " ... ";
3874#if 0
3875                        // check whether we can add the current ray to the output rays
3876                        for (int k = 0; k < raysOut; ++ k)
3877                        {
3878                                Ray *ray = sampleRays[k];
3879
3880                                for (int j = 0; j < (int)ray->bspIntersections.size(); ++ j)
3881                                {
3882                                        BspLeaf *leaf2 = ray->bspIntersections[j].mLeaf;
3883
3884                                        if (leaf->GetViewCell() == leaf2->GetViewCell())
3885                                        {
3886                                                vcRays.push_back(ray);
3887                                        }
3888                                }
3889                        }
3890#endif
3891                        Intersectable::NewMail();
3892
3893                        ViewCell *vc = leaf->mViewCell;
3894                        char str[64]; sprintf(str, "viewcell%04d.wrl", i);
3895
3896                        Exporter *exporter = Exporter::GetExporter(str);
3897                        exporter->SetFilled();
3898
3899                        exporter->SetWireframe();
3900                        //exporter->SetFilled();
3901
3902                        Material m;//= RandomMaterial();
3903                        m.mDiffuseColor = RgbColor(1, 1, 0);
3904                        exporter->SetForcedMaterial(m);
3905
3906                        AxisAlignedBox3 box = mKdTree->GetBox(leaf);
3907                        exporter->ExportBox(box);
3908
3909                        // export rays piercing this view cell
3910                        exporter->ExportRays(vcRays, 1000, RgbColor(0, 1, 0));
3911
3912                        m.mDiffuseColor = RgbColor(1, 0, 0);
3913                        exporter->SetForcedMaterial(m);
3914
3915                        // exporter->SetWireframe();
3916                        exporter->SetFilled();
3917
3918                        ObjectPvsIterator pit = vc->GetPvs().GetIterator();
3919                       
3920                        while (pit.HasMoreEntries())
3921                        {               
3922                                ObjectPvsEntry entry = pit.Next();
3923                               
3924                                //-- output PVS of view cell
3925                                Intersectable *intersect = entry.mObject;
3926                                if (!intersect->Mailed())
3927                                {
3928                                        exporter->ExportIntersectable(intersect);
3929                                        intersect->Mail();
3930                                }
3931                        }
3932
3933                        DEL_PTR(exporter);
3934                        cout << "finished" << endl;
3935                }
3936
3937                DEL_PTR(rays);
3938        }
3939        else // using kd PVS of objects
3940        {
3941                for (int i = 0; i < limit; ++ i)
3942                {
3943                        VssRay *ray = sampleRays[i];
3944
3945                        // check whether we can add this to the rays
3946                        for (int j = 0; j < pvsOut; j++)
3947                        {
3948                                if (objects[j] == ray->mTerminationObject)
3949                                {
3950                                        rays[j].push_back(ray);
3951                                }
3952                        }
3953                }
3954
3955                if (exportRays)
3956                {
3957                        Exporter *exporter = NULL;
3958                        exporter = Exporter::GetExporter("sample-rays.x3d");
3959                        exporter->SetWireframe();
3960                        exporter->ExportKdTree(*mKdTree);
3961
3962                        for (int i = 0; i < pvsOut; i++)
3963                                exporter->ExportRays(rays[i], RgbColor(1, 0, 0));
3964
3965                        exporter->SetFilled();
3966                        delete exporter;
3967                }
3968
3969                for (int k=0; k < pvsOut; k++)
3970                {
3971                        Intersectable *object = objects[k];
3972                        char str[64]; sprintf(str, "viewcell%04d.wrl", k);
3973
3974                        Exporter *exporter = Exporter::GetExporter(str);
3975                        exporter->SetWireframe();
3976
3977                        // matt: no kd pvs
3978                        /*
3979                        KdPvsMap::iterator kit = object->mKdPvs.mEntries.begin();
3980                        Intersectable::NewMail();
3981
3982                        // avoid adding the object to the list
3983                        object->Mail();
3984                        ObjectContainer visibleObjects;
3985
3986                        for (; kit != object->mKdPvs.mEntries.end(); i++)
3987                        {
3988                                KdNode *node = (*kit).first;
3989                                exporter->ExportBox(mKdTree->GetBox(node));
3990
3991                                mKdTree->CollectObjects(node, visibleObjects);
3992                        }
3993
3994                        exporter->ExportRays(rays[k],  RgbColor(0, 1, 0));
3995                        exporter->SetFilled();
3996
3997                        for (int j = 0; j < visibleObjects.size(); j++)
3998                                exporter->ExportIntersectable(visibleObjects[j]);
3999
4000                        Material m;
4001                        m.mDiffuseColor = RgbColor(1, 0, 0);
4002                        exporter->SetForcedMaterial(m);
4003                        exporter->ExportIntersectable(object);
4004*/
4005                        delete exporter;
4006                }
4007        }
4008}
4009
4010
4011ViewCell *KdViewCellsManager::GenerateViewCell(Mesh *mesh) const
4012{
4013        return new KdViewCell(mesh);
4014}
4015
4016
4017void KdViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
4018                                                                                                ViewCell *vc,
4019                                                                                                const AxisAlignedBox3 *sceneBox,
4020                                                                                                const AxisAlignedPlane *clipPlane
4021                                                                                                ) const
4022{
4023        ViewCellContainer leaves;
4024        mViewCellsTree->CollectLeaves(vc, leaves);
4025        ViewCellContainer::const_iterator it, it_end = leaves.end();
4026
4027        for (it = leaves.begin(); it != it_end; ++ it)
4028        {
4029                KdViewCell *kdVc = dynamic_cast<KdViewCell *>(*it);
4030                exporter->ExportBox(mKdTree->GetBox(kdVc->mLeaves[0]));
4031        }
4032}
4033
4034
4035int KdViewCellsManager::GetType() const
4036{
4037        return ViewCellsManager::KD;
4038}
4039
4040
4041
4042KdNode *KdViewCellsManager::GetNodeForPvs(KdLeaf *leaf)
4043{
4044        KdNode *node = leaf;
4045
4046        while (node->mParent && node->mDepth > mKdPvsDepth)
4047                node = node->mParent;
4048
4049        return node;
4050}
4051
4052int KdViewCellsManager::CastLineSegment(const Vector3 &origin,
4053                                                                                const Vector3 &termination,
4054                                                                                ViewCellContainer &viewcells)
4055{
4056        return mKdTree->CastLineSegment(origin, termination, viewcells);
4057}
4058
4059
4060void KdViewCellsManager::CreateMesh(ViewCell *vc)
4061{
4062        // TODO
4063}
4064
4065
4066
4067void KdViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
4068                                                                                                vector<MergeCandidate> &candidates)
4069{
4070        // TODO
4071}
4072
4073
4074
4075/**************************************************************************/
4076/*                   VspBspViewCellsManager implementation                */
4077/**************************************************************************/
4078
4079
4080VspBspViewCellsManager::VspBspViewCellsManager(ViewCellsTree *vcTree, VspBspTree *vspBspTree):
4081ViewCellsManager(vcTree), mVspBspTree(vspBspTree)
4082{
4083        Environment::GetSingleton()->GetIntValue("VspBspTree.Construction.samples", mInitialSamples);
4084        mVspBspTree->SetViewCellsManager(this);
4085        mVspBspTree->mViewCellsTree = mViewCellsTree;
4086}
4087
4088
4089VspBspViewCellsManager::~VspBspViewCellsManager()
4090{
4091}
4092
4093
4094float VspBspViewCellsManager::GetProbability(ViewCell *viewCell)
4095{
4096        if (0 && mVspBspTree->mUseAreaForPvs)
4097                return GetArea(viewCell) / GetAccVcArea();
4098        else
4099                return GetVolume(viewCell) / mViewSpaceBox.GetVolume();
4100}
4101
4102
4103void VspBspViewCellsManager::CollectViewCells()
4104{
4105        // view cells tree constructed?
4106        if (!ViewCellsTreeConstructed())
4107        {
4108                mVspBspTree->CollectViewCells(mViewCells, false);
4109        }
4110        else
4111        {       
4112                // we can use the view cells tree hierarchy to get the right set
4113                mViewCellsTree->CollectBestViewCellSet(mViewCells, mNumActiveViewCells);
4114        }
4115}
4116
4117
4118void VspBspViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
4119                                                                                                        vector<MergeCandidate> &candidates)
4120{       
4121        cout << "collecting merge candidates ... " << endl;
4122
4123        if (mUseRaysForMerge)
4124        {
4125                mVspBspTree->CollectMergeCandidates(rays, candidates);
4126        }
4127        else
4128        {
4129                vector<BspLeaf *> leaves;
4130                mVspBspTree->CollectLeaves(leaves);
4131       
4132                mVspBspTree->CollectMergeCandidates(leaves, candidates);
4133        }
4134
4135        cout << "fininshed collecting candidates" << endl;
4136}
4137
4138
4139bool VspBspViewCellsManager::ViewCellsConstructed() const
4140{
4141        return mVspBspTree->GetRoot() != NULL;
4142}
4143
4144
4145ViewCell *VspBspViewCellsManager::GenerateViewCell(Mesh *mesh) const
4146{
4147        return new BspViewCell(mesh);
4148}
4149
4150
4151int VspBspViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
4152                                                                                                 const VssRayContainer &rays)
4153{
4154        mMaxPvsSize = (int)(mMaxPvsRatio * (float)objects.size());
4155
4156        // if view cells were already constructed
4157        if (ViewCellsConstructed())
4158        {
4159                return 0;
4160        }
4161
4162        int sampleContributions = 0;
4163        VssRayContainer sampleRays;
4164
4165        const int limit = min(mInitialSamples, (int)rays.size());
4166
4167        Debug << "samples used for vsp bsp subdivision: " << mInitialSamples
4168                  << ", actual rays: " << (int)rays.size() << endl;
4169
4170        VssRayContainer savedRays;
4171
4172        if (SAMPLE_AFTER_SUBDIVISION)
4173        {
4174                VssRayContainer constructionRays;
4175               
4176                GetRaySets(rays, mInitialSamples, constructionRays, &savedRays);
4177
4178                Debug << "rays used for initial construction: " << (int)constructionRays.size() << endl;
4179                Debug << "rays saved for later use: " << (int)savedRays.size() << endl;
4180       
4181                mVspBspTree->Construct(constructionRays, &mViewSpaceBox);
4182        }
4183        else
4184        {
4185                Debug << "rays used for initial construction: " << (int)rays.size() << endl;
4186                mVspBspTree->Construct(rays, &mViewSpaceBox);
4187        }
4188
4189        // collapse invalid regions
4190        cout << "collapsing invalid tree regions ... ";
4191        long startTime = GetTime();
4192
4193        const int collapsedLeaves = mVspBspTree->CollapseTree();
4194        Debug << "collapsed in " << TimeDiff(startTime, GetTime()) * 1e-3
4195                  << " seconds" << endl;
4196
4197    cout << "finished" << endl;
4198
4199        /////////////////
4200        //-- stats after construction
4201
4202        Debug << mVspBspTree->GetStatistics() << endl;
4203
4204        ResetViewCells();
4205        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
4206
4207
4208        //////////////////////
4209        //-- recast the rest of the rays
4210
4211        startTime = GetTime();
4212
4213        cout << "Computing remaining ray contributions ... ";
4214
4215        if (SAMPLE_AFTER_SUBDIVISION)
4216                ComputeSampleContributions(savedRays, true, false);
4217
4218        cout << "finished" << endl;
4219
4220        Debug << "Computed remaining ray contribution in " << TimeDiff(startTime, GetTime()) * 1e-3
4221                  << " secs" << endl;
4222
4223        cout << "construction finished" << endl;
4224
4225        if (0)
4226        {       ////////
4227                //-- real meshes are contructed at this stage
4228
4229                cout << "finalizing view cells ... ";
4230                FinalizeViewCells(true);
4231                cout << "finished" << endl;
4232        }
4233
4234        return sampleContributions;
4235}
4236
4237
4238void VspBspViewCellsManager::MergeViewCells(const VssRayContainer &rays,
4239                                                                                        const ObjectContainer &objects)
4240{
4241    int vcSize = 0;
4242        int pvsSize = 0;
4243
4244        //-- merge view cells
4245        cout << "starting merge using " << mPostProcessSamples << " samples ... " << endl;
4246        long startTime = GetTime();
4247
4248
4249        if (mMergeViewCells)
4250        {
4251                // TODO: should be done BEFORE the ray casting
4252                // compute tree by merging the nodes based on cost heuristics
4253                mViewCellsTree->ConstructMergeTree(rays, objects);
4254        }
4255        else
4256        {
4257                // compute tree by merging the nodes of the spatial hierarchy
4258                ViewCell *root = ConstructSpatialMergeTree(mVspBspTree->GetRoot());
4259                mViewCellsTree->SetRoot(root);
4260
4261                // compute pvs
4262                ObjectPvs pvs;
4263                UpdatePvsForEvaluation(root, pvs);
4264        }
4265
4266        if (1)
4267        {
4268                char mstats[100];
4269                ObjectPvs pvs;
4270
4271                Environment::GetSingleton()->GetStringValue("ViewCells.mergeStats", mstats);
4272                mViewCellsTree->ExportStats(mstats);
4273        }
4274
4275        cout << "merged view cells in "
4276                 << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl;
4277
4278        Debug << "Postprocessing: Merged view cells in "
4279                  << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl << endl;
4280       
4281
4282        //////////////////
4283        //-- stats and visualizations
4284
4285        int savedColorCode = mColorCode;
4286       
4287        // get currently active view cell set
4288        ResetViewCells();
4289        Debug << "\nView cells after merge:\n" << mCurrentViewCellsStats << endl;
4290       
4291        if (mShowVisualization) // export merged view cells
4292        {
4293                mColorCode = 0;
4294                Exporter *exporter = Exporter::GetExporter("merged_view_cells.wrl");
4295               
4296                cout << "exporting view cells after merge ... ";
4297
4298                if (exporter)
4299                {
4300                        if (0)
4301                                exporter->SetWireframe();
4302                        else
4303                                exporter->SetFilled();
4304
4305                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
4306
4307                        if (mExportGeometry)
4308                        {
4309                                Material m;
4310                                m.mDiffuseColor = RgbColor(0, 1, 0);
4311                                exporter->SetForcedMaterial(m);
4312                                exporter->SetFilled();
4313
4314                                exporter->ExportGeometry(objects);
4315                        }
4316
4317                        delete exporter;
4318                }
4319                cout << "finished" << endl;
4320        }
4321
4322        if (mShowVisualization)
4323        {
4324                // use pvs size for color coding
4325                mColorCode = 1;
4326                Exporter *exporter = Exporter::GetExporter("merged_view_cells_pvs.wrl");
4327
4328                cout << "exporting view cells after merge (pvs size) ... ";     
4329
4330                if (exporter)
4331                {
4332                        exporter->SetFilled();
4333
4334                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
4335
4336                        if (mExportGeometry)
4337                        {
4338                                Material m;
4339                                m.mDiffuseColor = RgbColor(0, 1, 0);
4340                                exporter->SetForcedMaterial(m);
4341                                exporter->SetFilled();
4342
4343                                exporter->ExportGeometry(objects);
4344                        }
4345
4346                        delete exporter;
4347                }
4348                cout << "finished" << endl;
4349        }
4350
4351        mColorCode = savedColorCode;
4352}
4353
4354
4355void VspBspViewCellsManager::RefineViewCells(const VssRayContainer &rays,
4356                                                                                         const ObjectContainer &objects)
4357{
4358        mRenderer->RenderScene();
4359
4360        SimulationStatistics ss;
4361        dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
4362    Debug << "render time before refine\n\n" << ss << endl;
4363
4364        const long startTime = GetTime();
4365        cout << "Refining the merged view cells ... ";
4366
4367        // refining the merged view cells
4368        const int refined = mViewCellsTree->RefineViewCells(rays, objects);
4369
4370        //-- stats and visualizations
4371        cout << "finished" << endl;
4372        cout << "refined " << refined << " view cells in "
4373                 << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl;
4374
4375        Debug << "Postprocessing: refined " << refined << " view cells in "
4376                  << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl << endl;
4377}
4378
4379
4380int VspBspViewCellsManager::PostProcess(const ObjectContainer &objects,
4381                                                                                const VssRayContainer &rays)
4382{
4383        if (!ViewCellsConstructed())
4384        {
4385                Debug << "postprocess error: no view cells constructed" << endl;
4386                return 0;
4387        }
4388
4389        // view cells already finished before post processing step
4390        // (i.e. because they were loaded)
4391        if (mViewCellsFinished)
4392        {
4393                FinalizeViewCells(true);
4394                EvaluateViewCellsStats();
4395
4396                return 0;
4397        }
4398
4399        // check if new view cells turned invalid
4400        int minPvs, maxPvs;
4401
4402        if (0)
4403        {
4404                minPvs = mMinPvsSize;
4405                maxPvs = mMaxPvsSize;
4406        }
4407        else
4408        {
4409                // problem matt: why did I start here from zero?
4410                minPvs = 0;
4411                maxPvs = mMaxPvsSize;
4412        }
4413
4414        Debug << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
4415        cout << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
4416       
4417        SetValidity(minPvs, maxPvs);
4418
4419        // update valid view space according to valid view cells
4420        if (0) mVspBspTree->ValidateTree();
4421
4422        // area has to be recomputed
4423        mTotalAreaValid = false;
4424        VssRayContainer postProcessRays;
4425        GetRaySets(rays, mPostProcessSamples, postProcessRays);
4426
4427        Debug << "post processing using " << (int)postProcessRays.size() << " samples" << endl;
4428
4429        //////////
4430        //-- merge neighbouring view cells
4431        MergeViewCells(postProcessRays, objects);
4432       
4433        // refines the merged view cells
4434        if (0) RefineViewCells(postProcessRays, objects);
4435
4436
4437        ///////////
4438        //-- render simulation after merge + refine
4439
4440        cout << "\nview cells partition render time before compress" << endl << endl;;
4441        dynamic_cast<RenderSimulator *>(mRenderer)->RenderScene();
4442        SimulationStatistics ss;
4443        dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
4444        cout << ss << endl;
4445       
4446        if (0) CompressViewCells();
4447       
4448        // collapse sibling leaves that share the same view cell
4449        if (0) mVspBspTree->CollapseTree();
4450
4451        // recompute view cell list and statistics
4452        ResetViewCells();
4453
4454        // compute final meshes and volume / area
4455        if (1) FinalizeViewCells(true);
4456
4457        return 0;
4458}
4459
4460
4461int VspBspViewCellsManager::GetType() const
4462{
4463        return VSP_BSP;
4464}
4465
4466
4467ViewCell *VspBspViewCellsManager::ConstructSpatialMergeTree(BspNode *root)
4468{
4469        // terminate recursion
4470        if (root->IsLeaf())
4471        {
4472                BspLeaf *leaf = dynamic_cast<BspLeaf *>(root);
4473                leaf->GetViewCell()->SetMergeCost(0.0f);
4474                return leaf->GetViewCell();
4475        }
4476       
4477       
4478        BspInterior *interior = dynamic_cast<BspInterior *>(root);
4479        ViewCellInterior *viewCellInterior = new ViewCellInterior();
4480               
4481        // evaluate merge cost for priority traversal
4482        float mergeCost = 1.0f / (float)root->mTimeStamp;
4483        viewCellInterior->SetMergeCost(mergeCost);
4484
4485        float volume = 0;
4486       
4487        BspNode *front = interior->GetFront();
4488        BspNode *back = interior->GetBack();
4489
4490
4491        ObjectPvs frontPvs, backPvs;
4492
4493        //-- recursivly compute child hierarchies
4494        ViewCell *backVc = ConstructSpatialMergeTree(back);
4495        ViewCell *frontVc = ConstructSpatialMergeTree(front);
4496
4497
4498        viewCellInterior->SetupChildLink(backVc);
4499        viewCellInterior->SetupChildLink(frontVc);
4500
4501        volume += backVc->GetVolume();
4502        volume += frontVc->GetVolume();
4503
4504        viewCellInterior->SetVolume(volume);
4505
4506        return viewCellInterior;
4507}
4508
4509
4510bool VspBspViewCellsManager::GetViewPoint(Vector3 &viewPoint) const
4511{
4512        if (!ViewCellsConstructed())
4513                return ViewCellsManager::GetViewPoint(viewPoint);
4514
4515        // TODO: set reasonable limit
4516        const int limit = 20;
4517
4518        for (int i = 0; i < limit; ++ i)
4519        {
4520                viewPoint = mViewSpaceBox.GetRandomPoint();
4521                if (mVspBspTree->ViewPointValid(viewPoint))
4522                {
4523                        return true;
4524                }
4525        }
4526
4527        Debug << "failed to find valid view point, taking " << viewPoint << endl;
4528        return false;
4529}
4530
4531
4532bool VspBspViewCellsManager::ViewPointValid(const Vector3 &viewPoint) const
4533{
4534        // $$JB -> implemented in viewcellsmanager (slower, but allows dynamic
4535        // validy update in preprocessor for all managers)
4536        return ViewCellsManager::ViewPointValid(viewPoint);
4537
4538        //      return mViewSpaceBox.IsInside(viewPoint) &&
4539        //                 mVspBspTree->ViewPointValid(viewPoint);
4540}
4541
4542
4543void VspBspViewCellsManager::Visualize(const ObjectContainer &objects,
4544                                                                           const VssRayContainer &sampleRays)
4545{
4546        if (!ViewCellsConstructed())
4547                return;
4548
4549        VssRayContainer visRays;
4550        GetRaySets(sampleRays, mVisualizationSamples, visRays);
4551       
4552        if (1)
4553        {       
4554                //////////////////
4555                //-- export final view cell partition
4556
4557                Exporter *exporter = Exporter::GetExporter("final_view_cells.wrl");
4558               
4559                if (exporter)
4560                {
4561                        cout << "exporting view cells after post process ... ";
4562                        if (0)
4563                        {       // export view space box
4564                                exporter->SetWireframe();
4565                                exporter->ExportBox(mViewSpaceBox);
4566                                exporter->SetFilled();
4567                        }
4568
4569                        Material m;
4570                        m.mDiffuseColor.r = 0.0f;
4571                        m.mDiffuseColor.g = 0.5f;
4572                        m.mDiffuseColor.b = 0.5f;
4573
4574            exporter->SetForcedMaterial(m);
4575
4576                        if (1 && mExportGeometry)
4577                        {
4578                                exporter->ExportGeometry(objects);
4579                        }
4580
4581                        if (0 && mExportRays)
4582                        {
4583                                exporter->ExportRays(visRays, RgbColor(1, 0, 0));
4584                        }
4585                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
4586
4587                        delete exporter;
4588                        cout << "finished" << endl;
4589                }
4590        }
4591
4592        ////////////////
4593        //-- visualization of the BSP splits
4594
4595        bool exportSplits = false;
4596        Environment::GetSingleton()->GetBoolValue("VspBspTree.Visualization.exportSplits", exportSplits);
4597
4598        if (exportSplits)
4599        {
4600                cout << "exporting splits ... ";
4601                ExportSplits(objects, visRays);
4602                cout << "finished" << endl;
4603        }
4604
4605        ////////
4606        //-- export single view cells
4607       
4608        int leafOut;
4609        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.maxOutput", leafOut);
4610        const int raysOut = 100;
4611       
4612        ExportSingleViewCells(objects, leafOut, false, true, false, raysOut, "");
4613}
4614
4615
4616void VspBspViewCellsManager::ExportSplits(const ObjectContainer &objects,
4617                                                                                  const VssRayContainer &rays)
4618{
4619        Exporter *exporter = Exporter::GetExporter("bsp_splits.x3d");
4620
4621        if (exporter)
4622        {
4623                Material m;
4624                m.mDiffuseColor = RgbColor(1, 0, 0);
4625                exporter->SetForcedMaterial(m);
4626                exporter->SetWireframe();
4627
4628                exporter->ExportBspSplits(*mVspBspTree, true);
4629
4630                // take forced material, else big scenes cannot be viewed
4631                m.mDiffuseColor = RgbColor(0, 1, 0);
4632                exporter->SetForcedMaterial(m);
4633                exporter->SetFilled();
4634
4635                exporter->ResetForcedMaterial();
4636
4637                // export rays
4638                if (mExportRays)
4639                {
4640                        exporter->ExportRays(rays, RgbColor(1, 1, 0));
4641                }
4642
4643                if (mExportGeometry)
4644                {
4645                        exporter->ExportGeometry(objects);
4646                }
4647                delete exporter;
4648        }
4649}
4650
4651
4652void VspBspViewCellsManager::ExportSingleViewCells(const ObjectContainer &objects,
4653                                                                                                   const int maxViewCells,
4654                                                                                                   const bool sortViewCells,
4655                                                                                                   const bool exportPvs,
4656                                                                                                   const bool exportRays,
4657                                                                                                   const int maxRays,
4658                                                                                                   const string prefix,
4659                                                                                                   VssRayContainer *visRays)
4660{       
4661        if (sortViewCells)
4662        {
4663                // sort view cells to visualize the largest view cells
4664                sort(mViewCells.begin(), mViewCells.end(), ViewCell::LargerRenderCost);
4665        }
4666
4667        //////////
4668        //-- some view cells for output
4669
4670        ViewCell::NewMail();
4671        const int limit = min(maxViewCells, (int)mViewCells.size());
4672       
4673        for (int i = 0; i < limit; ++ i)
4674        {
4675                cout << "creating output for view cell " << i << " ... ";
4676
4677                ViewCell *vc = sortViewCells ? // largest view cell pvs first?
4678                        mViewCells[(int)RandomValue(0, (float)mViewCells.size() - 0.5f)] : mViewCells[i];
4679
4680                if (vc->Mailed() || vc->GetId() == OUT_OF_BOUNDS_ID)
4681                        continue;
4682
4683                vc->Mail();
4684
4685                ObjectPvs pvs;
4686                mViewCellsTree->GetPvs(vc, pvs);
4687
4688                char s[64]; sprintf(s, "%sviewcell%04d.wrl", prefix.c_str(), i);
4689                Exporter *exporter = Exporter::GetExporter(s);
4690               
4691                const float pvsCost = mViewCellsTree->GetPvsCost(vc);
4692                cout << "view cell " << vc->GetId() << ": pvs cost=" << pvsCost << endl;
4693
4694                if (exportRays)
4695                {
4696                        ////////////
4697                        //-- export rays piercing this view cell
4698
4699                        // take rays stored with the view cells during subdivision
4700                        VssRayContainer vcRays;
4701            VssRayContainer collectRays;
4702
4703                        // collect initial view cells
4704                        ViewCellContainer leaves;
4705                        mViewCellsTree->CollectLeaves(vc, leaves);
4706
4707                        ViewCellContainer::const_iterator vit, vit_end = leaves.end();
4708                for (vit = leaves.begin(); vit != vit_end; ++ vit)
4709                        {       
4710                                BspLeaf *vcLeaf = dynamic_cast<BspViewCell *>(*vit)->mLeaves[0];
4711                                VssRayContainer::const_iterator rit, rit_end = vcLeaf->mVssRays.end();
4712
4713                                for (rit = vcLeaf->mVssRays.begin(); rit != rit_end; ++ rit)
4714                                {
4715                                        collectRays.push_back(*rit);
4716                                }
4717                        }
4718
4719                        const int raysOut = min((int)collectRays.size(), maxRays);
4720               
4721                        // prepare some rays for output
4722                        VssRayContainer::const_iterator rit, rit_end = collectRays.end();
4723                        for (rit = collectRays.begin(); rit != rit_end; ++ rit)
4724                        {
4725                                const float p = RandomValue(0.0f, (float)collectRays.size());
4726                       
4727                                if (p < raysOut)
4728                                {
4729                                        vcRays.push_back(*rit);
4730                                }
4731                        }
4732
4733                        exporter->ExportRays(vcRays, RgbColor(1, 1, 1));
4734                }
4735               
4736                ////////////////
4737                //-- export view cell geometry
4738
4739                exporter->SetWireframe();
4740
4741                Material m;//= RandomMaterial();
4742                m.mDiffuseColor = RgbColor(0, 1, 0);
4743                exporter->SetForcedMaterial(m);
4744
4745                ExportViewCellGeometry(exporter, vc, NULL, NULL);
4746                exporter->SetFilled();
4747
4748                if (exportPvs)
4749                {
4750                        Intersectable::NewMail();
4751
4752                        ObjectPvsIterator pit = pvs.GetIterator();
4753
4754                        cout << endl;
4755
4756                        // output PVS of view cell
4757                        while (pit.HasMoreEntries())
4758                        {
4759                                ObjectPvsEntry entry = pit.Next();             
4760                                Intersectable *intersect = entry.mObject;
4761                               
4762                                if (!intersect->Mailed())
4763                                {
4764                                        intersect->Mail();
4765
4766                                        m = RandomMaterial();
4767                                        exporter->SetForcedMaterial(m);
4768                                        exporter->ExportIntersectable(intersect);
4769                                }
4770                        }
4771                        cout << endl;
4772                }
4773               
4774                DEL_PTR(exporter);
4775                cout << "finished" << endl;
4776        }
4777}
4778
4779
4780void VspBspViewCellsManager::TestFilter(const ObjectContainer &objects)
4781{
4782        Exporter *exporter = Exporter::GetExporter("filter.x3d");
4783
4784        Vector3 bsize = mViewSpaceBox.Size();
4785        const Vector3 viewPoint(mViewSpaceBox.Center());
4786        float w = Magnitude(mViewSpaceBox.Size()) * mFilterWidth;
4787        const Vector3 width = Vector3(w);
4788       
4789        PrVs testPrVs;
4790       
4791        if (exporter)
4792        {
4793                ViewCellContainer viewCells;
4794       
4795        const AxisAlignedBox3 tbox = GetFilterBBox(viewPoint, mFilterWidth);
4796
4797                GetPrVS(viewPoint, testPrVs, GetFilterWidth());
4798
4799                exporter->SetWireframe();
4800
4801                exporter->SetForcedMaterial(RgbColor(1,1,1));
4802                exporter->ExportBox(tbox);
4803               
4804                exporter->SetFilled();
4805
4806                exporter->SetForcedMaterial(RgbColor(0,1,0));
4807                ExportViewCellGeometry(exporter, GetViewCell(viewPoint), NULL, NULL);
4808
4809                //exporter->ResetForcedMaterial();
4810                exporter->SetForcedMaterial(RgbColor(0,0,1));
4811                ExportViewCellGeometry(exporter, testPrVs.mViewCell, NULL, NULL);
4812
4813        exporter->SetForcedMaterial(RgbColor(1,0,0));
4814                exporter->ExportGeometry(objects);
4815
4816                delete exporter;
4817        }
4818}
4819
4820
4821int VspBspViewCellsManager::ComputeBoxIntersections(const AxisAlignedBox3 &box,
4822                                                                                                        ViewCellContainer &viewCells) const
4823{
4824        return mVspBspTree->ComputeBoxIntersections(box, viewCells);
4825}
4826
4827
4828int VspBspViewCellsManager::CastLineSegment(const Vector3 &origin,
4829                                                                                        const Vector3 &termination,
4830                                                                                        ViewCellContainer &viewcells)
4831{
4832        return mVspBspTree->CastLineSegment(origin, termination, viewcells);
4833}
4834
4835
4836void VspBspViewCellsManager::VisualizeWithFromPointQueries()
4837{
4838        int numSamples;
4839       
4840        Environment::GetSingleton()->GetIntValue("RenderSampler.samples", numSamples);
4841        cout << "samples" << numSamples << endl;
4842
4843        vector<RenderCostSample> samples;
4844 
4845        if (!mPreprocessor->GetRenderer())
4846                return;
4847
4848        //start the view point queries
4849        long startTime = GetTime();
4850        cout << "starting sampling of render cost ... ";
4851       
4852        mPreprocessor->GetRenderer()->SampleRenderCost(numSamples, samples, true);
4853
4854        cout << "finished in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
4855
4856
4857        // for each sample:
4858        //    find view cells associated with the samples
4859        //    store the sample pvs with the pvs associated with the view cell
4860        //
4861        // for each view cell:
4862        //    compute difference point sampled pvs - view cell pvs
4863        //    export geometry with color coded pvs difference
4864       
4865    std::map<ViewCell *, ObjectPvs> sampleMap;
4866
4867        vector<RenderCostSample>::const_iterator rit, rit_end = samples.end();
4868
4869        for (rit = samples.begin(); rit != rit_end; ++ rit)
4870        {
4871                RenderCostSample sample = *rit;
4872       
4873                ViewCell *vc = GetViewCell(sample.mPosition);
4874
4875                std::map<ViewCell *, ObjectPvs>::iterator it = sampleMap.find(vc);
4876
4877                if (it == sampleMap.end())
4878                {
4879                        sampleMap[vc] = sample.mPvs;
4880                }
4881                else
4882                {
4883                        (*it).second.MergeInPlace(sample.mPvs);
4884                }
4885        }
4886
4887        // visualize the view cells
4888        std::map<ViewCell *, ObjectPvs>::const_iterator vit, vit_end = sampleMap.end();
4889
4890        Material m;//= RandomMaterial();
4891
4892        for (vit = sampleMap.begin(); vit != vit_end; ++ vit)
4893        {
4894                ViewCell *vc = (*vit).first;
4895               
4896                const int pvsVc = mViewCellsTree->GetPvsEntries(vc);
4897                const int pvsPtSamples = (*vit).second.GetSize();
4898
4899        m.mDiffuseColor.r = (float) (pvsVc - pvsPtSamples);
4900                m.mDiffuseColor.b = 1.0f;
4901                //exporter->SetForcedMaterial(m);
4902                //ExportViewCellGeometry(exporter, vc, mClipPlaneForViz);
4903
4904                /*      // counting the pvss
4905                for (rit = samples.begin(); rit != rit_end; ++ rit)
4906                {
4907                        RenderCostSample sample = *rit;
4908                        ViewCell *vc = GetViewCell(sample.mPosition);
4909
4910                        AxisAlignedBox3 box(sample.mPosition - Vector3(1, 1, 1), sample.mPosition + Vector3(1, 1, 1));
4911                        Mesh *hMesh = CreateMeshFromBox(box);
4912
4913                        DEL_PTR(hMesh);
4914                }
4915                */
4916        }
4917}
4918
4919
4920void VspBspViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
4921                                                                                                        ViewCell *vc,
4922                                                                                                        const AxisAlignedBox3 *sceneBox,
4923                                                                                                        const AxisAlignedPlane *clipPlane
4924                                                                                                        ) const
4925{
4926        if (clipPlane)
4927        {
4928                const Plane3 plane = clipPlane->GetPlane();
4929
4930                ViewCellContainer leaves;
4931                mViewCellsTree->CollectLeaves(vc, leaves);
4932                ViewCellContainer::const_iterator it, it_end = leaves.end();
4933
4934                for (it = leaves.begin(); it != it_end; ++ it)
4935                {
4936                        BspNodeGeometry geom;
4937                        BspNodeGeometry front;
4938                        BspNodeGeometry back;
4939
4940                        mVspBspTree->ConstructGeometry(*it, geom);
4941
4942                        const float eps = 0.0001f;
4943                        const int cf = geom.Side(plane, eps);
4944
4945                        if (cf == -1)
4946                        {
4947                                exporter->ExportPolygons(geom.GetPolys());
4948                        }
4949                        else if (cf == 0)
4950                        {
4951                                geom.SplitGeometry(front,
4952                                                                   back,
4953                                                                   plane,
4954                                                                   mViewSpaceBox,
4955                                                                   eps);
4956
4957                                if (back.Valid())
4958                                {
4959                                        exporter->ExportPolygons(back.GetPolys());
4960                                }                       
4961                        }
4962                }
4963        }
4964        else
4965        {
4966                // export mesh if available
4967                // TODO: some bug here?
4968                if (1 && vc->GetMesh())
4969                {
4970                        exporter->ExportMesh(vc->GetMesh());
4971                }
4972                else
4973                {
4974                        BspNodeGeometry geom;
4975                        mVspBspTree->ConstructGeometry(vc, geom);
4976                        exporter->ExportPolygons(geom.GetPolys());
4977                }
4978        }
4979}
4980
4981
4982int VspBspViewCellsManager::GetMaxTreeDiff(ViewCell *vc) const
4983{
4984        ViewCellContainer leaves;
4985        mViewCellsTree->CollectLeaves(vc, leaves);
4986
4987        int maxDist = 0;
4988       
4989        // compute max height difference
4990        for (int i = 0; i < (int)leaves.size(); ++ i)
4991        {
4992                for (int j = 0; j < (int)leaves.size(); ++ j)
4993                {
4994                        BspLeaf *leaf = dynamic_cast<BspViewCell *>(leaves[i])->mLeaves[0];
4995
4996                        if (i != j)
4997                        {
4998                                BspLeaf *leaf2 =dynamic_cast<BspViewCell *>(leaves[j])->mLeaves[0];
4999                                const int dist = mVspBspTree->TreeDistance(leaf, leaf2);
5000                               
5001                                if (dist > maxDist)
5002                                        maxDist = dist;
5003                        }
5004                }
5005        }
5006
5007        return maxDist;
5008}
5009
5010
5011ViewCell *VspBspViewCellsManager::GetViewCell(const Vector3 &point, const bool active) const
5012{
5013        if (!ViewCellsConstructed())
5014                return NULL;
5015
5016        if (!mViewSpaceBox.IsInside(point))
5017          return NULL;
5018
5019        return mVspBspTree->GetViewCell(point, active);
5020}
5021
5022
5023void VspBspViewCellsManager::CreateMesh(ViewCell *vc)
5024{
5025        BspNodeGeometry geom;
5026        mVspBspTree->ConstructGeometry(vc, geom);
5027       
5028        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
5029        IncludeNodeGeomInMesh(geom, *mesh);
5030
5031        vc->SetMesh(mesh);
5032}
5033
5034
5035int VspBspViewCellsManager::CastBeam(Beam &beam)
5036{
5037        return mVspBspTree->CastBeam(beam);
5038}
5039
5040
5041void VspBspViewCellsManager::Finalize(ViewCell *viewCell,
5042                                                                          const bool createMesh)
5043{
5044        float area = 0;
5045        float volume = 0;
5046
5047        ViewCellContainer leaves;
5048        mViewCellsTree->CollectLeaves(viewCell, leaves);
5049
5050        ViewCellContainer::const_iterator it, it_end = leaves.end();
5051
5052    for (it = leaves.begin(); it != it_end; ++ it)
5053        {
5054                BspNodeGeometry geom;
5055                mVspBspTree->ConstructGeometry(*it, geom);
5056
5057                const float lVol = geom.GetVolume();
5058                const float lArea = geom.GetArea();
5059
5060                area += lArea;
5061                volume += lVol;
5062
5063                if (createMesh)
5064                        CreateMesh(*it);
5065        }
5066
5067        viewCell->SetVolume(volume);
5068        viewCell->SetArea(area);
5069}
5070
5071
5072void VspBspViewCellsManager::TestSubdivision()
5073{
5074        ViewCellContainer leaves;
5075        mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
5076
5077        ViewCellContainer::const_iterator it, it_end = leaves.end();
5078
5079        const float vol = mViewSpaceBox.GetVolume();
5080        float subdivVol = 0;
5081        float newVol = 0;
5082
5083        for (it = leaves.begin(); it != it_end; ++ it)
5084        {
5085                BspNodeGeometry geom;
5086                mVspBspTree->ConstructGeometry(*it, geom);
5087
5088                const float lVol = geom.GetVolume();
5089               
5090                newVol += lVol;
5091                subdivVol += (*it)->GetVolume();
5092               
5093                float thres = 0.9f;
5094                if ((lVol < ((*it)->GetVolume() * thres)) || (lVol * thres > ((*it)->GetVolume())))
5095                        Debug << "warning: " << lVol << " " << (*it)->GetVolume() << endl;
5096        }
5097       
5098        Debug << "exact volume: " << vol << endl;
5099        Debug << "subdivision volume: " << subdivVol << endl;
5100        Debug << "new volume: " << newVol << endl;
5101}
5102
5103
5104void VspBspViewCellsManager::PrepareLoadedViewCells()
5105{
5106        // TODO: do I still need this here?
5107        if (0)
5108                mVspBspTree->RepairViewCellsLeafLists();
5109}
5110
5111
5112
5113/************************************************************************/
5114/*                 VspOspViewCellsManager implementation                */
5115/************************************************************************/
5116
5117
5118VspOspViewCellsManager::VspOspViewCellsManager(ViewCellsTree *vcTree,
5119                                                                                           const string &hierarchyType)
5120: ViewCellsManager(vcTree)
5121{
5122        Environment::GetSingleton()->GetIntValue("Hierarchy.Construction.samples", mInitialSamples);
5123
5124        Environment::GetSingleton()->GetBoolValue("ViewCells.compressObjects", mCompressObjects);
5125
5126        Debug << "compressing objects: " << mCompressObjects << endl;
5127        cout << "compressing objects: " << mCompressObjects << endl;
5128
5129        mHierarchyManager = CreateHierarchyManager(hierarchyType);
5130        mHierarchyManager->SetViewCellsManager(this);
5131        mHierarchyManager->SetViewCellsTree(mViewCellsTree);
5132}
5133
5134
5135VspOspViewCellsManager::VspOspViewCellsManager(ViewCellsTree *vcTree, HierarchyManager *hm)
5136: ViewCellsManager(vcTree), mHierarchyManager(hm)
5137{
5138        Environment::GetSingleton()->GetIntValue("Hierarchy.Construction.samples", mInitialSamples);
5139        Environment::GetSingleton()->GetBoolValue("ViewCells.compressObjects", mCompressObjects);
5140
5141        Debug << "compressing objects: " << mCompressObjects << endl;
5142        cout << "compressing objects: " << mCompressObjects << endl;
5143
5144        mHierarchyManager->SetViewCellsManager(this);
5145        mHierarchyManager->SetViewCellsTree(mViewCellsTree);
5146}
5147
5148
5149Intersectable *
5150VspOspViewCellsManager::GetIntersectable(const VssRay &ray, const bool isTermination) const
5151{
5152#if USE_KD_PVS
5153  return ViewCellsManager::GetIntersectable(ray, isTermination);
5154#else
5155  return mHierarchyManager->GetIntersectable(ray, isTermination);
5156#endif
5157}
5158
5159
5160HierarchyManager *VspOspViewCellsManager::CreateHierarchyManager(const string &hierarchyType)
5161{
5162        HierarchyManager *hierarchyManager;
5163
5164        if (strcmp(hierarchyType.c_str(), "osp") == 0)
5165        {
5166                Debug << "hierarchy manager: osp" << endl;
5167                hierarchyManager = new HierarchyManager(HierarchyManager::KD_BASED_OBJ_SUBDIV);
5168        }
5169        else if (strcmp(hierarchyType.c_str(), "bvh") == 0)
5170        {
5171                Debug << "hierarchy manager: bvh" << endl;
5172                hierarchyManager = new HierarchyManager(HierarchyManager::BV_BASED_OBJ_SUBDIV);
5173        }
5174        else // only view space partition
5175        {
5176                Debug << "hierarchy manager: obj" << endl;
5177                hierarchyManager = new HierarchyManager(HierarchyManager::NO_OBJ_SUBDIV);
5178        }
5179
5180        return hierarchyManager;
5181}
5182
5183
5184VspOspViewCellsManager::~VspOspViewCellsManager()
5185{
5186        DEL_PTR(mHierarchyManager);
5187}
5188
5189
5190float VspOspViewCellsManager::GetProbability(ViewCell *viewCell)
5191{
5192        return GetVolume(viewCell) / mViewSpaceBox.GetVolume();
5193}
5194
5195
5196void VspOspViewCellsManager::CollectViewCells()
5197{
5198        // view cells tree constructed
5199        if (!ViewCellsTreeConstructed())
5200        {
5201                mHierarchyManager->GetVspTree()->CollectViewCells(mViewCells, false);
5202        }
5203        else
5204        {       // we can use the view cells tree hierarchy to get the right set
5205                mViewCellsTree->CollectBestViewCellSet(mViewCells, mNumActiveViewCells);
5206        }
5207}
5208
5209
5210bool VspOspViewCellsManager::ViewCellsConstructed() const
5211{
5212        return mHierarchyManager->GetVspTree()->GetRoot() != NULL;
5213}
5214
5215
5216ViewCell *VspOspViewCellsManager::GenerateViewCell(Mesh *mesh) const
5217{
5218        return new VspViewCell(mesh);
5219}
5220
5221
5222int VspOspViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
5223                                                                                                 const VssRayContainer &rays)
5224{
5225        mMaxPvsSize = (int)(mMaxPvsRatio * (float)objects.size());
5226
5227        // skip rest if view cells were already constructed
5228        if (ViewCellsConstructed())
5229                return 0;
5230
5231        int sampleContributions = 0;
5232        VssRayContainer sampleRays;
5233
5234        int limit = min (mInitialSamples, (int)rays.size());
5235
5236        VssRayContainer constructionRays;
5237        VssRayContainer savedRays;
5238
5239        Debug << "samples used for vsp bsp subdivision: " << mInitialSamples
5240                  << ", actual rays: " << (int)rays.size() << endl;
5241
5242        GetRaySets(rays, mInitialSamples, constructionRays, &savedRays);
5243
5244        Debug << "initial rays used for construction: " << (int)constructionRays.size() << endl;
5245        Debug << "saved rays: " << (int)savedRays.size() << endl;
5246
5247        mHierarchyManager->Construct(constructionRays, objects, &mViewSpaceBox);
5248
5249#if TEST_EVALUATION
5250        VssRayContainer::const_iterator tit, tit_end = constructionRays.end();
5251        for (tit = constructionRays.begin(); tit != tit_end; ++ tit)
5252        {
5253                storedRays.push_back(new VssRay(*(*tit)));
5254        }
5255#endif
5256
5257        /////////////////////////
5258        //-- print satistics for subdivision and view cells
5259
5260        Debug << endl << endl << *mHierarchyManager << endl;
5261
5262        ResetViewCells();
5263        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
5264
5265        //////////////
5266        //-- recast rest of rays
5267       
5268        const long startTime = GetTime();
5269        cout << "Computing remaining ray contributions ... ";
5270
5271        if (SAMPLE_AFTER_SUBDIVISION)
5272                ComputeSampleContributions(savedRays, true, false);
5273
5274        Debug << "finished computing remaining ray contribution in " << TimeDiff(startTime, GetTime()) * 1e-3
5275                  << " secs" << endl;
5276
5277        if (0)
5278        {       // real meshes are constructed at this stage
5279                cout << "finalizing view cells ... ";
5280                FinalizeViewCells(true);
5281                cout << "finished" << endl;
5282        }
5283
5284        return sampleContributions;
5285}
5286
5287
5288int VspOspViewCellsManager::PostProcess(const ObjectContainer &objects,
5289                                                                                const VssRayContainer &rays)
5290{
5291        if (!ViewCellsConstructed())
5292        {
5293                Debug << "post process error: no view cells constructed" << endl;
5294                return 0;
5295        }
5296
5297        // if view cells were already constructed before post processing step
5298        // (e.g., because they were loaded), we are finished
5299        if (mViewCellsFinished)
5300        {
5301                FinalizeViewCells(true);
5302                EvaluateViewCellsStats();
5303
5304                return 0;
5305        }
5306
5307        // check if new view cells turned invalid
5308        int minPvs, maxPvs;
5309
5310        if (0)
5311        {
5312                minPvs = mMinPvsSize;
5313                maxPvs = mMaxPvsSize;
5314        }
5315        else
5316        {
5317                // problem matt: why did I start here from zero?
5318                minPvs = 0;
5319                maxPvs = mMaxPvsSize;
5320        }
5321
5322        Debug << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
5323        cout << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
5324       
5325        SetValidity(minPvs, maxPvs);
5326
5327       
5328        // area is not up to date, has to be recomputed
5329        mTotalAreaValid = false;
5330        VssRayContainer postProcessRays;
5331        GetRaySets(rays, mPostProcessSamples, postProcessRays);
5332
5333        Debug << "post processing using " << (int)postProcessRays.size() << " samples" << endl;
5334
5335
5336        // compute tree by merging the nodes of the spatial hierarchy
5337        ViewCell *root = ConstructSpatialMergeTree(mHierarchyManager->GetVspTree()->GetRoot());
5338        mViewCellsTree->SetRoot(root);
5339
5340        //////////////////////////
5341        //-- update pvs up to the root of the hierarchy
5342
5343        ObjectPvs pvs;
5344        UpdatePvsForEvaluation(root, pvs);
5345
5346
5347        //////////////////////
5348        //-- render simulation after merge + refine
5349
5350        cout << "\nview cells partition render time before compress" << endl << endl;
5351        dynamic_cast<RenderSimulator *>(mRenderer)->RenderScene();
5352        SimulationStatistics ss;
5353        dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
5354        cout << ss << endl;
5355       
5356
5357        mHierarchyManager->CreateUniqueObjectIds();
5358
5359        ///////////
5360        //-- compression
5361
5362        if (0) CompressViewCells();
5363
5364        /////////////
5365        //-- some tasks still to do on the view cells:
5366        //-- Compute meshes from view cell geometry, evaluate volume and / or area
5367
5368        if (1) FinalizeViewCells(true);
5369
5370        return 0;
5371}
5372
5373
5374int VspOspViewCellsManager::GetType() const
5375{
5376        return VSP_OSP;
5377}
5378
5379
5380ViewCell *VspOspViewCellsManager::ConstructSpatialMergeTree(VspNode *root)
5381{
5382        // terminate recursion
5383        if (root->IsLeaf())
5384        {
5385                VspLeaf *leaf = dynamic_cast<VspLeaf *>(root);
5386                leaf->GetViewCell()->SetMergeCost(0.0f);
5387                return leaf->GetViewCell();
5388        }
5389       
5390        VspInterior *interior = dynamic_cast<VspInterior *>(root);
5391        ViewCellInterior *viewCellInterior = new ViewCellInterior();
5392               
5393        // evaluate merge cost for priority traversal
5394        const float mergeCost = -(float)root->mTimeStamp;
5395        viewCellInterior->SetMergeCost(mergeCost);
5396
5397        float volume = 0;
5398       
5399        VspNode *front = interior->GetFront();
5400        VspNode *back = interior->GetBack();
5401
5402        ObjectPvs frontPvs, backPvs;
5403
5404        /////////
5405        //-- recursivly compute child hierarchies
5406
5407        ViewCell *backVc = ConstructSpatialMergeTree(back);
5408        ViewCell *frontVc = ConstructSpatialMergeTree(front);
5409
5410        viewCellInterior->SetupChildLink(backVc);
5411        viewCellInterior->SetupChildLink(frontVc);
5412
5413        volume += backVc->GetVolume();
5414        volume += frontVc->GetVolume();
5415
5416        viewCellInterior->SetVolume(volume);
5417
5418        return viewCellInterior;
5419}
5420
5421
5422bool VspOspViewCellsManager::GetViewPoint(Vector3 &viewPoint) const
5423{
5424        if (!ViewCellsConstructed())
5425                return ViewCellsManager::GetViewPoint(viewPoint);
5426
5427        // TODO: set reasonable limit
5428        const int limit = 20;
5429
5430        for (int i = 0; i < limit; ++ i)
5431        {
5432                viewPoint = mViewSpaceBox.GetRandomPoint();
5433
5434                if (mHierarchyManager->GetVspTree()->ViewPointValid(viewPoint))
5435                {
5436                        return true;
5437                }
5438        }
5439
5440        Debug << "failed to find valid view point, taking " << viewPoint << endl;
5441        return false;
5442}
5443
5444
5445void VspOspViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
5446                                                                                                        ViewCell *vc,
5447                                                                                                        const AxisAlignedBox3 *sceneBox,
5448                                                                                                        const AxisAlignedPlane *clipPlane
5449                                                                                                        ) const
5450{
5451        ViewCellContainer leaves;
5452        mViewCellsTree->CollectLeaves(vc, leaves);
5453        ViewCellContainer::const_iterator it, it_end = leaves.end();
5454
5455        Plane3 plane;
5456        if (clipPlane)
5457        {
5458                // arbitrary plane definition
5459                plane = clipPlane->GetPlane();
5460        }
5461
5462        for (it = leaves.begin(); it != it_end; ++ it)
5463        {
5464                VspViewCell *vspVc = dynamic_cast<VspViewCell *>(*it);
5465                VspLeaf *l = vspVc->mLeaves[0];
5466
5467                const AxisAlignedBox3 box =
5468                        mHierarchyManager->GetVspTree()->GetBoundingBox(vspVc->mLeaves[0]);
5469               
5470                if (sceneBox && !Overlap(*sceneBox, box))
5471                        continue;
5472
5473                if (clipPlane)
5474                {
5475                        if (box.Side(plane) == -1)
5476                        {
5477                                exporter->ExportBox(box);
5478                        }
5479                        else if (box.Side(plane) == 0)
5480                        {
5481                                // intersection
5482                                AxisAlignedBox3 fbox, bbox;
5483                                box.Split(clipPlane->mAxis, clipPlane->mPosition, fbox, bbox);
5484                                exporter->ExportBox(bbox);
5485                        }
5486                }
5487                else
5488                {
5489                        exporter->ExportBox(box);
5490                }
5491        }
5492}
5493
5494
5495bool VspOspViewCellsManager::ViewPointValid(const Vector3 &viewPoint) const
5496{
5497  // $$JB -> implemented in viewcellsmanager (slower, but allows dynamic
5498  // validy update in preprocessor for all managers)
5499  return ViewCellsManager::ViewPointValid(viewPoint);
5500
5501  //    return mViewSpaceBox.IsInside(viewPoint) &&
5502  //               mVspTree->ViewPointValid(viewPoint);
5503}
5504
5505
5506void VspOspViewCellsManager::Visualize(const ObjectContainer &objects,
5507                                                                           const VssRayContainer &sampleRays)
5508{
5509        if (!ViewCellsConstructed())
5510                return;
5511
5512        VssRayContainer visRays;
5513        GetRaySets(sampleRays, mVisualizationSamples, visRays);
5514
5515        ////////////
5516        //-- export final view cells
5517
5518        Exporter *exporter = Exporter::GetExporter("final_view_cells.wrl");
5519
5520        Vector3 scale(0.9f, 0.9f, 0.9f);
5521        //Vector3 scale(1.0f, 1.0f, 1.0f);
5522
5523        if (exporter)
5524        {
5525                if (CLAMP_TO_BOX)
5526                {       
5527                        exporter->mClampToBox = true;   
5528                }
5529
5530                EvaluateViewCellsStats();
5531
5532                const long starttime = GetTime();
5533                cout << "exporting final view cells (after initial construction + post process) ... ";
5534
5535                // matt: hack for clamping scene
5536                AxisAlignedBox3 bbox = mViewSpaceBox;
5537                bbox.Scale(scale);
5538
5539                if (1 && mExportRays)
5540                {       
5541                        exporter->ExportRays(visRays, RgbColor(0, 1, 0));
5542                }
5543
5544                mHierarchyManager->ExportObjectSpaceHierarchy(exporter, objects,
5545                                                                                                          CLAMP_TO_BOX ? &bbox : NULL, false);
5546               
5547                // hack color code (show pvs size)
5548                const int savedColorCode = mColorCode;
5549                mColorCode = 1; // export pvs
5550
5551                //ExportViewCellsForViz(exporter, CLAMP_TO_BOX ? &bbox : NULL, mColorCode, GetClipPlane());
5552                ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
5553
5554                delete exporter;
5555
5556                cout << "finished in " << TimeDiff(starttime, GetTime()) * 1e-3f << " secs" << endl;
5557                mColorCode = savedColorCode;
5558        }
5559
5560        // export final object partition
5561        exporter = Exporter::GetExporter("final_object_partition.wrl");
5562
5563        if (exporter)
5564        {
5565                if (CLAMP_TO_BOX)
5566                {       
5567                        exporter->mClampToBox = true;   
5568                }
5569
5570                const long starttime = GetTime();
5571
5572                // matt: hack for making visualization smaller in size
5573                AxisAlignedBox3 bbox = mHierarchyManager->GetObjectSpaceBox();
5574                bbox.Scale(scale);
5575
5576                cout << "exporting object space hierarchy ... ";
5577                mHierarchyManager->ExportObjectSpaceHierarchy(exporter, objects, CLAMP_TO_BOX ? &bbox : NULL);
5578
5579                delete exporter;
5580                cout << "finished in " << TimeDiff(starttime, GetTime()) * 1e-3f << " secs" << endl;
5581        }
5582       
5583        // visualization of the view cells
5584    if (0)
5585        {       
5586                ExportMergedViewCells(objects);
5587        }
5588
5589        // export some view cells
5590        int leafOut;
5591        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.maxOutput", leafOut);
5592
5593        const bool sortViewCells = false;
5594        const bool exportPvs = true;
5595        const bool exportRays = true;
5596        const int raysOut = 100;
5597
5598        ExportSingleViewCells(objects,
5599                                                  leafOut,
5600                                                  sortViewCells,
5601                                                  exportPvs,
5602                                                  exportRays,
5603                                                  raysOut,
5604                                                  "");
5605}
5606
5607
5608void VspOspViewCellsManager::ExportSingleViewCells(const ObjectContainer &objects,
5609                                                                                                   const int maxViewCells,
5610                                                                                                   const bool sortViewCells,
5611                                                                                                   const bool exportPvs,
5612                                                                                                   const bool exportRays,
5613                                                                                                   const int maxRays,
5614                                                                                                   const string prefix,
5615                                                                                                   VssRayContainer *visRays)
5616{
5617        if (sortViewCells)
5618        {
5619                // sort view cells to visualize the view cells with highest render cost
5620                sort(mViewCells.begin(), mViewCells.end(), ViewCell::LargerRenderCost);
5621        }
5622
5623        ViewCell::NewMail();
5624        const int limit = min(maxViewCells, (int)mViewCells.size());
5625       
5626        cout << "\nExporting " << limit << " single view cells: " << endl;
5627       
5628        for (int i = 0; i < limit; ++ i)
5629        {
5630                cout << "creating output for view cell " << i << " ... ";
5631               
5632                // largest view cell pvs first of random view cell
5633                ViewCell *vc = sortViewCells ?
5634                        mViewCells[i] : mViewCells[(int)RandomValue(0, (float)mViewCells.size() - 1)];
5635               
5636                if (vc->Mailed()) // view cell already processed
5637                        continue;
5638
5639                vc->Mail();
5640
5641                ObjectPvs pvs;
5642                mViewCellsTree->GetPvs(vc, pvs);
5643
5644                char s[64]; sprintf(s, "%sviewcell%04d.wrl", prefix.c_str(), i);
5645                Exporter *exporter = Exporter::GetExporter(s);
5646               
5647                cout << "view cell " << vc->GetId() << ": pvs cost=" << mViewCellsTree->GetPvsCost(vc) << endl;
5648
5649                if (exportPvs)
5650                {
5651                        Material m;
5652
5653                        Intersectable::NewMail();
5654                       
5655                        ObjectPvsIterator pit = pvs.GetIterator();
5656
5657                        // output PVS of view cell
5658                        while (pit.HasMoreEntries())
5659                        {               
5660                                ObjectPvsEntry entry = pit.Next();
5661                               
5662                                Intersectable *intersect = entry.mObject;
5663
5664                                if (!intersect->Mailed())
5665                                {
5666                                        m = RandomMaterial();
5667                                        exporter->SetForcedMaterial(m);
5668
5669                                        exporter->ExportIntersectable(intersect);
5670                                        intersect->Mail();
5671                                }
5672                        }
5673                }
5674
5675                if (exportRays)
5676                {
5677                        ////////////
5678                        //-- export the sample rays
5679
5680                        // output rays stored with the view cells during subdivision
5681                        VssRayContainer vcRays;
5682                        VssRayContainer collectRays;
5683
5684                        // collect intial view cells
5685                        ViewCellContainer leaves;
5686                        mViewCellsTree->CollectLeaves(vc, leaves);
5687
5688                        ViewCellContainer::const_iterator vit, vit_end = leaves.end();
5689
5690                        for (vit = leaves.begin(); vit != vit_end; ++ vit)
5691                        {
5692                                VspLeaf *vcLeaf = dynamic_cast<VspViewCell *>(*vit)->mLeaves[0];
5693                                VssRayContainer::const_iterator rit, rit_end = vcLeaf->mVssRays.end();
5694
5695                                for (rit = vcLeaf->mVssRays.begin(); rit != rit_end; ++ rit)
5696                                {
5697                                        collectRays.push_back(*rit);
5698                                }
5699                        }
5700
5701                        const int raysOut = min((int)collectRays.size(), maxRays);
5702
5703                        VssRayContainer::const_iterator rit, rit_end = collectRays.end();
5704
5705                        for (rit = collectRays.begin(); rit != rit_end; ++ rit)
5706                        {
5707                                const float p = RandomValue(0.0f, (float)collectRays.size());
5708
5709                                if (p < raysOut)
5710                                        vcRays.push_back(*rit);
5711                        }
5712
5713                        exporter->ExportRays(vcRays, RgbColor(1, 1, 1));
5714                }
5715               
5716       
5717                /////////////////
5718                //-- export view cell geometry
5719
5720                exporter->SetWireframe();
5721
5722                Material m;
5723                m.mDiffuseColor = RgbColor(0, 1, 0);
5724                exporter->SetForcedMaterial(m);
5725
5726                ExportViewCellGeometry(exporter, vc, NULL, NULL);
5727                exporter->SetFilled();
5728
5729                DEL_PTR(exporter);
5730                cout << "finished" << endl;
5731        }
5732
5733        cout << endl;
5734}
5735
5736
5737int VspOspViewCellsManager::ComputeBoxIntersections(const AxisAlignedBox3 &box,
5738                                                                                                        ViewCellContainer &viewCells) const
5739{
5740        return mHierarchyManager->GetVspTree()->ComputeBoxIntersections(box, viewCells);
5741}
5742
5743
5744int VspOspViewCellsManager::CastLineSegment(const Vector3 &origin,
5745                                                                                        const Vector3 &termination,
5746                                                                                        ViewCellContainer &viewcells)
5747{
5748        return mHierarchyManager->GetVspTree()->CastLineSegment(origin, termination, viewcells);
5749}
5750
5751
5752bool VspOspViewCellsManager::ExportViewCells(const string filename,
5753                                                                                         const bool exportPvs,
5754                                                                                         const ObjectContainer &objects)
5755{
5756        if (!ViewCellsConstructed() || !ViewCellsTreeConstructed())
5757                return false;
5758
5759        const long starttime = GetTime();
5760        cout << "exporting view cells to xml ... ";
5761       
5762        OUT_STREAM stream(filename.c_str());
5763
5764        // for output we need unique ids for each view cell
5765        CreateUniqueViewCellIds();
5766
5767        stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<endl;
5768        stream << "<VisibilitySolution>" << endl;
5769
5770        // §§ tmp matt: for storage cost
5771        if (0 && exportPvs)
5772        {
5773        ///////////////
5774                //-- export bounding boxes
5775                //-- The bounding boxes are used to identify
5776                //-- the objects in the rendering engine
5777                mHierarchyManager->ExportBoundingBoxes(stream, objects);
5778        }
5779
5780        //////////////////////////
5781        //-- export the view cells and the pvs
5782
5783        const int numViewCells = mCurrentViewCellsStats.viewCells;
5784
5785        stream << "<ViewCells number=\"" << numViewCells << "\" >" << endl;
5786        mViewCellsTree->Export(stream, exportPvs);
5787        stream << "</ViewCells>" << endl;
5788
5789        //////////////////////
5790        //-- export the view space hierarchy
5791       
5792        stream << "<ViewSpaceHierarchy type=\"vsp\""
5793                   << " min=\"" << mViewSpaceBox.Min().x << " " << mViewSpaceBox.Min().y << " " << mViewSpaceBox.Min().z << "\""
5794                   << " max=\"" << mViewSpaceBox.Max().x << " " << mViewSpaceBox.Max().y << " " << mViewSpaceBox.Max().z << "\">" << endl;
5795
5796        mHierarchyManager->GetVspTree()->Export(stream);
5797        stream << "</ViewSpaceHierarchy>" << endl;
5798
5799        ////////////////////// 
5800        //-- export the object space partition
5801       
5802        mHierarchyManager->ExportObjectSpaceHierarchy(stream);
5803       
5804        stream << "</VisibilitySolution>" << endl;
5805        stream.close();
5806       
5807        cout << "finished in " << TimeDiff(starttime, GetTime()) * 1e-3 << " secs" << endl;
5808        return true;
5809}
5810
5811
5812
5813ViewCell *VspOspViewCellsManager::GetViewCell(const Vector3 &point,
5814                                                                                          const bool active) const
5815{
5816        if (!ViewCellsConstructed())
5817                return NULL;
5818
5819        if (!mViewSpaceBox.IsInside(point))
5820                return NULL;
5821
5822        return mHierarchyManager->GetVspTree()->GetViewCell(point, active);
5823}
5824
5825
5826void VspOspViewCellsManager::CreateMesh(ViewCell *vc)
5827{
5828        // matt: TODO
5829        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
5830
5831        ViewCellContainer leaves;
5832        mViewCellsTree->CollectLeaves(vc, leaves);
5833
5834        ViewCellContainer::const_iterator it, it_end = leaves.end();
5835
5836    for (it = leaves.begin(); it != it_end; ++ it)
5837        {
5838                VspLeaf *leaf = dynamic_cast<VspViewCell *>(*it)->mLeaves[0];
5839                const AxisAlignedBox3 box = mHierarchyManager->GetVspTree()->GetBoundingBox(leaf);
5840        IncludeBoxInMesh(box, *mesh);
5841        }
5842
5843        vc->SetMesh(mesh);
5844}
5845
5846
5847int VspOspViewCellsManager::CastBeam(Beam &beam)
5848{
5849        // matt: TODO
5850        return 0;
5851}
5852
5853
5854void VspOspViewCellsManager::Finalize(ViewCell *viewCell, const bool createMesh)
5855{
5856        float area = 0;
5857        float volume = 0;
5858
5859        ViewCellContainer leaves;
5860        mViewCellsTree->CollectLeaves(viewCell, leaves);
5861
5862        ViewCellContainer::const_iterator it, it_end = leaves.end();
5863
5864    for (it = leaves.begin(); it != it_end; ++ it)
5865        {
5866                VspLeaf *leaf = dynamic_cast<VspViewCell *>(*it)->mLeaves[0];
5867               
5868                const AxisAlignedBox3 box = mHierarchyManager->GetVspTree()->GetBoundingBox(leaf);
5869
5870                const float lVol = box.GetVolume();
5871                const float lArea = box.SurfaceArea();
5872
5873                area += lArea;
5874                volume += lVol;
5875
5876        CreateMesh(*it);
5877        }
5878
5879        viewCell->SetVolume(volume);
5880        viewCell->SetArea(area);
5881}
5882
5883
5884void VspOspViewCellsManager::PrepareLoadedViewCells()
5885{
5886        // TODO
5887}
5888
5889
5890static void PrintCompressionStats(HierarchyManager *hm, const int pvsEntries)
5891{
5892        float mem = (float)pvsEntries * ObjectPvs::GetEntrySize();
5893               
5894        float fullmem = mem +
5895                        (hm->GetVspTree()->GetStatistics().Leaves() * 16 +
5896                         hm->mBvHierarchy->GetStatistics().Leaves() * 16) / float(1024 * 1024);
5897
5898        cout << "entries: " << pvsEntries << ", mem=" << mem << ", fullmem=" << fullmem <<endl;
5899        Debug << "entries: " << pvsEntries << ", mem=" << mem << ", fullmem=" << fullmem <<endl;
5900}
5901
5902
5903void VspOspViewCellsManager::CompressViewCells()
5904{
5905        if (!(ViewCellsTreeConstructed() && mCompressViewCells))
5906                return;
5907
5908        ////////////
5909        //-- compression
5910
5911        int pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
5912
5913        cout << "before compression: " << endl;
5914        Debug << "before compression: " << endl;
5915       
5916        PrintCompressionStats(mHierarchyManager, pvsEntries);
5917
5918        if (mCompressObjects)
5919        {
5920                cout << "compressing in the objects: " << endl;
5921                Debug << "compressing in the objects: " << endl;
5922
5923                pvsEntries = mHierarchyManager->CompressObjectSpace();
5924        }
5925        else
5926        {
5927                cout << "compressing in the view space: " << endl;
5928                Debug << "compressing in the view space: " << endl;
5929
5930                mViewCellsTree->SetViewCellsStorage(ViewCellsTree::COMPRESSED);
5931                pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
5932        }
5933
5934        PrintCompressionStats(mHierarchyManager, pvsEntries);
5935}
5936
5937
5938ViewCellsManager *VspOspViewCellsManager::LoadViewCells(const string &filename,
5939                                                                                                                ObjectContainer *objects,
5940                                                                                                                const bool finalizeViewCells,
5941                                                                                                                BoundingBoxConverter *bconverter)
5942                                                                                                 
5943{
5944        ViewCellsManager *vm =
5945                ViewCellsManager::LoadViewCells(filename, objects, finalizeViewCells, bconverter);
5946#if 0
5947        // insert scene objects in tree
5948        mOspTree->InsertObjects(mOspTree->GetRoot(), *objects);
5949#endif
5950        return vm;
5951}
5952
5953
5954void
5955VspOspViewCellsManager::CollectObjects(const AxisAlignedBox3 &box, ObjectContainer &objects)
5956{
5957  mHierarchyManager->CollectObjects(box, objects);
5958}
5959
5960
5961#if 1
5962
5963void VspOspViewCellsManager::EvalViewCellPartition()
5964{
5965        int samplesPerPass;
5966        int numSamples;
5967        int castSamples = 0;
5968        int oldSamples = 0;
5969        int samplesForStats;
5970        char statsPrefix[100];
5971        char suffix[100];
5972        int splitsStepSize;
5973
5974        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesPerPass", samplesPerPass);
5975        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesForStats", samplesForStats);
5976        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samples", numSamples);
5977        Environment::GetSingleton()->GetStringValue("ViewCells.Evaluation.statsPrefix", statsPrefix);
5978        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.stepSize", splitsStepSize);
5979       
5980        Debug << "step size: " << splitsStepSize << endl;
5981        Debug << "view cell evaluation samples per pass: " << samplesPerPass << endl;
5982        Debug << "view cell evaluation samples: " << numSamples << endl;
5983        Debug << "view cell stats prefix: " << statsPrefix << endl;
5984
5985    cout << "reseting pvs ... ";
5986               
5987        // reset pvs and start over from zero
5988        mViewCellsTree->ResetPvs();
5989       
5990        cout << "finished" << endl;
5991    cout << "Evaluating view cell partition ... " << endl;
5992
5993        vector<int> evalStrats;
5994
5995        // mix of sampling strategies
5996        if (1)
5997        {
5998                evalStrats.push_back(SamplingStrategy::OBJECT_BASED_DISTRIBUTION);
5999                //evalStrats.push_back(SamplingStrategy::SPATIAL_BOX_BASED_DISTRIBUTION);
6000                evalStrats.push_back(SamplingStrategy::REVERSE_VIEWSPACE_BORDER_BASED_DISTRIBUTION);
6001                evalStrats.push_back(SamplingStrategy::REVERSE_OBJECT_BASED_DISTRIBUTION);
6002        }
6003        else
6004        {
6005                //evalStrats.push_back(SamplingStrategy::VIEWSPACE_BORDER_BASED_DISTRIBUTION);
6006                evalStrats.push_back(SamplingStrategy::OBJECT_BASED_DISTRIBUTION);
6007                evalStrats.push_back(SamplingStrategy::REVERSE_VIEWSPACE_BORDER_BASED_DISTRIBUTION);
6008                //evalStrats.push_back(SamplingStrategy::REVERSE_VIEWSPACE_BORDER_BASED_DISTRIBUTION);
6009                //evalStrats.push_back(SamplingStrategy::REVERSE_VIEWSPACE_BORDER_BASED_DISTRIBUTION);
6010        }
6011       
6012    Debug << "casting eval strategies: ";
6013        for (int i = 0; i < (int)evalStrats.size(); ++ i)
6014                Debug << evalStrats[i] << " ";
6015        Debug << endl;
6016
6017        cout << "casting eval strategies: ";
6018        for (int i = 0; i < (int)evalStrats.size(); ++ i)
6019                cout << evalStrats[i] << " ";
6020        cout << endl;
6021
6022        while (castSamples < numSamples)
6023        {               
6024                ///////////////
6025                //-- we have to use uniform sampling strategy for construction rays
6026
6027                VssRayContainer evaluationSamples;
6028                const int samplingType = mEvaluationSamplingType;
6029
6030                long startTime = GetTime();
6031
6032                cout << "casting " << samplesPerPass << " samples ... ";
6033                Debug << "casting " << samplesPerPass << " samples ... ";
6034       
6035                CastPassSamples(samplesPerPass, evalStrats, evaluationSamples);
6036                //CastPassSamples(samplesPerPass, mStrategies, evaluationSamples);
6037               
6038                castSamples += samplesPerPass;
6039
6040                Real timeDiff = TimeDiff(startTime, GetTime());
6041               
6042                cout << "finished in " << timeDiff * 1e-3f << " secs" << endl;
6043                cout << "computing sample contributions of " << (int)evaluationSamples.size()  << " samples ... ";
6044               
6045                Debug << "finished in " << timeDiff * 1e-3f << " secs" << endl;
6046                Debug << "computing sample contributions of " << (int)evaluationSamples.size()  << " samples ... ";
6047
6048                startTime = GetTime();
6049
6050                ComputeSampleContributions(evaluationSamples, true, false);
6051
6052                timeDiff = TimeDiff(startTime, GetTime());
6053                cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
6054                Debug << "finished in " << timeDiff * 1e-3 << " secs" << endl;
6055
6056                if ((castSamples >= samplesForStats + oldSamples) ||
6057                        (castSamples >= numSamples))
6058                {
6059                        oldSamples += samplesForStats;
6060
6061                        ///////////
6062                        //-- output stats
6063
6064                        sprintf(suffix, "-%09d-eval.log", castSamples);
6065                        const string filename = string(statsPrefix) + string(suffix);
6066
6067                        startTime = GetTime();
6068                       
6069                        cout << "compute new statistics ... " << endl;
6070
6071                        ofstream ofstr(filename.c_str());
6072                        mHierarchyManager->EvaluateSubdivision2(ofstr, splitsStepSize, false);
6073
6074                        timeDiff = TimeDiff(startTime, GetTime());
6075                        cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
6076                        cout << "*************************************" << endl;
6077
6078                        Debug << "statistics computed in " << timeDiff * 1e-3 << " secs" << endl;
6079
6080#if 0
6081                        //////////////
6082                        // filtered stats
6083
6084                        sprintf(suffix, "-%09d-eval-filter.log", castSamples);
6085                        const string filename2 = string(statsPrefix) + string(suffix);
6086
6087                        startTime = GetTime();
6088                       
6089                        cout << "compute new statistics for filtered pvs ... " << endl;
6090
6091                        ofstream ofstr2(filename2.c_str());
6092                        mHierarchyManager->EvaluateSubdivision2(ofstr2, splitsStepSize, true);
6093
6094                        timeDiff = TimeDiff(startTime, GetTime());
6095                        cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
6096                        cout << "*************************************" << endl;
6097                        Debug << "filtered statistics computed in " << timeDiff * 1e-3 << " secs" << endl;
6098#endif
6099
6100                        // only for debugging purpose
6101                        if (0)
6102                        {
6103                                ViewCellContainer viewCells;
6104                                mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), viewCells);
6105
6106                                ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
6107                                int pvsSize = 0;
6108
6109                                for (vit = viewCells.begin(); vit != vit_end; ++ vit)
6110                                {
6111                                        pvsSize += (*vit)->GetPvs().GetSize();
6112                                }
6113
6114                                cout << "debug entries: " << pvsSize << ", memcost: "
6115                                         << (float)pvsSize * ObjectPvs::GetEntrySize() << endl;
6116                        }
6117                }
6118
6119                disposeRays(evaluationSamples, NULL);
6120        }
6121       
6122}
6123#endif
6124
6125
6126
6127}
Note: See TracBrowser for help on using the repository browser.