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

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