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

Revision 1586, 142.2 KB checked in by mattausch, 18 years ago (diff)

resolved bug for object space distribution using triangles
fixed biasing bug for mesh::GetRandomSurfacePoint? method and
GetRandomVisibleSurfacePoint?.

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