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

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