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

Revision 1616, 143.0 KB checked in by mattausch, 18 years ago (diff)

some shit happen

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