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

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