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

Revision 1563, 139.9 KB checked in by mattausch, 18 years ago (diff)

fixed bug with view space box

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