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

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