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

Revision 1486, 140.0 KB checked in by mattausch, 18 years ago (diff)

worked on guided visibility sampling

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