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

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