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

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