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

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