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

Revision 1758, 154.1 KB checked in by mattausch, 18 years ago (diff)

bvhnode is now derived from Intersectable

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