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

Revision 1576, 141.8 KB checked in by mattausch, 18 years ago (diff)

added measurement for pvs entries size decrease during subdivision

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