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

Revision 1760, 154.9 KB checked in by mattausch, 18 years ago (diff)
Line 
1#include "ViewCellsManager.h"
2#include "RenderSimulator.h"
3#include "Mesh.h"
4#include "Triangle3.h"
5#include "ViewCell.h"
6#include "Environment.h"
7#include "X3dParser.h"
8#include "ViewCellBsp.h"
9#include "KdTree.h"
10#include "HierarchyManager.h"
11#include "Exporter.h"
12#include "VspBspTree.h"
13#include "ViewCellsParser.h"
14#include "Beam.h"
15#include "VssPreprocessor.h"
16#include "RssPreprocessor.h"
17#include "BoundingBoxConverter.h"
18#include "GlRenderer.h"
19#include "ResourceManager.h"
20#include "IntersectableWrapper.h"
21#include "VspTree.h"
22#include "OspTree.h"
23#include "BvHierarchy.h"
24#include "SamplingStrategy.h"
25#include "SceneGraph.h"
26
27
28#define ABS_CONTRIBUTION_WEIGHT 1.0f
29
30// warning: Should not count origin object for sampling because it disturbs heuristics
31#define SAMPLE_ORIGIN_OBJECTS 0  // matt temp
32
33// $$JB HACK
34#define USE_KD_PVS 0
35#define KD_PVS_AREA (5*1e-4f)
36
37
38
39namespace GtpVisibilityPreprocessor {
40
41
42// HACK
43const static bool SAMPLE_AFTER_SUBDIVISION = true;
44const static bool CLAMP_TO_BOX = false;
45//const static bool CLAMP_TO_BOX = true;
46
47
48int ViewCellsManager::sRenderCostEvaluationType = 0;
49
50
51template <typename T> class myless
52{
53public:
54        //bool operator() (HierarchyNode *v1, HierarchyNode *v2) const
55        bool operator() (T v1, T v2) const
56        {
57                return (v1->GetMergeCost() < v2->GetMergeCost());
58        }
59};
60
61
62ViewCellsManager::ViewCellsManager(ViewCellsTree *viewCellsTree):
63mRenderer(NULL),
64mInitialSamples(0),
65mConstructionSamples(0),
66mPostProcessSamples(0),
67mVisualizationSamples(0),
68mTotalAreaValid(false),
69mTotalArea(0.0f),
70mViewCellsFinished(false),
71mMaxPvsSize(9999999),
72mMinPvsSize(0),
73mMaxPvsRatio(1.0),
74mViewCellPvsIsUpdated(false),
75mPreprocessor(NULL),
76mViewCellsTree(viewCellsTree),
77mUsePredefinedViewCells(false)
78{
79        mViewSpaceBox.Initialize();
80        ParseEnvironment();
81
82        mViewCellsTree->SetViewCellsManager(this);
83}
84
85
86void ViewCellsManager::ParseEnvironment()
87{
88        // visualization stuff
89        Environment::GetSingleton()->GetBoolValue("ViewCells.Visualization.exportRays", mExportRays);
90        Environment::GetSingleton()->GetBoolValue("ViewCells.Visualization.exportGeometry", mExportGeometry);
91        Environment::GetSingleton()->GetFloatValue("ViewCells.maxPvsRatio", mMaxPvsRatio);
92       
93        Environment::GetSingleton()->GetBoolValue("ViewCells.processOnlyValidViewCells", mOnlyValidViewCells);
94
95        Environment::GetSingleton()->GetIntValue("ViewCells.Construction.samples", mConstructionSamples);
96        Environment::GetSingleton()->GetIntValue("ViewCells.PostProcess.samples", mPostProcessSamples);
97        Environment::GetSingleton()->GetBoolValue("ViewCells.PostProcess.useRaysForMerge", mUseRaysForMerge);
98
99        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.samples", mVisualizationSamples);
100
101        Environment::GetSingleton()->GetIntValue("ViewCells.Construction.samplesPerPass", mSamplesPerPass);
102        Environment::GetSingleton()->GetBoolValue("ViewCells.exportToFile", mExportViewCells);
103       
104        Environment::GetSingleton()->GetIntValue("ViewCells.active", mNumActiveViewCells);
105        Environment::GetSingleton()->GetBoolValue("ViewCells.PostProcess.compress", mCompressViewCells);
106        Environment::GetSingleton()->GetBoolValue("ViewCells.Visualization.useClipPlane", mUseClipPlaneForViz);
107        Environment::GetSingleton()->GetBoolValue("ViewCells.PostProcess.merge", mMergeViewCells);
108        Environment::GetSingleton()->GetBoolValue("ViewCells.evaluateViewCells", mEvaluateViewCells);
109        Environment::GetSingleton()->GetBoolValue("ViewCells.showVisualization", mShowVisualization);
110        Environment::GetSingleton()->GetIntValue("ViewCells.Filter.maxSize", mMaxFilterSize);
111        Environment::GetSingleton()->GetFloatValue("ViewCells.Filter.width", mFilterWidth);
112        Environment::GetSingleton()->GetIntValue("ViewCells.renderCostEvaluationType", sRenderCostEvaluationType);
113
114        Environment::GetSingleton()->GetBoolValue("ViewCells.exportBboxesForPvs", mExportBboxesForPvs);
115        Environment::GetSingleton()->GetBoolValue("ViewCells.exportPvs", mExportPvs);
116       
117        char buf[100];
118        Environment::GetSingleton()->GetStringValue("ViewCells.samplingType", buf);
119
120       
121        /*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, mColorCode, 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        if (0)
537        {
538                ///////////////
539                //-- Get stats after the additional sampling step
540                //-- and before the bottom-up merge step
541
542                EvaluateViewCellsStats();
543                Debug << "\noriginal view cell partition before post process:\n"
544                          << mCurrentViewCellsStats << endl;
545       
546                mRenderer->RenderScene();
547                SimulationStatistics ss;
548                dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
549
550                Debug << ss << endl;
551        }
552
553        ////////////////////
554        //-- post processing of the initial construction
555        //-- We can bottom-up merge the view cells in this step
556        //-- We can additionally cast some post processing sample rays.
557        //-- These rays can be used to store the view cells with the rays
558
559        VssRayContainer postProcessSamples;
560        cout << "casting " << mPostProcessSamples << " post processing samples ... ";
561       
562        CastPassSamples(mPostProcessSamples, mSamplingType, postProcessSamples);
563
564        cout << "finished" << endl;
565        cout << "starting post processing and visualization" << endl;
566
567        // store view cells with rays for post processing?
568        const bool storeViewCells = true;
569
570        if (SAMPLE_AFTER_SUBDIVISION)
571                ComputeSampleContributions(postProcessSamples, true, storeViewCells);
572
573        PostProcess(preprocessor->mObjects, postProcessSamples);
574
575        const float secs = TimeDiff(startTime, GetTime()) * 1e-3f;
576        cout << "post processing (=merge) finished in " << secs << " secs" << endl;
577
578        Debug << "post processing time: " << secs << endl;
579        disposeRays(postProcessSamples, outRays);
580
581               
582        // write view cells to disc
583        if (mExportViewCells)
584        {
585                char filename[100];
586                Environment::GetSingleton()->GetStringValue("ViewCells.filename", filename);
587                ExportViewCells(filename, mExportPvs, mPreprocessor->mObjects);
588        }
589
590        ////////////////
591        //-- Evaluation of the resulting view cell partition.
592        //-- We cast a number of new samples and measure the render cost
593
594        if (mEvaluateViewCells)
595        {
596                EvalViewCellPartition();
597        }
598       
599        /////////////////
600        //-- Finally, we do some visualization
601
602        if (mShowVisualization)
603        {
604                ///////////////
605                //-- visualization rays, e.g., to show some samples in the scene
606               
607                VssRayContainer visSamples;
608                int numSamples = CastPassSamples(mVisualizationSamples,
609                                                                                 mSamplingType,
610                                                                                 visSamples);
611
612                if (SAMPLE_AFTER_SUBDIVISION)
613                        ComputeSampleContributions(visSamples, true, storeViewCells);
614
615                // various visualizations
616                Visualize(preprocessor->mObjects, visSamples);
617
618                disposeRays(visSamples, outRays);
619        }
620
621        // recalculate view cells
622        EvaluateViewCellsStats();
623
624        return numSamples;
625}
626
627
628AxisAlignedPlane *ViewCellsManager::GetClipPlane()
629{
630        return mUseClipPlaneForViz ? &mClipPlaneForViz : NULL;
631}
632
633
634void ViewCellsManager::EvalViewCellHistogram(const string filename,
635                                                                                         const int nViewCells)
636{
637        std::ofstream outstream;
638        outstream.open(filename.c_str());
639
640        ViewCellContainer viewCells;
641        mViewCellsTree->CollectBestViewCellSet(viewCells, nViewCells);
642
643        float maxRenderCost, minRenderCost;
644
645        // sort by render cost
646        sort(viewCells.begin(), viewCells.end(), ViewCell::SmallerRenderCost);
647
648        minRenderCost = viewCells.front()->GetRenderCost();
649        maxRenderCost = viewCells.back()->GetRenderCost();
650
651        Debug << "histogram min rc: " << minRenderCost << " max rc: " << maxRenderCost << endl;
652
653    int histoIntervals;
654        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.intervals", histoIntervals);
655        const int intervals = min(histoIntervals, (int)viewCells.size());
656
657        int histoMaxVal;
658        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.maxValue", histoMaxVal);
659        maxRenderCost = max((float)histoMaxVal, maxRenderCost);
660
661       
662        const float range = maxRenderCost - minRenderCost;
663        const float stepSize = range / (float)intervals;
664
665        float currentRenderCost = minRenderCost;//(int)ceil(minRenderCost);
666
667        const float totalRenderCost = mViewCellsTree->GetRoot()->GetRenderCost();
668        const float totalVol = GetViewSpaceBox().GetVolume();
669        //const float totalVol = mViewCellsTree->GetRoot()->GetVolume();
670
671        int j = 0;
672        int i = 0;
673       
674        ViewCellContainer::const_iterator it = viewCells.begin(), it_end = viewCells.end();             
675
676        // count for integral
677        float volSum = 0;
678        int smallerCostSum = 0;
679       
680        // note can skip computations for view cells already evaluated and delete them from vector ...
681    while (1)
682        {
683                // count for histogram value
684                float volDif = 0;
685                int smallerCostDif = 0;
686
687                while ((i < (int)viewCells.size()) && (viewCells[i]->GetRenderCost() < currentRenderCost))
688                {
689                        volSum += viewCells[i]->GetVolume();
690                        volDif += viewCells[i]->GetVolume();
691
692                        ++ i;
693                        ++ smallerCostSum;
694                        ++ smallerCostDif;
695                }
696               
697                if ((i >= (int)viewCells.size()) || (currentRenderCost >= maxRenderCost))
698                        break;
699               
700                const float rcRatio = currentRenderCost / maxRenderCost;
701                const float volRatioSum = volSum / totalVol;
702                const float volRatioDif = volDif / totalVol;
703
704                outstream << "#Pass\n" << j ++ << endl;
705                outstream << "#RenderCostRatio\n" << rcRatio << endl;
706                outstream << "#WeightedCost\n" << currentRenderCost / totalVol << endl;
707                outstream << "#ViewCellsDif\n" << smallerCostDif << endl;
708                outstream << "#ViewCellsSum\n" << smallerCostSum << endl;       
709                outstream << "#VolumeDif\n" << volRatioDif << endl << endl;
710                outstream << "#VolumeSum\n" << volRatioSum << endl << endl;
711
712                // increase current render cost
713                currentRenderCost += stepSize;
714        }
715
716        outstream.close();
717}
718
719
720
721ViewCellsManager *ViewCellsManager::LoadViewCells(const string &filename,
722                                                                                                  ObjectContainer *objects,
723                                                                                                  bool finalizeViewCells,
724                                                                                                  BoundingBoxConverter *bconverter)
725                                                                                                 
726{
727        ViewCellsParser parser;
728        ViewCellsManager *vm = NULL;
729
730        const long startTime = GetTime();
731        bool success = parser.ParseViewCellsFile(filename, &vm, objects, bconverter);
732
733        cout<<"viewcells parsed "<<endl<<flush;
734       
735        if (success)
736        {
737                //vm->ResetViewCells();
738                //hack
739                vm->mViewCells.clear();
740                ViewCellContainer leaves;
741                vm->mViewCellsTree->CollectLeaves(vm->mViewCellsTree->GetRoot(), leaves);
742
743                ViewCellContainer::const_iterator it, it_end = leaves.end();
744
745                for (it = leaves.begin(); it != it_end; ++ it)
746                {
747                        vm->mViewCells.push_back(*it);
748                }
749                vm->mViewCellsFinished = true;
750                vm->mMaxPvsSize = (int)objects->size();
751
752                if (finalizeViewCells)
753                {
754                        // create the meshes and compute volumes
755                        vm->FinalizeViewCells(true);
756                        // vm->mViewCellsTree->AssignRandomColors();
757                }
758
759                Debug << (int)vm->mViewCells.size() << " view cells loaded in "
760                          << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
761        }
762        else
763        {
764                Debug << "Error: loading view cells failed!" << endl;
765                DEL_PTR(vm);
766        }
767
768        return vm;
769}
770
771
772bool VspBspViewCellsManager::ExportViewCells(const string filename,
773                                                                                         const bool exportPvs,
774                                                                                         const ObjectContainer &objects)
775{
776        if (!ViewCellsConstructed() || !ViewCellsTreeConstructed())
777        {
778                return false;
779        }
780
781        cout << "exporting view cells to xml ... ";
782
783        OUT_STREAM stream(filename.c_str());
784
785        // for output we need unique ids for each view cell
786        CreateUniqueViewCellIds();
787
788        stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<endl;
789        stream << "<VisibilitySolution>" << endl;
790
791        if (exportPvs)
792        {
793                //-- export bounding boxes
794                stream << "<BoundingBoxes>" << endl;
795#if USE_KD_PVS
796        KdIntersectableMap::const_iterator kit, kit_end = GetPreprocessor()->mKdTree->mKdIntersectables.end();
797
798                int id = 0;
799                for (kit = GetPreprocessor()->mKdTree->mKdIntersectables.begin(); kit != kit_end; ++ kit, ++ id)
800                {
801                        Intersectable *obj = (*kit).second;
802                        const AxisAlignedBox3 box = obj->GetBox();
803               
804                        obj->SetId(id);
805
806                        stream << "<BoundingBox" << " id=\"" << id << "\""
807                                   << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
808                                   << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\" />" << endl;
809                }
810#else
811        ObjectContainer::const_iterator oit, oit_end = objects.end();
812
813                for (oit = objects.begin(); oit != oit_end; ++ oit)
814                {
815                        const AxisAlignedBox3 box = (*oit)->GetBox();
816
817                        ////////////
818                        //-- the bounding boxes
819                        stream << "<BoundingBox" << " id=\"" << (*oit)->GetId() << "\""
820                                   << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
821                                   << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\" />" << endl;
822                }
823#endif
824                stream << "</BoundingBoxes>" << endl;
825        }
826
827       
828        /////////////
829        //-- export the view cells and the pvs
830
831        const int numViewCells = mCurrentViewCellsStats.viewCells;
832        stream << "<ViewCells number=\"" << numViewCells << "\" >" << endl;
833
834        mViewCellsTree->Export(stream, exportPvs);
835
836        stream << "</ViewCells>" << endl;
837
838
839        //////////
840        //-- export the view space hierarchy
841       
842        stream << "<ViewSpaceHierarchy type=\"bsp\""
843                   << " min=\"" << mViewSpaceBox.Min().x << " " << mViewSpaceBox.Min().y << " " << mViewSpaceBox.Min().z << "\""
844                   << " max=\"" << mViewSpaceBox.Max().x << " " << mViewSpaceBox.Max().y << " " << mViewSpaceBox.Max().z << "\">" << endl;
845
846        mVspBspTree->Export(stream);
847        stream << "</ViewSpaceHierarchy>" << endl;
848
849        stream << "</VisibilitySolution>" << endl;
850
851        stream.close();
852        cout << "finished" << endl;
853
854        return true;
855}
856
857
858void ViewCellsManager::EvalViewCellHistogramForPvsSize(const string filename,
859                                                                                                           const int nViewCells)
860{
861        std::ofstream outstream;
862        outstream.open(filename.c_str());
863
864        ViewCellContainer viewCells;
865        mViewCellsTree->CollectBestViewCellSet(viewCells, nViewCells);
866
867        float maxPvs, maxVal, minVal;
868
869        // sort by pvs size
870        sort(viewCells.begin(), viewCells.end(), ViewCell::SmallerPvs);
871
872        maxPvs = mViewCellsTree->GetPvsCost(viewCells.back());
873        minVal = 0;
874
875        // hack: normalize pvs size
876        int histoMaxVal;
877        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.maxValue", histoMaxVal);
878        maxVal = max((float)histoMaxVal, maxPvs);
879               
880        Debug << "histogram minpvssize: " << minVal << " maxpvssize: " << maxVal
881                << " real maxpvs " << maxPvs << endl;
882
883        int histoIntervals;
884        Environment::GetSingleton()->GetIntValue("Preprocessor.histogram.intervals", histoIntervals);
885        const int intervals = min(histoIntervals, (int)viewCells.size());
886
887        const float range = maxVal - minVal;
888        int stepSize = (int)(range / intervals);
889
890        // set step size to avoid endless loop
891        if (!stepSize) stepSize = 1;
892       
893        Debug << "stepsize: " << stepSize << endl;
894       
895        const float totalRenderCost = mViewCellsTree->GetRoot()->GetRenderCost();
896        const float totalVol = GetViewSpaceBox().GetVolume();
897
898        float currentPvs = minVal;
899       
900        int i = 0;
901        int j = 0;
902        float volSum = 0;
903        int smallerSum = 0;
904
905        ViewCellContainer::const_iterator it = viewCells.begin(), it_end = viewCells.end();             
906       
907        for (int j = 0; j < intervals; ++ j)
908        {
909                float volDif = 0;
910                int smallerDif = 0;
911
912                while ((i < (int)viewCells.size()) &&
913                           (mViewCellsTree->GetPvsCost(viewCells[i]) < currentPvs))
914                {
915                        volDif += viewCells[i]->GetVolume();
916                        volSum += viewCells[i]->GetVolume();
917
918                        ++ i;
919                        ++ smallerDif;
920                        ++ smallerSum;
921                }
922               
923                if (0 && (i < (int)viewCells.size()))
924                        Debug << "new pvs cost increase: " << mViewCellsTree->GetPvsCost(viewCells[i])
925                        << " " << currentPvs << endl;
926       
927                const float volRatioDif = volDif / totalVol;
928                const float volRatioSum = volSum / totalVol;
929
930                outstream << "#Pass\n" << j << endl;
931                outstream << "#Pvs\n" << currentPvs << endl;
932                outstream << "#ViewCellsDif\n" << smallerDif << endl;
933                outstream << "#ViewCellsSum\n" << smallerSum << endl;   
934                outstream << "#VolumeDif\n" << volRatioDif << endl << endl;
935                outstream << "#VolumeSum\n" << volRatioSum << endl << endl;
936       
937                //-- increase current pvs size to define next interval
938                currentPvs += stepSize;
939        }
940
941        outstream.close();
942}
943
944
945bool ViewCellsManager::GetExportPvs() const
946{
947        return mExportPvs;
948}
949
950
951bool ViewCellsManager::AddSampleToPvs(Intersectable *obj,
952                                                                          const Vector3 &hitPoint,
953                                                                          ViewCell *vc,
954                                                                          const float pdf,
955                                                                          float &contribution) const
956{
957        if (!obj) return false;
958
959        // potentially visible objects
960        return vc->AddPvsSample(obj, pdf, contribution);
961}
962
963
964void ViewCellsManager::ResetPvs()
965{
966        if (ViewCellsTreeConstructed())
967        {
968                mViewCellsTree->ResetPvs();
969        }
970        else
971        {
972                cout << "view cells tree not constructed" << endl;
973        }
974}
975
976
977void ViewCellsManager::ExportStats(const string &fileName)
978{
979        mViewCellsTree->ExportStats(fileName);
980}
981
982
983void ViewCellsManager::EvalViewCellPartition()
984{
985        int samplesPerPass;
986        int numSamples;
987        int castSamples = 0;
988        char str[64];
989        int oldSamples = 0;
990
991        int samplesForStats;
992
993        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesPerPass", samplesPerPass);
994        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesForStats", samplesForStats);
995        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samples", numSamples);
996
997        char statsPrefix[100];
998        Environment::GetSingleton()->GetStringValue("ViewCells.Evaluation.statsPrefix", statsPrefix);
999
1000        Debug << "view cell evaluation samples per pass: " << samplesPerPass << endl;
1001        Debug << "view cell evaluation samples: " << numSamples << endl;
1002        Debug << "view cell stats prefix: " << statsPrefix << endl;
1003
1004        // should directional sampling be used?
1005        bool dirSamples =
1006                (mEvaluationSamplingType == SamplingStrategy::DIRECTION_BASED_DISTRIBUTION);
1007
1008        cout << "reseting pvs ... ";
1009               
1010        const bool startFromZero = true;
1011
1012        // reset pvs and start over from zero
1013        if (startFromZero)
1014        {
1015                mViewCellsTree->ResetPvs();
1016        }
1017        else // start from current sampless
1018        {
1019                // statistics before casting more samples
1020                cout << "compute new statistics ... ";
1021                sprintf(str, "-%09d-eval.log", castSamples);
1022                string fName = string(statsPrefix) + string(str);
1023
1024                mViewCellsTree->ExportStats(fName);
1025                cout << "finished" << endl;
1026        }
1027
1028        cout << "finished" << endl;
1029    cout << "Evaluating view cell partition ... " << endl;
1030
1031        while (castSamples < numSamples)
1032        {               
1033                ///////////////
1034                //-- we have to use uniform sampling strategy for construction rays
1035
1036                VssRayContainer evaluationSamples;
1037                const int samplingType = mEvaluationSamplingType;
1038
1039                long startTime = GetTime();
1040
1041                cout << "casting " << samplesPerPass << " samples ... ";
1042                Debug << "casting " << samplesPerPass << " samples ... ";
1043
1044                CastPassSamples(samplesPerPass, samplingType, evaluationSamples);
1045               
1046                castSamples += samplesPerPass;
1047
1048                Real timeDiff = TimeDiff(startTime, GetTime());
1049               
1050                cout << "finished in " << timeDiff * 1e-3f << " secs" << endl;
1051                cout << "computing sample contributions of " << (int)evaluationSamples.size()  << " samples ... ";
1052               
1053                Debug << "finished in " << timeDiff * 1e-3f << " secs" << endl;
1054                Debug << "computing sample contributions of " << (int)evaluationSamples.size()  << " samples ... ";
1055
1056                startTime = GetTime();
1057
1058                ComputeSampleContributions(evaluationSamples, true, false);
1059
1060                timeDiff = TimeDiff(startTime, GetTime());
1061                cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
1062                Debug << "finished in " << timeDiff * 1e-3 << " secs" << endl;
1063
1064                if ((castSamples >= samplesForStats + oldSamples) || (castSamples >= numSamples))
1065                {
1066                        oldSamples += samplesForStats;
1067
1068                        ///////////
1069                        //-- output stats
1070
1071                        sprintf(str, "-%09d-eval.log", castSamples);
1072                        string fileName = string(statsPrefix) + string(str);
1073
1074                        ///////////////
1075                        //-- propagate pvs or pvs size information
1076
1077                        startTime = GetTime();
1078                        ObjectPvs pvs;
1079
1080                        cout << "updating pvs for evaluation ... " << endl;
1081
1082                        UpdatePvsForEvaluation(mViewCellsTree->GetRoot(), pvs);
1083
1084                        timeDiff = TimeDiff(startTime, GetTime());
1085                        cout << "finished updating the pvs in " << timeDiff * 1e-3 << " secs" << endl;
1086                        Debug << "pvs evaluated in " << timeDiff * 1e-3 << " secs" << endl;
1087               
1088                        startTime = GetTime();
1089                        cout << "compute new statistics ... " << endl;
1090
1091                        ExportStats(fileName);
1092
1093                        timeDiff = TimeDiff(startTime, GetTime());
1094                        cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
1095                        Debug << "statistis computed in " << timeDiff * 1e-3 << " secs" << endl;
1096                }
1097
1098                disposeRays(evaluationSamples, NULL);
1099        }
1100       
1101
1102        ////////////
1103        //-- histogram
1104
1105        const int numLeaves = mViewCellsTree->GetNumInitialViewCells(mViewCellsTree->GetRoot());
1106        bool useHisto;
1107        int histoStepSize;
1108
1109        Environment::GetSingleton()->GetBoolValue("ViewCells.Evaluation.histogram", useHisto);
1110        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.histoStepSize", histoStepSize);
1111
1112        if (useHisto)
1113        {
1114                // evaluate view cells in a histogram           
1115                char s[64];
1116
1117                for (int pass = histoStepSize; pass <= numLeaves; pass += histoStepSize)
1118                {
1119                        string filename;
1120
1121                        cout << "computing histogram for " << pass << " view cells" << endl;
1122#if 0
1123                        //-- evaluate histogram for render cost
1124                        sprintf(s, "-%09d-histo.log", pass);
1125                        filename = string(statsPrefix) + string(s);
1126
1127                        EvalViewCellHistogram(filename, pass);
1128
1129#endif
1130                        //////////////////////////////////////////
1131            //-- evaluate histogram for pvs size
1132
1133                        cout << "computing pvs histogram for " << pass << " view cells" << endl;
1134
1135                        sprintf(s, "-%09d-histo-pvs.log", pass);
1136                        filename = string(statsPrefix) + string(s);
1137
1138                        EvalViewCellHistogramForPvsSize(filename, pass);
1139                }
1140        }
1141}
1142
1143
1144inline float EvalMergeCost(ViewCell *root, ViewCell *candidate)
1145{
1146        return root->GetPvs().GetPvsHomogenity(candidate->GetPvs());
1147}
1148
1149
1150/// Returns index of the best view cells of the neighborhood
1151static int GetBestViewCellIdx(ViewCell *root, const ViewCellContainer &neighborhood)
1152{
1153        int bestViewCellIdx = 0;
1154
1155        float mergeCost = Limits::Infinity;
1156        int i = 0;
1157
1158        ViewCellContainer::const_iterator vit, vit_end = neighborhood.end();
1159
1160        for (vit = neighborhood.begin(); vit != vit_end; ++ vit, ++ i)
1161        {
1162                const float mc = EvalMergeCost(root, *vit);
1163               
1164                if (mc < mergeCost)
1165                {
1166                        mergeCost = mc;
1167                        bestViewCellIdx = i;
1168                }
1169        }
1170
1171        return bestViewCellIdx;
1172}
1173
1174
1175void ViewCellsManager::SetMaxFilterSize(const int size)
1176{
1177        mMaxFilterSize = size;
1178}
1179
1180
1181float ViewCellsManager::EvalRenderCost(Intersectable *obj) //const
1182{
1183        switch (sRenderCostEvaluationType)
1184        {
1185        case PER_OBJECT:
1186                return 1.0f;
1187       
1188        case PER_TRIANGLE:
1189                {
1190                        return (float)obj->NumberOfFaces();
1191                }
1192        default:
1193                cout << "default" << endl;
1194                return 1.0f;
1195        }
1196
1197        // should not come here
1198        return 0.0f;
1199}
1200
1201
1202ViewCell *ViewCellsManager::ConstructLocalMergeTree(ViewCell *currentViewCell,
1203                                                                                                        const ViewCellContainer &viewCells)
1204{
1205        ViewCell *root = currentViewCell;
1206        ViewCellContainer neighborhood = viewCells;
1207
1208        ViewCellContainer::const_iterator it, it_end = neighborhood.end();
1209
1210        const int n = min(mMaxFilterSize, (int)neighborhood.size());
1211       
1212        /////////////////
1213        //-- use priority queue to merge leaf pairs
1214       
1215        for (int nMergedViewCells = 0; nMergedViewCells < n; ++ nMergedViewCells)
1216        {
1217                const int bestViewCellIdx = GetBestViewCellIdx(root, neighborhood);
1218               
1219                ViewCell *bestViewCell = neighborhood[bestViewCellIdx];
1220       
1221                // remove from vector
1222                swap(neighborhood[bestViewCellIdx], neighborhood.back());
1223                neighborhood.pop_back();
1224       
1225                if (!bestViewCell || !root)
1226            cout << "warning!!" << endl;
1227               
1228                // create new root of the hierarchy
1229                root = MergeViewCells(root, bestViewCell);
1230        }
1231
1232        return root;   
1233}
1234
1235
1236struct SortableViewCellEntry {
1237
1238        SortableViewCellEntry() {}
1239        SortableViewCellEntry(const float v, ViewCell *cell):mValue(v), mViewCell(cell) {}
1240
1241        float mValue;
1242        ViewCell *mViewCell;
1243
1244        friend bool operator<(const SortableViewCellEntry &a, const SortableViewCellEntry &b) {
1245                return a.mValue < b.mValue;
1246        }
1247};
1248
1249
1250ViewCell * ViewCellsManager::ConstructLocalMergeTree2(ViewCell *currentViewCell,
1251                                                                                                          const ViewCellContainer &viewCells)
1252{
1253 
1254  vector<SortableViewCellEntry> neighborhood(viewCells.size());
1255  int i, j;
1256  for (i = 0, j = 0; i < viewCells.size(); i++) {
1257        if (viewCells[i] != currentViewCell)
1258          neighborhood[j++] = SortableViewCellEntry(
1259                                                                                                EvalMergeCost(currentViewCell, viewCells[i]),
1260                                                                                                viewCells[i]);
1261  }
1262  neighborhood.resize(j);
1263 
1264  sort(neighborhood.begin(), neighborhood.end());
1265 
1266  ViewCell *root = currentViewCell;
1267 
1268  vector<SortableViewCellEntry>::const_iterator it, it_end = neighborhood.end();
1269 
1270  const int n = min(mMaxFilterSize, (int)neighborhood.size());
1271  //-- use priority queue to merge leaf pairs
1272 
1273  //cout << "neighborhood: " << neighborhood.size() << endl;
1274  for (int nMergedViewCells = 0; nMergedViewCells < n; ++ nMergedViewCells)
1275  {
1276          ViewCell *bestViewCell = neighborhood[nMergedViewCells].mViewCell;
1277          //cout <<nMergedViewCells<<":"<<"homogenity=" <<neighborhood[nMergedViewCells].mValue<<endl;
1278          // create new root of the hierarchy
1279          root = MergeViewCells(root, bestViewCell);
1280          // set negative cost so that this view cell gets deleted
1281          root->SetMergeCost(-1.0f);
1282  }
1283 
1284  return root; 
1285}
1286
1287void
1288ViewCellsManager::DeleteLocalMergeTree(ViewCell *vc
1289                                                                           ) const
1290{
1291        if (!vc->IsLeaf() && vc->GetMergeCost() < 0.0f)
1292        {       
1293                ViewCellInterior *vci = (ViewCellInterior *) vc;
1294                ViewCellContainer::const_iterator it, it_end = vci->mChildren.end();
1295
1296        for (it = vci->mChildren.begin(); it != it_end; ++ it)
1297                        DeleteLocalMergeTree(*it);
1298               
1299                vci->mChildren.clear();
1300               
1301                delete vci;
1302  }
1303}
1304
1305
1306bool ViewCellsManager::CheckValidity(ViewCell *vc,
1307                                                                         int minPvsSize,
1308                                                                         int maxPvsSize) const
1309{
1310
1311        if ((vc->GetPvs().EvalPvsCost() > maxPvsSize) ||
1312                (vc->GetPvs().EvalPvsCost() < minPvsSize))
1313        {
1314                return false;
1315        }
1316
1317        return true;
1318}
1319
1320
1321int ViewCellsManager::ComputeBoxIntersections(const AxisAlignedBox3 &box,
1322                                                                                          ViewCellContainer &viewCells) const
1323{
1324        return 0;
1325};
1326
1327
1328AxisAlignedBox3 ViewCellsManager::GetFilterBBox(const Vector3 &viewPoint,
1329                                                                                                const float width) const
1330{
1331  float w = Magnitude(mViewSpaceBox.Size())*width;
1332  Vector3 min = viewPoint - w * 0.5f;
1333  Vector3 max = viewPoint + w * 0.5f;
1334 
1335  return AxisAlignedBox3(min, max);
1336}
1337
1338
1339void ViewCellsManager::GetPrVS(const Vector3 &viewPoint,
1340                                                           PrVs &prvs,
1341                                                           const float filterWidth)
1342{
1343  ViewCell *currentViewCell = GetViewCell(viewPoint);
1344
1345  if (mMaxFilterSize < 1) {
1346        prvs.mViewCell = currentViewCell;
1347        return;
1348  }
1349 
1350  const AxisAlignedBox3 box = GetFilterBBox(viewPoint, filterWidth);
1351 
1352  if (currentViewCell)
1353        {
1354          ViewCellContainer viewCells;
1355          ComputeBoxIntersections(box, viewCells);
1356         
1357          ViewCell *root = ConstructLocalMergeTree2(currentViewCell, viewCells);
1358          prvs.mViewCell = root;
1359         
1360        }
1361  else
1362        {
1363          prvs.mViewCell = NULL;
1364          //prvs.mPvs = root->GetPvs();
1365        }
1366}
1367
1368
1369bool ViewCellsManager::ViewCellsTreeConstructed() const
1370{
1371    return (mViewCellsTree && mViewCellsTree->GetRoot());
1372}
1373
1374
1375void ViewCellsManager::SetValidity(ViewCell *vc,
1376                                                                   int minPvs,
1377                                                                   int maxPvs) const
1378{
1379        vc->SetValid(CheckValidity(vc, minPvs, maxPvs));
1380}
1381
1382
1383void
1384ViewCellsManager::SetValidity(
1385                                                          int minPvsSize,
1386                                                          int maxPvsSize) const
1387{
1388        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1389
1390
1391        for (it = mViewCells.begin(); it != it_end; ++ it)
1392        {
1393                SetValidity(*it, minPvsSize, maxPvsSize);
1394        }
1395}
1396
1397void
1398ViewCellsManager::SetValidityPercentage(
1399                                                                                const float minValid,
1400                                                                                const float maxValid
1401                                                                                )
1402{
1403        sort(mViewCells.begin(), mViewCells.end(), ViewCell::SmallerPvs);
1404
1405        int start = (int)(mViewCells.size() * minValid);
1406        int end = (int)(mViewCells.size() * maxValid);
1407
1408        for (int i = 0; i < (int)mViewCells.size(); ++ i)
1409        {
1410                mViewCells[i]->SetValid(i >= start && i <= end);
1411        }
1412}
1413
1414
1415int ViewCellsManager::CountValidViewcells() const
1416{
1417        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1418        int valid = 0;
1419
1420        for (it = mViewCells.begin(); it != it_end; ++ it)
1421        {       
1422                if ((*it)->GetValid())
1423                        ++ valid;
1424        }
1425
1426        return valid;
1427}
1428
1429
1430bool ViewCellsManager::LoadViewCellsGeometry(const string filename,
1431                                                                                         const bool extrudeBaseTriangles)
1432{
1433        /// we use predefined view cells from now on
1434        mUsePredefinedViewCells = true;
1435        X3dParser parser;
1436       
1437        if (extrudeBaseTriangles)
1438        {
1439                Environment::GetSingleton()->GetFloatValue("ViewCells.height", parser.mViewCellHeight);
1440                const bool success = parser.ParseFile(filename, *this);
1441
1442                if (!success)
1443                        return false;
1444        }
1445        else
1446        {
1447                // hack: use standard mesh loading
1448                // create temporary scene graph for loading the view cells geometry
1449                // note: delete the meshes as they are created two times for transformed mesh instances.
1450                SceneGraphNode *root = new SceneGraphNode();
1451                const bool success = parser.ParseFile(filename, root, true);
1452               
1453                if (!success)
1454                {
1455                        DEL_PTR(root);
1456                        return false;
1457                }
1458
1459                ObjectContainer::const_iterator oit, oit_end = root->mGeometry.end();
1460               
1461                for (oit = root->mGeometry.begin(); oit != oit_end; ++ oit)
1462                {
1463                        Mesh *mesh;
1464                        if ((*oit)->Type() == Intersectable::TRANSFORMED_MESH_INSTANCE)
1465                        {
1466                                TransformedMeshInstance *mit = dynamic_cast<TransformedMeshInstance *>(*oit);
1467                                mesh = MeshManager::GetSingleton()->CreateResource();
1468                                mit->GetTransformedMesh(*mesh);
1469                        }
1470                        else if ((*oit)->Type() == Intersectable::MESH_INSTANCE)
1471                        {
1472                                MeshInstance *mit = dynamic_cast<MeshInstance *>(*oit);
1473                                mesh = mit->GetMesh();
1474                        }
1475                        mesh->ComputeBoundingBox();
1476                        mViewCells.push_back(GenerateViewCell(mesh));
1477                }
1478
1479                DEL_PTR(root);
1480        }
1481
1482        // set view space box to bounding box of the view cells
1483        AxisAlignedBox3 bbox;
1484        bbox.Initialize();
1485        ViewCellContainer::iterator it = mViewCells.begin(), it_end = mViewCells.end();
1486
1487        for (; it != it_end; ++ it)
1488        {
1489                bbox.Include((*it)->GetMesh()->mBox);
1490        }
1491
1492        SetViewSpaceBox(bbox);
1493        cout << "view space box: " << bbox << endl;
1494        cout << "generated " << (int)mViewCells.size() << " view cells using the geometry " << filename << endl;
1495
1496        return true;
1497}
1498
1499
1500bool ViewCellsManager::GetViewPoint(Vector3 &viewPoint) const
1501{
1502        viewPoint = mViewSpaceBox.GetRandomPoint();
1503        return true;
1504}
1505
1506
1507float ViewCellsManager::GetViewSpaceVolume()
1508{
1509        return mViewSpaceBox.GetVolume() * (2.0f * sqr((float)M_PI));
1510}
1511
1512
1513bool ViewCellsManager::ViewPointValid(const Vector3 &viewPoint) const
1514{
1515        if (!ViewCellsConstructed())
1516        {
1517                return mViewSpaceBox.IsInside(viewPoint);
1518        }
1519        else
1520        {
1521                if (!mViewSpaceBox.IsInside(viewPoint))
1522                        return false;
1523
1524                ViewCell *viewcell = GetViewCell(viewPoint);
1525
1526                if (!viewcell || !viewcell->GetValid())
1527                        return false;
1528        }
1529
1530        return true;
1531}
1532
1533
1534float ViewCellsManager::ComputeSampleContributions(const VssRayContainer &rays,
1535                                                                                                   const bool addRays,                                                                 
1536                                                                                                   const bool storeViewCells)
1537{
1538        // view cells not yet constructed
1539        if (!ViewCellsConstructed())
1540                return 0.0f;
1541       
1542        float sum = 0.0f;
1543        VssRayContainer::const_iterator it, it_end = rays.end();
1544       
1545        for (it = rays.begin(); it != it_end; ++ it)
1546        {
1547                sum += ComputeSampleContribution(*(*it), addRays, storeViewCells);
1548        }
1549
1550        return sum;
1551}
1552
1553
1554void ViewCellsManager::EvaluateViewCellsStats()
1555{
1556        mCurrentViewCellsStats.Reset();
1557        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1558
1559        for (it = mViewCells.begin(); it != it_end; ++ it)
1560        {
1561                mViewCellsTree->UpdateViewCellsStats(*it, mCurrentViewCellsStats);
1562        }
1563        cout << "here44 " << mCurrentViewCellsStats.maxPvs << endl;
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 bool colorCode,
2197                                                                                         const AxisAlignedPlane *clipPlane
2198                                                                                         ) const
2199{
2200        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
2201cout << "here2" << endl;
2202        for (it = mViewCells.begin(); it != it_end; ++ it)
2203        {cout << "here4 " << mOnlyValidViewCells << " " << (*it)->GetValid() <<  endl;
2204                if (!mOnlyValidViewCells || (*it)->GetValid())
2205                {cout << "here5 " << mColorCode << endl;
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        //cout << "color code: " << colorCode << endl;
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                { //cout << "here22 " << mCurrentViewCellsStats.maxPvs << endl;
2758                        if (mCurrentViewCellsStats.maxPvs)
2759                        {
2760                                //cout << "pvscost : " << (float)mViewCellsTree->GetPvsCost(vc) << endl;
2761                                //cout << "maxPvs : " << (float)mCurrentViewCellsStats.maxPvs << endl;
2762
2763                                importance =
2764                                        (float)mViewCellsTree->GetPvsCost(vc) /
2765                                        (float)mCurrentViewCellsStats.maxPvs;
2766                        }
2767                }
2768                break;
2769        case 2: // merges
2770                {
2771            const int lSize = mViewCellsTree->GetNumInitialViewCells(vc);
2772                        importance = (float)lSize / (float)mCurrentViewCellsStats.maxLeaves;
2773                }
2774                break;
2775#if 0
2776        case 3: // merge tree differene
2777                {
2778                        importance = (float)GetMaxTreeDiff(vc) /
2779                                (float)(mVspBspTree->GetStatistics().maxDepth * 2);
2780
2781                }
2782                break;
2783#endif
2784        default:
2785                cout << "here10" << endl;
2786                break;
2787        }
2788
2789        // special color code for invalid view cells
2790        m.mDiffuseColor.r = importance;
2791        m.mDiffuseColor.g = 1.0f - m.mDiffuseColor.r;
2792        m.mDiffuseColor.b = vcValid ? 1.0f : 0.0f;
2793
2794        //Debug << "importance: " << importance << endl;
2795        exporter->SetForcedMaterial(m);
2796}
2797
2798
2799void ViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
2800                                                                                          vector<MergeCandidate> &candidates)
2801{
2802        // implemented in subclasses
2803}
2804
2805
2806void ViewCellsManager::UpdatePvsForEvaluation()
2807{
2808        ObjectPvs objPvs;
2809        UpdatePvsForEvaluation(mViewCellsTree->GetRoot(), objPvs);
2810}
2811
2812void ViewCellsManager::UpdatePvsForEvaluation(ViewCell *root, ObjectPvs &pvs)
2813{
2814        // terminate traversal
2815        if (root->IsLeaf())
2816        {
2817                //cout << "updating leaf" << endl;
2818                // we assume that pvs is explicitly stored in leaves
2819                pvs = root->GetPvs();
2820                UpdateScalarPvsSize(root, pvs.EvalPvsCost(), pvs.GetSize());
2821                return;
2822        }
2823
2824        //cout << "recursivly updating pvs" << endl;
2825
2826        ////////////////
2827        //-- interior node => propagate pvs up the tree
2828
2829        ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(root);
2830
2831        // reset interior pvs
2832        interior->GetPvs().Clear();
2833        // reset recursive pvs
2834        pvs.Clear();
2835
2836        // pvss of child nodes
2837        vector<ObjectPvs> pvsList;
2838        pvsList.resize((int)interior->mChildren.size());
2839
2840        ViewCellContainer::const_iterator vit, vit_end = interior->mChildren.end();
2841       
2842        int i = 0;
2843
2844        for (vit = interior->mChildren.begin(); vit != vit_end; ++ vit, ++ i)
2845        {
2846                //////////////////
2847                //-- recursivly compute child pvss
2848                UpdatePvsForEvaluation(*vit, pvsList[i]/*objPvs*/);
2849        }
2850
2851#if 1
2852        Intersectable::NewMail();
2853
2854        //-- faster way of computing pvs:
2855        //-- construct merged pvs by adding
2856        //-- and only those of the next pvs which were not mailed.
2857        //-- note: sumpdf is not correct!!
2858
2859        vector<ObjectPvs>::iterator oit = pvsList.begin();
2860
2861        for (vit = interior->mChildren.begin(); vit != vit_end; ++ vit, ++ oit)
2862        {
2863                ObjectPvsIterator pit = (*oit).GetIterator();
2864               
2865                // first mark all object from this pvs
2866                while (pit.HasMoreEntries())
2867                {               
2868                        ObjectPvsEntry entry = pit.Next();
2869
2870                        Intersectable *intersect = entry.mObject;
2871
2872                        if (!intersect->Mailed())
2873                        {
2874                                pvs.AddSample(intersect, entry.mData.mSumPdf);
2875                                intersect->Mail();
2876                        }
2877                }
2878        }
2879
2880        // store pvs in this node
2881        if (mViewCellsTree->ViewCellsStorage() == ViewCellsTree::PVS_IN_INTERIORS)
2882        {
2883                interior->SetPvs(pvs);
2884        }
2885       
2886        // set new pvs size
2887        UpdateScalarPvsSize(interior, pvs.EvalPvsCost(), pvs.GetSize());
2888       
2889#else
2890        // really merge cells: slow put sumPdf is correct
2891        viewCellInterior->GetPvs().Merge(backVc->GetPvs());
2892        viewCellInterior->GetPvs().Merge(frontVc->GetPvs());
2893#endif
2894}
2895
2896
2897
2898/*******************************************************************/
2899/*               BspViewCellsManager implementation                */
2900/*******************************************************************/
2901
2902
2903BspViewCellsManager::BspViewCellsManager(ViewCellsTree *vcTree, BspTree *bspTree):
2904ViewCellsManager(vcTree), mBspTree(bspTree)
2905{
2906        Environment::GetSingleton()->GetIntValue("BspTree.Construction.samples", mInitialSamples);
2907
2908        mBspTree->SetViewCellsManager(this);
2909        mBspTree->SetViewCellsTree(mViewCellsTree);
2910}
2911
2912
2913bool BspViewCellsManager::ViewCellsConstructed() const
2914{
2915        return mBspTree->GetRoot() != NULL;
2916}
2917
2918
2919ViewCell *BspViewCellsManager::GenerateViewCell(Mesh *mesh) const
2920{
2921        return new BspViewCell(mesh);
2922}
2923
2924
2925int BspViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
2926                                                                                          const VssRayContainer &rays)
2927{
2928        // if view cells were already constructed, we can finish
2929        if (ViewCellsConstructed())
2930                return 0;
2931
2932        int sampleContributions = 0;
2933
2934        // construct view cells using the collected samples
2935        RayContainer constructionRays;
2936        VssRayContainer savedRays;
2937
2938        // choose a a number of rays based on the ratio of cast rays / requested rays
2939        const int limit = min(mInitialSamples, (int)rays.size());
2940        VssRayContainer::const_iterator it, it_end = rays.end();
2941
2942        const float prop = (float)limit / ((float)rays.size() + Limits::Small);
2943
2944        for (it = rays.begin(); it != it_end; ++ it)
2945        {
2946                if (Random(1.0f) < prop)
2947                        constructionRays.push_back(new Ray(*(*it)));
2948                else
2949                        savedRays.push_back(*it);
2950        }
2951
2952    if (!mUsePredefinedViewCells)
2953        {
2954                // no view cells loaded
2955                mBspTree->Construct(objects, constructionRays, &mViewSpaceBox);
2956                // collect final view cells
2957                mBspTree->CollectViewCells(mViewCells);
2958        }
2959        else
2960        {       
2961                // use predefined view cells geometry =>
2962                // contruct bsp hierarchy over them
2963                mBspTree->Construct(mViewCells);
2964        }
2965
2966        // destroy rays created only for construction
2967        CLEAR_CONTAINER(constructionRays);
2968
2969        Debug << mBspTree->GetStatistics() << endl;
2970        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
2971
2972        // recast rest of the rays
2973        if (SAMPLE_AFTER_SUBDIVISION)
2974                ComputeSampleContributions(savedRays, true, false);
2975
2976        // real meshes are contructed at this stage
2977        if (0)
2978        {
2979                cout << "finalizing view cells ... ";
2980                FinalizeViewCells(true);
2981                cout << "finished" << endl;     
2982        }
2983
2984        return sampleContributions;
2985}
2986
2987
2988void BspViewCellsManager::CollectViewCells()
2989{       
2990        if (!ViewCellsTreeConstructed())
2991        {       // view cells tree constructed 
2992                mBspTree->CollectViewCells(mViewCells);
2993        }
2994        else
2995        {       // we can use the view cells tree hierarchy to get the right set
2996                mViewCellsTree->CollectBestViewCellSet(mViewCells, mNumActiveViewCells);
2997        }
2998}
2999
3000
3001float BspViewCellsManager::GetProbability(ViewCell *viewCell)
3002{
3003        if (1)
3004                return GetVolume(viewCell) / GetViewSpaceBox().GetVolume();
3005        else
3006                // compute view cell area as subsititute for probability
3007                return GetArea(viewCell) / GetAccVcArea();
3008}
3009
3010
3011
3012int BspViewCellsManager::CastLineSegment(const Vector3 &origin,
3013                                                                                 const Vector3 &termination,
3014                                                                                 ViewCellContainer &viewcells)
3015{
3016        return mBspTree->CastLineSegment(origin, termination, viewcells);
3017}
3018
3019
3020void ViewCellsManager::ExportMergedViewCells(const ObjectContainer &objects)
3021{
3022        // save color code
3023        const int savedColorCode = mColorCode;
3024
3025        // export merged view cells
3026        mColorCode = 0; // use random colors
3027
3028        Exporter *exporter = Exporter::GetExporter("merged_view_cells.wrl");
3029
3030        cout << "exporting view cells after merge ... ";
3031
3032        if (exporter)
3033        {
3034                if (mExportGeometry)
3035                {
3036                        exporter->ExportGeometry(objects);
3037                }
3038
3039                exporter->SetFilled();
3040                ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
3041
3042                delete exporter;
3043        }
3044        cout << "finished" << endl;
3045
3046        // export merged view cells using pvs color coding
3047       
3048        exporter = Exporter::GetExporter("merged_view_cells_pvs.wrl");
3049        cout << "exporting view cells after merge (pvs size) ... ";     
3050
3051        if (exporter)
3052        {
3053                if (mExportGeometry)
3054                {
3055                        exporter->ExportGeometry(objects);
3056                }
3057
3058                exporter->SetFilled();
3059                mColorCode = 1;
3060cout << "here49 " << mColorCode << endl;
3061                ExportViewCellsForViz(exporter, NULL,  mColorCode, GetClipPlane());
3062
3063                delete exporter;
3064        }
3065        cout << "finished" << endl;
3066       
3067        mColorCode = savedColorCode;
3068}
3069
3070
3071int BspViewCellsManager::PostProcess(const ObjectContainer &objects,
3072                                                                         const VssRayContainer &rays)
3073{
3074        if (!ViewCellsConstructed())
3075        {
3076                Debug << "view cells not constructed" << endl;
3077                return 0;
3078        }
3079       
3080        // view cells already finished before post processing step,
3081        // i.e., because they were loaded from disc
3082        if (mViewCellsFinished)
3083        {
3084                FinalizeViewCells(true);
3085                EvaluateViewCellsStats();
3086
3087                return 0;
3088        }
3089
3090        //////////////////
3091        //-- merge leaves of the view cell hierarchy   
3092       
3093        cout << "starting post processing using " << mPostProcessSamples << " samples ... ";
3094        long startTime = GetTime();
3095       
3096        VssRayContainer postProcessRays;
3097        GetRaySets(rays, mPostProcessSamples, postProcessRays);
3098
3099        if (mMergeViewCells)
3100        {
3101                cout << "constructing visibility based merge tree" << endl;
3102                mViewCellsTree->ConstructMergeTree(rays, objects);
3103        }
3104        else
3105        {
3106                cout << "constructing spatial merge tree" << endl;
3107                ViewCell *root;
3108                // the spatial merge tree is difficult to build for
3109                // this type of construction, as view cells cover several
3110                // leaves => create dummy tree which is only 2 levels deep
3111                if (mUsePredefinedViewCells)
3112                {
3113                        root = ConstructDummyMergeTree(mBspTree->GetRoot());
3114                }
3115                else
3116                {
3117                        // create spatial merge hierarchy
3118                        root = ConstructSpatialMergeTree(mBspTree->GetRoot());
3119                }
3120               
3121                mViewCellsTree->SetRoot(root);
3122
3123                // recompute pvs in the whole hierarchy
3124                ObjectPvs pvs;
3125                UpdatePvsForEvaluation(root, pvs);
3126        }
3127
3128        cout << "finished" << endl;
3129        cout << "merged view cells in "
3130                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
3131
3132        Debug << "Postprocessing: Merged view cells in "
3133                << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl << endl;
3134
3135       
3136        ////////////////////////
3137        //-- visualization and statistics after merge
3138
3139        if (1)
3140        {
3141                char mstats[100];
3142                Environment::GetSingleton()->GetStringValue("ViewCells.mergeStats", mstats);
3143                mViewCellsTree->ExportStats(mstats);
3144        }
3145
3146        // recompute view cells and stats
3147        ResetViewCells();
3148        Debug << "\nView cells after merge:\n" << mCurrentViewCellsStats << endl;
3149
3150        //  visualization of the view cells
3151        if (0) ExportMergedViewCells(objects);
3152
3153        // compute final meshes and volume / area
3154        if (1) FinalizeViewCells(true);
3155       
3156        return 0;
3157}
3158
3159
3160BspViewCellsManager::~BspViewCellsManager()
3161{
3162}
3163
3164
3165int BspViewCellsManager::GetType() const
3166{
3167        return BSP;
3168}
3169
3170
3171void BspViewCellsManager::Visualize(const ObjectContainer &objects,
3172                                                                        const VssRayContainer &sampleRays)
3173{
3174        if (!ViewCellsConstructed())
3175                return;
3176       
3177        const int savedColorCode = mColorCode;
3178       
3179        if (1) // export final view cells
3180        {
3181                mColorCode = 1; // hack color code
3182                Exporter *exporter = Exporter::GetExporter("final_view_cells.wrl");
3183       
3184                cout << "exporting view cells after merge (pvs size) ... ";     
3185
3186                if (exporter)
3187                {
3188                        if (mExportGeometry)
3189                        {
3190                                exporter->ExportGeometry(objects);
3191                        }
3192
3193                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
3194                        delete exporter;
3195                }
3196                cout << "finished" << endl;
3197        }
3198
3199        // reset color code
3200        mColorCode = savedColorCode;
3201
3202
3203        //////////////////
3204        //-- visualization of the BSP splits
3205
3206        bool exportSplits = false;
3207        Environment::GetSingleton()->GetBoolValue("BspTree.Visualization.exportSplits", exportSplits);
3208
3209        if (exportSplits)
3210        {
3211                cout << "exporting splits ... ";
3212                ExportSplits(objects);
3213                cout << "finished" << endl;
3214        }
3215
3216        int leafOut;
3217        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.maxOutput", leafOut);
3218        const int raysOut = 100;
3219        ExportSingleViewCells(objects, leafOut, false, true, false, raysOut, "");
3220}
3221
3222
3223void BspViewCellsManager::ExportSplits(const ObjectContainer &objects)
3224{
3225        Exporter *exporter = Exporter::GetExporter("bsp_splits.x3d");
3226
3227        if (exporter)
3228        {
3229                //exporter->SetFilled();
3230                if (mExportGeometry)
3231                {
3232                        exporter->ExportGeometry(objects);
3233                }
3234
3235                Material m;
3236                m.mDiffuseColor = RgbColor(1, 0, 0);
3237                exporter->SetForcedMaterial(m);
3238                exporter->SetWireframe();
3239
3240                exporter->ExportBspSplits(*mBspTree, true);
3241
3242                // NOTE: take forced material, else big scenes cannot be viewed
3243                m.mDiffuseColor = RgbColor(0, 1, 0);
3244                exporter->SetForcedMaterial(m);
3245                //exporter->ResetForcedMaterial();
3246
3247                delete exporter;
3248        }
3249}
3250
3251
3252void BspViewCellsManager::ExportSingleViewCells(const ObjectContainer &objects,
3253                                                                                                const int maxViewCells,
3254                                                                                                const bool sortViewCells,
3255                                                                                                const bool exportPvs,
3256                                                                                                const bool exportRays,
3257                                                                                                const int maxRays,
3258                                                                                                const string prefix,
3259                                                                                                VssRayContainer *visRays)
3260{
3261        if (sortViewCells)
3262        {       // sort view cells to visualize the largest view cells
3263                stable_sort(mViewCells.begin(), mViewCells.end(), ViewCell::LargerRenderCost);
3264        }
3265
3266        //////////
3267        //-- some view cells for output
3268
3269        ViewCell::NewMail();
3270        const int limit = min(maxViewCells, (int)mViewCells.size());
3271       
3272        for (int i = 0; i < limit; ++ i)
3273        {
3274                const int idx = sortViewCells ? (int)RandomValue(0, (float)mViewCells.size() - 0.5f) : i;
3275                ViewCell *vc = mViewCells[idx];
3276
3277                if (vc->Mailed() || vc->GetId() == OUT_OF_BOUNDS_ID)
3278                        continue;
3279
3280                vc->Mail();
3281
3282                ObjectPvs pvs;
3283                mViewCellsTree->GetPvs(vc, pvs);
3284
3285                char s[64]; sprintf(s, "%sviewcell-%04d.wrl", prefix.c_str(), i);
3286                Exporter *exporter = Exporter::GetExporter(s);
3287               
3288                cout << "view cell " << idx << ": pvs cost=" << (int)mViewCellsTree->GetPvsCost(vc) << endl;
3289
3290                if (exportRays)
3291                {
3292                        ////////////
3293                        //-- export rays piercing this view cell
3294
3295                        // use rays stored with the view cells
3296                        VssRayContainer vcRays, vcRays2, vcRays3;
3297            VssRayContainer collectRays;
3298
3299                        // collect initial view cells
3300                        ViewCellContainer leaves;
3301                        mViewCellsTree->CollectLeaves(vc, leaves);
3302
3303                        ViewCellContainer::const_iterator vit, vit_end = leaves.end();
3304                for (vit = leaves.begin(); vit != vit_end; ++ vit)
3305                        {       
3306                                // prepare some rays for output
3307                                VssRayContainer::const_iterator rit, rit_end = (*vit)->GetOrCreateRays()->end();
3308                                for (rit = (*vit)->GetOrCreateRays()->begin(); rit != rit_end; ++ rit)
3309                                {
3310                                        collectRays.push_back(*rit);
3311                                }
3312                        }
3313
3314                        const int raysOut = min((int)collectRays.size(), maxRays);
3315
3316                        // prepare some rays for output
3317                        VssRayContainer::const_iterator rit, rit_end = collectRays.end();
3318                        for (rit = collectRays.begin(); rit != rit_end; ++ rit)
3319                        {
3320                                const float p = RandomValue(0.0f, (float)collectRays.size());
3321                                if (p < raysOut)
3322                                {
3323                                        if ((*rit)->mFlags & VssRay::BorderSample)
3324                                        {
3325                                                vcRays.push_back(*rit);
3326                                        }
3327                                        else if ((*rit)->mFlags & VssRay::ReverseSample)
3328                                                vcRays2.push_back(*rit);
3329                                        else
3330                                                vcRays3.push_back(*rit);
3331                                               
3332                                }
3333                        }
3334
3335                        exporter->ExportRays(vcRays, RgbColor(1, 0, 0));
3336                        exporter->ExportRays(vcRays2, RgbColor(0, 1, 0));
3337                        exporter->ExportRays(vcRays3, RgbColor(1, 1, 1));
3338                }
3339               
3340                ////////////////
3341                //-- export view cell geometry
3342
3343                exporter->SetWireframe();
3344
3345                Material m;//= RandomMaterial();
3346                m.mDiffuseColor = RgbColor(0, 1, 0);
3347                exporter->SetForcedMaterial(m);
3348
3349                ExportViewCellGeometry(exporter, vc, NULL, NULL);
3350                exporter->SetFilled();
3351
3352                if (exportPvs)
3353                {
3354                        Intersectable::NewMail();
3355                        ObjectPvsIterator pit = pvs.GetIterator();
3356
3357                        while (pit.HasMoreEntries())
3358                        {               
3359                                ObjectPvsEntry entry = pit.Next();
3360
3361                // output PVS of view cell
3362                                Intersectable *intersect = entry.mObject;
3363                               
3364                                if (!intersect->Mailed())
3365                                {
3366                                        intersect->Mail();
3367
3368                                        m = RandomMaterial();
3369                                        exporter->SetForcedMaterial(m);
3370                                        exporter->ExportIntersectable(intersect);
3371                                }
3372                        }
3373                        cout << endl;
3374                }
3375               
3376                DEL_PTR(exporter);
3377                cout << "finished" << endl;
3378        }
3379}
3380
3381
3382void BspViewCellsManager::TestSubdivision()
3383{
3384        ViewCellContainer leaves;
3385        mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
3386
3387        ViewCellContainer::const_iterator it, it_end = leaves.end();
3388
3389        const float vol = mViewSpaceBox.GetVolume();
3390        float subdivVol = 0;
3391        float newVol = 0;
3392
3393        for (it = leaves.begin(); it != it_end; ++ it)
3394        {
3395                BspNodeGeometry geom;
3396                mBspTree->ConstructGeometry(*it, geom);
3397
3398                const float lVol = geom.GetVolume();
3399                newVol += lVol;
3400                subdivVol += (*it)->GetVolume();
3401
3402                const float thres = 0.9f;
3403                if ((lVol < ((*it)->GetVolume() * thres)) ||
3404                        (lVol * thres > ((*it)->GetVolume())))
3405                        Debug << "warning: " << lVol << " " << (*it)->GetVolume() << endl;
3406        }
3407       
3408        Debug << "exact volume: " << vol << endl;
3409        Debug << "subdivision volume: " << subdivVol << endl;
3410        Debug << "new volume: " << newVol << endl;
3411}
3412
3413
3414void BspViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
3415                                                                                                 ViewCell *vc,
3416                                                                                                 const AxisAlignedBox3 *sceneBox,
3417                                                                                                 const AxisAlignedPlane *clipPlane
3418                                                                                                 ) const
3419{
3420        if (clipPlane)
3421        {
3422                const Plane3 plane = clipPlane->GetPlane();
3423
3424                ViewCellContainer leaves;
3425                mViewCellsTree->CollectLeaves(vc, leaves);
3426                ViewCellContainer::const_iterator it, it_end = leaves.end();
3427
3428                for (it = leaves.begin(); it != it_end; ++ it)
3429                {
3430                        BspNodeGeometry geom;
3431                        BspNodeGeometry front;
3432                        BspNodeGeometry back;
3433
3434                        mBspTree->ConstructGeometry(*it, geom);
3435
3436                        const float eps = 0.0001f;
3437                        const int cf = geom.Side(plane, eps);
3438
3439                        if (cf == -1)
3440                        {
3441                                exporter->ExportPolygons(geom.GetPolys());
3442                        }
3443                        else if (cf == 0)
3444                        {
3445                                geom.SplitGeometry(front,
3446                                                                   back,
3447                                                                   plane,
3448                                                                   mViewSpaceBox,
3449                                                                   eps);
3450
3451                                if (back.Valid())
3452                                {
3453                                        exporter->ExportPolygons(back.GetPolys());
3454                                }                       
3455                        }
3456                }
3457        }
3458        else
3459        {
3460                // export mesh if available
3461                // TODO: some bug here?
3462                if (1 && vc->GetMesh())
3463                {
3464                        exporter->ExportMesh(vc->GetMesh());
3465                }
3466                else
3467                {
3468                        BspNodeGeometry geom;
3469                        mBspTree->ConstructGeometry(vc, geom);
3470                        exporter->ExportPolygons(geom.GetPolys());
3471                }
3472        }
3473}
3474
3475
3476void BspViewCellsManager::CreateMesh(ViewCell *vc)
3477{
3478        // note: should previous mesh be deleted (via mesh manager?)
3479        BspNodeGeometry geom;
3480        mBspTree->ConstructGeometry(vc, geom);
3481
3482        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
3483
3484        IncludeNodeGeomInMesh(geom, *mesh);
3485        vc->SetMesh(mesh);
3486}
3487
3488
3489void BspViewCellsManager::Finalize(ViewCell *viewCell,
3490                                                                   const bool createMesh)
3491{
3492        float area = 0;
3493        float volume = 0;
3494
3495        ViewCellContainer leaves;
3496        mViewCellsTree->CollectLeaves(viewCell, leaves);
3497
3498        ViewCellContainer::const_iterator it, it_end = leaves.end();
3499
3500    for (it = leaves.begin(); it != it_end; ++ it)
3501        {
3502                BspNodeGeometry geom;
3503
3504                mBspTree->ConstructGeometry(*it, geom);
3505
3506                const float lVol = geom.GetVolume();
3507                const float lArea = geom.GetArea();
3508
3509                area += lArea;
3510                volume += lVol;
3511       
3512                CreateMesh(*it);
3513        }
3514
3515        viewCell->SetVolume(volume);
3516        viewCell->SetArea(area);
3517}
3518
3519
3520ViewCell *BspViewCellsManager::GetViewCell(const Vector3 &point, const bool active) const
3521{
3522        if (!ViewCellsConstructed())
3523        {
3524                return NULL;
3525        }
3526        if (!mViewSpaceBox.IsInside(point))
3527        {
3528                return NULL;
3529        }
3530        return mBspTree->GetViewCell(point);
3531}
3532
3533
3534void BspViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
3535                                                                                                 vector<MergeCandidate> &candidates)
3536{
3537        cout << "collecting merge candidates ... " << endl;
3538
3539        if (mUseRaysForMerge)
3540        {
3541                mBspTree->CollectMergeCandidates(rays, candidates);
3542        }
3543        else
3544        {
3545                vector<BspLeaf *> leaves;
3546                mBspTree->CollectLeaves(leaves);
3547                mBspTree->CollectMergeCandidates(leaves, candidates);
3548        }
3549
3550        cout << "fininshed collecting candidates" << endl;
3551}
3552
3553
3554
3555bool BspViewCellsManager::ExportViewCells(const string filename,
3556                                                                                  const bool exportPvs,
3557                                                                                  const ObjectContainer &objects)
3558{
3559        if (!ViewCellsConstructed() || !ViewCellsTreeConstructed())
3560        {
3561                return false;
3562        }
3563
3564        cout << "exporting view cells to xml ... ";
3565
3566        OUT_STREAM stream(filename.c_str());
3567
3568        // for output we need unique ids for each view cell
3569        CreateUniqueViewCellIds();
3570
3571        stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<endl;
3572        stream << "<VisibilitySolution>" << endl;
3573
3574        if (exportPvs)
3575        {
3576                //////////
3577                //-- export bounding boxes: they are used to identify the objects from the pvs and
3578                //-- assign them to the entities in the rendering engine
3579
3580                stream << "<BoundingBoxes>" << endl;
3581                ObjectContainer::const_iterator oit, oit_end = objects.end();
3582
3583                for (oit = objects.begin(); oit != oit_end; ++ oit)
3584                {
3585                        const AxisAlignedBox3 box = (*oit)->GetBox();
3586                       
3587                        stream << "<BoundingBox" << " id=\"" << (*oit)->GetId() << "\""
3588                                   << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
3589                                   << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\" />" << endl;
3590                }
3591
3592                stream << "</BoundingBoxes>" << endl;
3593        }
3594
3595        ///////////
3596        //-- export the view cells and the pvs
3597
3598        const int numViewCells = mCurrentViewCellsStats.viewCells;
3599        stream << "<ViewCells number=\"" << numViewCells << "\" >" << endl;
3600
3601        mViewCellsTree->Export(stream, exportPvs);
3602       
3603        stream << "</ViewCells>" << endl;
3604
3605        /////////////
3606        //-- export the view space hierarchy
3607        stream << "<ViewSpaceHierarchy type=\"bsp\""
3608                   << " min=\"" << mViewSpaceBox.Min().x << " " << mViewSpaceBox.Min().y << " " << mViewSpaceBox.Min().z << "\""
3609                   << " max=\"" << mViewSpaceBox.Max().x << " " << mViewSpaceBox.Max().y << " " << mViewSpaceBox.Max().z << "\">" << endl;
3610
3611        mBspTree->Export(stream);
3612
3613        // end tags
3614        stream << "</ViewSpaceHierarchy>" << endl;
3615        stream << "</VisibilitySolution>" << endl;
3616
3617        stream.close();
3618        cout << "finished" << endl;
3619
3620        return true;
3621}
3622
3623
3624ViewCell *BspViewCellsManager::ConstructDummyMergeTree(BspNode *root)
3625{
3626        ViewCellInterior *vcRoot = new ViewCellInterior();
3627               
3628        // evaluate merge cost for priority traversal
3629        const float mergeCost =  -(float)root->mTimeStamp;
3630        vcRoot->SetMergeCost(mergeCost);
3631
3632        float volume = 0;
3633        vector<BspLeaf *> leaves;
3634        mBspTree->CollectLeaves(leaves);
3635        vector<BspLeaf *>::const_iterator lit, lit_end = leaves.end();
3636        ViewCell::NewMail();
3637
3638        for (lit = leaves.begin(); lit != lit_end; ++ lit)
3639        {
3640                BspLeaf *leaf = *lit;
3641                ViewCell *vc = leaf->GetViewCell();
3642
3643                if (!vc->Mailed())
3644                {
3645                        vc->Mail();
3646                        vc->SetMergeCost(0.0f);
3647                        vcRoot->SetupChildLink(vc);
3648
3649                        volume += vc->GetVolume();
3650                        volume += vc->GetVolume();     
3651                        vcRoot->SetVolume(volume);
3652                }
3653        }
3654       
3655        return vcRoot;
3656}
3657
3658
3659ViewCell *BspViewCellsManager::ConstructSpatialMergeTree(BspNode *root)
3660{
3661        // terminate recursion
3662        if (root->IsLeaf())
3663        {
3664                BspLeaf *leaf = dynamic_cast<BspLeaf *>(root);
3665                leaf->GetViewCell()->SetMergeCost(0.0f);
3666                return leaf->GetViewCell();
3667        }
3668       
3669        BspInterior *interior = dynamic_cast<BspInterior *>(root);
3670        ViewCellInterior *viewCellInterior = new ViewCellInterior();
3671               
3672        // evaluate merge cost for priority traversal
3673        const float mergeCost = -(float)root->mTimeStamp;
3674        viewCellInterior->SetMergeCost(mergeCost);
3675
3676        float volume = 0;
3677       
3678        BspNode *front = interior->GetFront();
3679        BspNode *back = interior->GetBack();
3680
3681
3682        ////////////
3683        //-- recursivly compute child hierarchies
3684
3685        ViewCell *backVc = ConstructSpatialMergeTree(back);
3686        ViewCell *frontVc = ConstructSpatialMergeTree(front);
3687
3688        viewCellInterior->SetupChildLink(backVc);
3689        viewCellInterior->SetupChildLink(frontVc);
3690
3691        volume += backVc->GetVolume();
3692        volume += frontVc->GetVolume();
3693
3694        viewCellInterior->SetVolume(volume);
3695
3696        return viewCellInterior;
3697}
3698
3699
3700/************************************************************************/
3701/*                   KdViewCellsManager implementation                  */
3702/************************************************************************/
3703
3704
3705
3706KdViewCellsManager::KdViewCellsManager(ViewCellsTree *vcTree, KdTree *kdTree):
3707ViewCellsManager(vcTree), mKdTree(kdTree), mKdPvsDepth(100)
3708{
3709}
3710
3711
3712float KdViewCellsManager::GetProbability(ViewCell *viewCell)
3713{
3714        // compute view cell area / volume as subsititute for probability
3715        if (0)
3716                return GetArea(viewCell) / GetViewSpaceBox().SurfaceArea();
3717        else
3718                return GetVolume(viewCell) / GetViewSpaceBox().GetVolume();
3719}
3720
3721
3722
3723
3724void KdViewCellsManager::CollectViewCells()
3725{
3726        //mKdTree->CollectViewCells(mViewCells); TODO
3727}
3728
3729
3730int KdViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
3731                                                                  const VssRayContainer &rays)
3732{
3733        // if view cells already constructed
3734        if (ViewCellsConstructed())
3735                return 0;
3736
3737        mKdTree->Construct();
3738
3739        mTotalAreaValid = false;
3740        // create the view cells
3741        mKdTree->CreateAndCollectViewCells(mViewCells);
3742        // cast rays
3743        ComputeSampleContributions(rays, true, false);
3744
3745        EvaluateViewCellsStats();
3746        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
3747
3748        return 0;
3749}
3750
3751
3752bool KdViewCellsManager::ViewCellsConstructed() const
3753{
3754        return mKdTree->GetRoot() != NULL;
3755}
3756
3757
3758int KdViewCellsManager::PostProcess(const ObjectContainer &objects,
3759                                                                        const VssRayContainer &rays)
3760{
3761        return 0;
3762}
3763
3764
3765void KdViewCellsManager::ExportSingleViewCells(const ObjectContainer &objects,
3766                                                                                           const int maxViewCells,
3767                                                                                           const bool sortViewCells,
3768                                                                                           const bool exportPvs,
3769                                                                                           const bool exportRays,
3770                                                                                           const int maxRays,
3771                                                                                           const string prefix,
3772                                                                                           VssRayContainer *visRays)
3773{
3774        // TODO
3775}
3776
3777
3778void KdViewCellsManager::Visualize(const ObjectContainer &objects,
3779                                                                   const VssRayContainer &sampleRays)
3780{
3781        if (!ViewCellsConstructed())
3782                return;
3783
3784        // using view cells instead of the kd PVS of objects
3785        const bool useViewCells = true;
3786        bool exportRays = false;
3787
3788        int limit = min(mVisualizationSamples, (int)sampleRays.size());
3789        const int pvsOut = min((int)objects.size(), 10);
3790        VssRayContainer *rays = new VssRayContainer[pvsOut];
3791
3792        if (useViewCells)
3793        {
3794                const int leafOut = 10;
3795
3796                ViewCell::NewMail();
3797
3798                //-- some rays for output
3799                const int raysOut = min((int)sampleRays.size(), mVisualizationSamples);
3800                Debug << "visualization using " << raysOut << " samples" << endl;
3801
3802                //-- some random view cells and rays for output
3803                vector<KdLeaf *> kdLeaves;
3804
3805                for (int i = 0; i < leafOut; ++ i)
3806                        kdLeaves.push_back(dynamic_cast<KdLeaf *>(mKdTree->GetRandomLeaf()));
3807
3808                for (int i = 0; i < kdLeaves.size(); ++ i)
3809                {
3810                        KdLeaf *leaf = kdLeaves[i];
3811                        RayContainer vcRays;
3812
3813                        cout << "creating output for view cell " << i << " ... ";
3814#if 0
3815                        // check whether we can add the current ray to the output rays
3816                        for (int k = 0; k < raysOut; ++ k)
3817                        {
3818                                Ray *ray = sampleRays[k];
3819
3820                                for (int j = 0; j < (int)ray->bspIntersections.size(); ++ j)
3821                                {
3822                                        BspLeaf *leaf2 = ray->bspIntersections[j].mLeaf;
3823
3824                                        if (leaf->GetViewCell() == leaf2->GetViewCell())
3825                                        {
3826                                                vcRays.push_back(ray);
3827                                        }
3828                                }
3829                        }
3830#endif
3831                        Intersectable::NewMail();
3832
3833                        ViewCell *vc = leaf->mViewCell;
3834                        char str[64]; sprintf(str, "viewcell%04d.wrl", i);
3835
3836                        Exporter *exporter = Exporter::GetExporter(str);
3837                        exporter->SetFilled();
3838
3839                        exporter->SetWireframe();
3840                        //exporter->SetFilled();
3841
3842                        Material m;//= RandomMaterial();
3843                        m.mDiffuseColor = RgbColor(1, 1, 0);
3844                        exporter->SetForcedMaterial(m);
3845
3846                        AxisAlignedBox3 box = mKdTree->GetBox(leaf);
3847                        exporter->ExportBox(box);
3848
3849                        // export rays piercing this view cell
3850                        exporter->ExportRays(vcRays, 1000, RgbColor(0, 1, 0));
3851
3852                        m.mDiffuseColor = RgbColor(1, 0, 0);
3853                        exporter->SetForcedMaterial(m);
3854
3855                        // exporter->SetWireframe();
3856                        exporter->SetFilled();
3857
3858                        ObjectPvsIterator pit = vc->GetPvs().GetIterator();
3859                       
3860                        while (pit.HasMoreEntries())
3861                        {               
3862                                ObjectPvsEntry entry = pit.Next();
3863                               
3864                                //-- output PVS of view cell
3865                                Intersectable *intersect = entry.mObject;
3866                                if (!intersect->Mailed())
3867                                {
3868                                        exporter->ExportIntersectable(intersect);
3869                                        intersect->Mail();
3870                                }
3871                        }
3872
3873                        DEL_PTR(exporter);
3874                        cout << "finished" << endl;
3875                }
3876
3877                DEL_PTR(rays);
3878        }
3879        else // using kd PVS of objects
3880        {
3881                for (int i = 0; i < limit; ++ i)
3882                {
3883                        VssRay *ray = sampleRays[i];
3884
3885                        // check whether we can add this to the rays
3886                        for (int j = 0; j < pvsOut; j++)
3887                        {
3888                                if (objects[j] == ray->mTerminationObject)
3889                                {
3890                                        rays[j].push_back(ray);
3891                                }
3892                        }
3893                }
3894
3895                if (exportRays)
3896                {
3897                        Exporter *exporter = NULL;
3898                        exporter = Exporter::GetExporter("sample-rays.x3d");
3899                        exporter->SetWireframe();
3900                        exporter->ExportKdTree(*mKdTree);
3901
3902                        for (int i = 0; i < pvsOut; i++)
3903                                exporter->ExportRays(rays[i], RgbColor(1, 0, 0));
3904
3905                        exporter->SetFilled();
3906                        delete exporter;
3907                }
3908
3909                for (int k=0; k < pvsOut; k++)
3910                {
3911                        Intersectable *object = objects[k];
3912                        char str[64]; sprintf(str, "viewcell%04d.wrl", k);
3913
3914                        Exporter *exporter = Exporter::GetExporter(str);
3915                        exporter->SetWireframe();
3916
3917                        // matt: no kd pvs
3918                        /*
3919                        KdPvsMap::iterator kit = object->mKdPvs.mEntries.begin();
3920                        Intersectable::NewMail();
3921
3922                        // avoid adding the object to the list
3923                        object->Mail();
3924                        ObjectContainer visibleObjects;
3925
3926                        for (; kit != object->mKdPvs.mEntries.end(); i++)
3927                        {
3928                                KdNode *node = (*kit).first;
3929                                exporter->ExportBox(mKdTree->GetBox(node));
3930
3931                                mKdTree->CollectObjects(node, visibleObjects);
3932                        }
3933
3934                        exporter->ExportRays(rays[k],  RgbColor(0, 1, 0));
3935                        exporter->SetFilled();
3936
3937                        for (int j = 0; j < visibleObjects.size(); j++)
3938                                exporter->ExportIntersectable(visibleObjects[j]);
3939
3940                        Material m;
3941                        m.mDiffuseColor = RgbColor(1, 0, 0);
3942                        exporter->SetForcedMaterial(m);
3943                        exporter->ExportIntersectable(object);
3944*/
3945                        delete exporter;
3946                }
3947        }
3948}
3949
3950
3951ViewCell *KdViewCellsManager::GenerateViewCell(Mesh *mesh) const
3952{
3953        return new KdViewCell(mesh);
3954}
3955
3956
3957void KdViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
3958                                                                                                ViewCell *vc,
3959                                                                                                const AxisAlignedBox3 *sceneBox,
3960                                                                                                const AxisAlignedPlane *clipPlane
3961                                                                                                ) const
3962{
3963        ViewCellContainer leaves;
3964        mViewCellsTree->CollectLeaves(vc, leaves);
3965        ViewCellContainer::const_iterator it, it_end = leaves.end();
3966
3967        for (it = leaves.begin(); it != it_end; ++ it)
3968        {
3969                KdViewCell *kdVc = dynamic_cast<KdViewCell *>(*it);
3970                exporter->ExportBox(mKdTree->GetBox(kdVc->mLeaves[0]));
3971        }
3972}
3973
3974
3975int KdViewCellsManager::GetType() const
3976{
3977        return ViewCellsManager::KD;
3978}
3979
3980
3981
3982KdNode *KdViewCellsManager::GetNodeForPvs(KdLeaf *leaf)
3983{
3984        KdNode *node = leaf;
3985
3986        while (node->mParent && node->mDepth > mKdPvsDepth)
3987                node = node->mParent;
3988
3989        return node;
3990}
3991
3992int KdViewCellsManager::CastLineSegment(const Vector3 &origin,
3993                                                                                const Vector3 &termination,
3994                                                                                ViewCellContainer &viewcells)
3995{
3996        return mKdTree->CastLineSegment(origin, termination, viewcells);
3997}
3998
3999
4000void KdViewCellsManager::CreateMesh(ViewCell *vc)
4001{
4002        // TODO
4003}
4004
4005
4006
4007void KdViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
4008                                                                                                vector<MergeCandidate> &candidates)
4009{
4010        // TODO
4011}
4012
4013
4014
4015/**************************************************************************/
4016/*                   VspBspViewCellsManager implementation                */
4017/**************************************************************************/
4018
4019
4020VspBspViewCellsManager::VspBspViewCellsManager(ViewCellsTree *vcTree, VspBspTree *vspBspTree):
4021ViewCellsManager(vcTree), mVspBspTree(vspBspTree)
4022{
4023        Environment::GetSingleton()->GetIntValue("VspBspTree.Construction.samples", mInitialSamples);
4024        mVspBspTree->SetViewCellsManager(this);
4025        mVspBspTree->mViewCellsTree = mViewCellsTree;
4026}
4027
4028
4029VspBspViewCellsManager::~VspBspViewCellsManager()
4030{
4031}
4032
4033
4034float VspBspViewCellsManager::GetProbability(ViewCell *viewCell)
4035{
4036        if (0 && mVspBspTree->mUseAreaForPvs)
4037                return GetArea(viewCell) / GetAccVcArea();
4038        else
4039                return GetVolume(viewCell) / mViewSpaceBox.GetVolume();
4040}
4041
4042
4043void VspBspViewCellsManager::CollectViewCells()
4044{
4045        // view cells tree constructed?
4046        if (!ViewCellsTreeConstructed())
4047        {
4048                mVspBspTree->CollectViewCells(mViewCells, false);
4049        }
4050        else
4051        {       
4052                // we can use the view cells tree hierarchy to get the right set
4053                mViewCellsTree->CollectBestViewCellSet(mViewCells, mNumActiveViewCells);
4054        }
4055}
4056
4057
4058void VspBspViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
4059                                                                                                        vector<MergeCandidate> &candidates)
4060{       
4061        cout << "collecting merge candidates ... " << endl;
4062
4063        if (mUseRaysForMerge)
4064        {
4065                mVspBspTree->CollectMergeCandidates(rays, candidates);
4066        }
4067        else
4068        {
4069                vector<BspLeaf *> leaves;
4070                mVspBspTree->CollectLeaves(leaves);
4071       
4072                mVspBspTree->CollectMergeCandidates(leaves, candidates);
4073        }
4074
4075        cout << "fininshed collecting candidates" << endl;
4076}
4077
4078
4079bool VspBspViewCellsManager::ViewCellsConstructed() const
4080{
4081        return mVspBspTree->GetRoot() != NULL;
4082}
4083
4084
4085ViewCell *VspBspViewCellsManager::GenerateViewCell(Mesh *mesh) const
4086{
4087        return new BspViewCell(mesh);
4088}
4089
4090
4091int VspBspViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
4092                                                                                                 const VssRayContainer &rays)
4093{
4094        mMaxPvsSize = (int)(mMaxPvsRatio * (float)objects.size());
4095
4096        // if view cells were already constructed
4097        if (ViewCellsConstructed())
4098        {
4099                return 0;
4100        }
4101
4102        int sampleContributions = 0;
4103        VssRayContainer sampleRays;
4104
4105        const int limit = min(mInitialSamples, (int)rays.size());
4106
4107        Debug << "samples used for vsp bsp subdivision: " << mInitialSamples
4108                  << ", actual rays: " << (int)rays.size() << endl;
4109
4110        VssRayContainer savedRays;
4111
4112        if (SAMPLE_AFTER_SUBDIVISION)
4113        {
4114                VssRayContainer constructionRays;
4115               
4116                GetRaySets(rays, mInitialSamples, constructionRays, &savedRays);
4117
4118                Debug << "rays used for initial construction: " << (int)constructionRays.size() << endl;
4119                Debug << "rays saved for later use: " << (int)savedRays.size() << endl;
4120       
4121                mVspBspTree->Construct(constructionRays, &mViewSpaceBox);
4122        }
4123        else
4124        {
4125                Debug << "rays used for initial construction: " << (int)rays.size() << endl;
4126                mVspBspTree->Construct(rays, &mViewSpaceBox);
4127        }
4128
4129        // collapse invalid regions
4130        cout << "collapsing invalid tree regions ... ";
4131        long startTime = GetTime();
4132
4133        const int collapsedLeaves = mVspBspTree->CollapseTree();
4134        Debug << "collapsed in " << TimeDiff(startTime, GetTime()) * 1e-3
4135                  << " seconds" << endl;
4136
4137    cout << "finished" << endl;
4138
4139        /////////////////
4140        //-- stats after construction
4141
4142        Debug << mVspBspTree->GetStatistics() << endl;
4143
4144        ResetViewCells();
4145        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
4146
4147
4148        //////////////////////
4149        //-- recast the rest of the rays
4150
4151        startTime = GetTime();
4152
4153        cout << "Computing remaining ray contributions ... ";
4154
4155        if (SAMPLE_AFTER_SUBDIVISION)
4156                ComputeSampleContributions(savedRays, true, false);
4157
4158        cout << "finished" << endl;
4159
4160        Debug << "Computed remaining ray contribution in " << TimeDiff(startTime, GetTime()) * 1e-3
4161                  << " secs" << endl;
4162
4163        cout << "construction finished" << endl;
4164
4165        if (0)
4166        {       ////////
4167                //-- real meshes are contructed at this stage
4168                cout << "finalizing view cells ... ";
4169                FinalizeViewCells(true);
4170                cout << "finished" << endl;
4171        }
4172
4173        return sampleContributions;
4174}
4175
4176
4177void VspBspViewCellsManager::MergeViewCells(const VssRayContainer &rays,
4178                                                                                        const ObjectContainer &objects)
4179{
4180    int vcSize = 0;
4181        int pvsSize = 0;
4182
4183        //-- merge view cells
4184        cout << "starting merge using " << mPostProcessSamples << " samples ... " << endl;
4185        long startTime = GetTime();
4186
4187
4188        if (mMergeViewCells)
4189        {
4190                // TODO: should be done BEFORE the ray casting
4191                // compute tree by merging the nodes based on cost heuristics
4192                mViewCellsTree->ConstructMergeTree(rays, objects);
4193        }
4194        else
4195        {
4196                // compute tree by merging the nodes of the spatial hierarchy
4197                ViewCell *root = ConstructSpatialMergeTree(mVspBspTree->GetRoot());
4198                mViewCellsTree->SetRoot(root);
4199
4200                // compute pvs
4201                ObjectPvs pvs;
4202                UpdatePvsForEvaluation(root, pvs);
4203        }
4204
4205        if (1)
4206        {
4207                char mstats[100];
4208                ObjectPvs pvs;
4209
4210                Environment::GetSingleton()->GetStringValue("ViewCells.mergeStats", mstats);
4211                mViewCellsTree->ExportStats(mstats);
4212        }
4213
4214        cout << "merged view cells in "
4215                 << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl;
4216
4217        Debug << "Postprocessing: Merged view cells in "
4218                  << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl << endl;
4219       
4220
4221        //////////////////
4222        //-- stats and visualizations
4223
4224        int savedColorCode = mColorCode;
4225       
4226        // get currently active view cell set
4227        ResetViewCells();
4228        Debug << "\nView cells after merge:\n" << mCurrentViewCellsStats << endl;
4229       
4230        if (mShowVisualization) // export merged view cells
4231        {
4232                mColorCode = 0;
4233                Exporter *exporter = Exporter::GetExporter("merged_view_cells.wrl");
4234               
4235                cout << "exporting view cells after merge ... ";
4236
4237                if (exporter)
4238                {
4239                        if (0)
4240                                exporter->SetWireframe();
4241                        else
4242                                exporter->SetFilled();
4243
4244                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
4245
4246                        if (mExportGeometry)
4247                        {
4248                                Material m;
4249                                m.mDiffuseColor = RgbColor(0, 1, 0);
4250                                exporter->SetForcedMaterial(m);
4251                                exporter->SetFilled();
4252
4253                                exporter->ExportGeometry(objects);
4254                        }
4255
4256                        delete exporter;
4257                }
4258                cout << "finished" << endl;
4259        }
4260
4261        if (mShowVisualization)
4262        {
4263                // use pvs size for color coding
4264                mColorCode = 1;
4265                Exporter *exporter = Exporter::GetExporter("merged_view_cells_pvs.wrl");
4266
4267                cout << "exporting view cells after merge (pvs size) ... ";     
4268
4269                if (exporter)
4270                {
4271                        exporter->SetFilled();
4272
4273                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
4274
4275                        if (mExportGeometry)
4276                        {
4277                                Material m;
4278                                m.mDiffuseColor = RgbColor(0, 1, 0);
4279                                exporter->SetForcedMaterial(m);
4280                                exporter->SetFilled();
4281
4282                                exporter->ExportGeometry(objects);
4283                        }
4284
4285                        delete exporter;
4286                }
4287                cout << "finished" << endl;
4288        }
4289
4290        mColorCode = savedColorCode;
4291}
4292
4293
4294void VspBspViewCellsManager::RefineViewCells(const VssRayContainer &rays,
4295                                                                                         const ObjectContainer &objects)
4296{
4297        mRenderer->RenderScene();
4298
4299        SimulationStatistics ss;
4300        dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
4301    Debug << "render time before refine\n\n" << ss << endl;
4302
4303        const long startTime = GetTime();
4304        cout << "Refining the merged view cells ... ";
4305
4306        // refining the merged view cells
4307        const int refined = mViewCellsTree->RefineViewCells(rays, objects);
4308
4309        //-- stats and visualizations
4310        cout << "finished" << endl;
4311        cout << "refined " << refined << " view cells in "
4312                 << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl;
4313
4314        Debug << "Postprocessing: refined " << refined << " view cells in "
4315                  << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl << endl;
4316}
4317
4318
4319int VspBspViewCellsManager::PostProcess(const ObjectContainer &objects,
4320                                                                                const VssRayContainer &rays)
4321{
4322        if (!ViewCellsConstructed())
4323        {
4324                Debug << "postprocess error: no view cells constructed" << endl;
4325                return 0;
4326        }
4327
4328        // view cells already finished before post processing step
4329        // (i.e. because they were loaded)
4330        if (mViewCellsFinished)
4331        {
4332                FinalizeViewCells(true);
4333                EvaluateViewCellsStats();
4334
4335                return 0;
4336        }
4337
4338        // check if new view cells turned invalid
4339        int minPvs, maxPvs;
4340
4341        if (0)
4342        {
4343                minPvs = mMinPvsSize;
4344                maxPvs = mMaxPvsSize;
4345        }
4346        else
4347        {
4348                // problem matt: why did I start here from zero?
4349                minPvs = 0;
4350                maxPvs = mMaxPvsSize;
4351        }
4352
4353        Debug << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
4354        cout << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
4355       
4356        SetValidity(minPvs, maxPvs);
4357
4358        // update valid view space according to valid view cells
4359        if (0) mVspBspTree->ValidateTree();
4360
4361        // area has to be recomputed
4362        mTotalAreaValid = false;
4363        VssRayContainer postProcessRays;
4364        GetRaySets(rays, mPostProcessSamples, postProcessRays);
4365
4366        Debug << "post processing using " << (int)postProcessRays.size() << " samples" << endl;
4367
4368        // should maybe be done here to allow merge working
4369        // with area or volume and to correct the rendering statistics
4370        if (0) FinalizeViewCells(false);
4371               
4372        //////////
4373        //-- merge the individual view cells
4374        MergeViewCells(postProcessRays, objects);
4375       
4376        // refines the merged view cells
4377        if (0) RefineViewCells(postProcessRays, objects);
4378
4379
4380        ///////////
4381        //-- render simulation after merge + refine
4382
4383        cout << "\nview cells partition render time before compress" << endl << endl;;
4384        dynamic_cast<RenderSimulator *>(mRenderer)->RenderScene();
4385        SimulationStatistics ss;
4386        dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
4387        cout << ss << endl;
4388       
4389
4390        ////////////
4391        //-- compression
4392//#if HAS_TO_BE_REDONE
4393        if (ViewCellsTreeConstructed() && mCompressViewCells)
4394        {
4395                int pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
4396                Debug << "number of entries before compress: " << pvsEntries << endl;
4397
4398                mViewCellsTree->SetViewCellsStorage(ViewCellsTree::COMPRESSED);
4399
4400                pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
4401                Debug << "number of entries after compress: " << pvsEntries << endl;
4402        }
4403//#endif
4404
4405        // collapse sibling leaves that share the same view cell
4406        if (0) mVspBspTree->CollapseTree();
4407
4408        // recompute view cell list and statistics
4409        ResetViewCells();
4410
4411        // compute final meshes and volume / area
4412        if (1) FinalizeViewCells(true);
4413
4414        return 0;
4415}
4416
4417
4418int VspBspViewCellsManager::GetType() const
4419{
4420        return VSP_BSP;
4421}
4422
4423
4424ViewCell *VspBspViewCellsManager::ConstructSpatialMergeTree(BspNode *root)
4425{
4426        // terminate recursion
4427        if (root->IsLeaf())
4428        {
4429                BspLeaf *leaf = dynamic_cast<BspLeaf *>(root);
4430                leaf->GetViewCell()->SetMergeCost(0.0f);
4431                return leaf->GetViewCell();
4432        }
4433       
4434       
4435        BspInterior *interior = dynamic_cast<BspInterior *>(root);
4436        ViewCellInterior *viewCellInterior = new ViewCellInterior();
4437               
4438        // evaluate merge cost for priority traversal
4439        float mergeCost = 1.0f / (float)root->mTimeStamp;
4440        viewCellInterior->SetMergeCost(mergeCost);
4441
4442        float volume = 0;
4443       
4444        BspNode *front = interior->GetFront();
4445        BspNode *back = interior->GetBack();
4446
4447
4448        ObjectPvs frontPvs, backPvs;
4449
4450        //-- recursivly compute child hierarchies
4451        ViewCell *backVc = ConstructSpatialMergeTree(back);
4452        ViewCell *frontVc = ConstructSpatialMergeTree(front);
4453
4454
4455        viewCellInterior->SetupChildLink(backVc);
4456        viewCellInterior->SetupChildLink(frontVc);
4457
4458        volume += backVc->GetVolume();
4459        volume += frontVc->GetVolume();
4460
4461        viewCellInterior->SetVolume(volume);
4462
4463        return viewCellInterior;
4464}
4465
4466
4467bool VspBspViewCellsManager::GetViewPoint(Vector3 &viewPoint) const
4468{
4469        if (!ViewCellsConstructed())
4470                return ViewCellsManager::GetViewPoint(viewPoint);
4471
4472        // TODO: set reasonable limit
4473        const int limit = 20;
4474
4475        for (int i = 0; i < limit; ++ i)
4476        {
4477                viewPoint = mViewSpaceBox.GetRandomPoint();
4478                if (mVspBspTree->ViewPointValid(viewPoint))
4479                {
4480                        return true;
4481                }
4482        }
4483
4484        Debug << "failed to find valid view point, taking " << viewPoint << endl;
4485        return false;
4486}
4487
4488
4489bool VspBspViewCellsManager::ViewPointValid(const Vector3 &viewPoint) const
4490{
4491        // $$JB -> implemented in viewcellsmanager (slower, but allows dynamic
4492        // validy update in preprocessor for all managers)
4493        return ViewCellsManager::ViewPointValid(viewPoint);
4494
4495        //      return mViewSpaceBox.IsInside(viewPoint) &&
4496        //                 mVspBspTree->ViewPointValid(viewPoint);
4497}
4498
4499
4500void VspBspViewCellsManager::Visualize(const ObjectContainer &objects,
4501                                                                           const VssRayContainer &sampleRays)
4502{
4503        if (!ViewCellsConstructed())
4504                return;
4505
4506        VssRayContainer visRays;
4507        GetRaySets(sampleRays, mVisualizationSamples, visRays);
4508       
4509        if (1)
4510        {       
4511                //////////////////
4512                //-- export final view cell partition
4513
4514                Exporter *exporter = Exporter::GetExporter("final_view_cells.wrl");
4515               
4516                if (exporter)
4517                {
4518                        cout << "exporting view cells after post process ... ";
4519                        if (0)
4520                        {       // export view space box
4521                                exporter->SetWireframe();
4522                                exporter->ExportBox(mViewSpaceBox);
4523                                exporter->SetFilled();
4524                        }
4525
4526                        Material m;
4527                        m.mDiffuseColor.r = 0.0f;
4528                        m.mDiffuseColor.g = 0.5f;
4529                        m.mDiffuseColor.b = 0.5f;
4530
4531            exporter->SetForcedMaterial(m);
4532
4533                        if (1 && mExportGeometry)
4534                        {
4535                                exporter->ExportGeometry(objects);
4536                        }
4537
4538                        if (0 && mExportRays)
4539                        {
4540                                exporter->ExportRays(visRays, RgbColor(1, 0, 0));
4541                        }
4542                        ExportViewCellsForViz(exporter, NULL, mColorCode, GetClipPlane());
4543
4544                        delete exporter;
4545                        cout << "finished" << endl;
4546                }
4547        }
4548
4549        ////////////////
4550        //-- visualization of the BSP splits
4551
4552        bool exportSplits = false;
4553        Environment::GetSingleton()->GetBoolValue("VspBspTree.Visualization.exportSplits", exportSplits);
4554
4555        if (exportSplits)
4556        {
4557                cout << "exporting splits ... ";
4558                ExportSplits(objects, visRays);
4559                cout << "finished" << endl;
4560        }
4561
4562        ////////
4563        //-- export single view cells
4564       
4565        int leafOut;
4566        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.maxOutput", leafOut);
4567        const int raysOut = 100;
4568       
4569        ExportSingleViewCells(objects, leafOut, false, true, false, raysOut, "");
4570}
4571
4572
4573void VspBspViewCellsManager::ExportSplits(const ObjectContainer &objects,
4574                                                                                  const VssRayContainer &rays)
4575{
4576        Exporter *exporter = Exporter::GetExporter("bsp_splits.x3d");
4577
4578        if (exporter)
4579        {
4580                Material m;
4581                m.mDiffuseColor = RgbColor(1, 0, 0);
4582                exporter->SetForcedMaterial(m);
4583                exporter->SetWireframe();
4584
4585                exporter->ExportBspSplits(*mVspBspTree, true);
4586
4587                // take forced material, else big scenes cannot be viewed
4588                m.mDiffuseColor = RgbColor(0, 1, 0);
4589                exporter->SetForcedMaterial(m);
4590                exporter->SetFilled();
4591
4592                exporter->ResetForcedMaterial();
4593
4594                // export rays
4595                if (mExportRays)
4596                {
4597                        exporter->ExportRays(rays, RgbColor(1, 1, 0));
4598                }
4599
4600                if (mExportGeometry)
4601                {
4602                        exporter->ExportGeometry(objects);
4603                }
4604                delete exporter;
4605        }
4606}
4607
4608
4609void VspBspViewCellsManager::ExportSingleViewCells(const ObjectContainer &objects,
4610                                                                                                   const int maxViewCells,
4611                                                                                                   const bool sortViewCells,
4612                                                                                                   const bool exportPvs,
4613                                                                                                   const bool exportRays,
4614                                                                                                   const int maxRays,
4615                                                                                                   const string prefix,
4616                                                                                                   VssRayContainer *visRays)
4617{       
4618        if (sortViewCells)
4619        {
4620                // sort view cells to visualize the largest view cells
4621                stable_sort(mViewCells.begin(), mViewCells.end(), ViewCell::LargerRenderCost);
4622        }
4623
4624        //////////
4625        //-- some view cells for output
4626
4627        ViewCell::NewMail();
4628        const int limit = min(maxViewCells, (int)mViewCells.size());
4629       
4630        for (int i = 0; i < limit; ++ i)
4631        {
4632                cout << "creating output for view cell " << i << " ... ";
4633
4634                ViewCell *vc = sortViewCells ? // largest view cell pvs first?
4635                        mViewCells[(int)RandomValue(0, (float)mViewCells.size() - 0.5f)] : mViewCells[i];
4636
4637                if (vc->Mailed() || vc->GetId() == OUT_OF_BOUNDS_ID)
4638                        continue;
4639
4640                vc->Mail();
4641
4642                ObjectPvs pvs;
4643                mViewCellsTree->GetPvs(vc, pvs);
4644
4645                char s[64]; sprintf(s, "%sviewcell%04d.wrl", prefix.c_str(), i);
4646                Exporter *exporter = Exporter::GetExporter(s);
4647               
4648                const float pvsCost = mViewCellsTree->GetPvsCost(vc);
4649                cout << "view cell " << vc->GetId() << ": pvs cost=" << pvsCost << endl;
4650
4651                if (exportRays)
4652                {
4653                        ////////////
4654                        //-- export rays piercing this view cell
4655
4656                        // take rays stored with the view cells during subdivision
4657                        VssRayContainer vcRays;
4658            VssRayContainer collectRays;
4659
4660                        // collect initial view cells
4661                        ViewCellContainer leaves;
4662                        mViewCellsTree->CollectLeaves(vc, leaves);
4663
4664                        ViewCellContainer::const_iterator vit, vit_end = leaves.end();
4665                for (vit = leaves.begin(); vit != vit_end; ++ vit)
4666                        {       
4667                                BspLeaf *vcLeaf = dynamic_cast<BspViewCell *>(*vit)->mLeaves[0];
4668                                VssRayContainer::const_iterator rit, rit_end = vcLeaf->mVssRays.end();
4669
4670                                for (rit = vcLeaf->mVssRays.begin(); rit != rit_end; ++ rit)
4671                                {
4672                                        collectRays.push_back(*rit);
4673                                }
4674                        }
4675
4676                        const int raysOut = min((int)collectRays.size(), maxRays);
4677               
4678                        // prepare some rays for output
4679                        VssRayContainer::const_iterator rit, rit_end = collectRays.end();
4680                        for (rit = collectRays.begin(); rit != rit_end; ++ rit)
4681                        {
4682                                const float p = RandomValue(0.0f, (float)collectRays.size());
4683                       
4684                                if (p < raysOut)
4685                                {
4686                                        vcRays.push_back(*rit);
4687                                }
4688                        }
4689
4690                        exporter->ExportRays(vcRays, RgbColor(1, 1, 1));
4691                }
4692               
4693                ////////////////
4694                //-- export view cell geometry
4695
4696                exporter->SetWireframe();
4697
4698                Material m;//= RandomMaterial();
4699                m.mDiffuseColor = RgbColor(0, 1, 0);
4700                exporter->SetForcedMaterial(m);
4701
4702                ExportViewCellGeometry(exporter, vc, NULL, NULL);
4703                exporter->SetFilled();
4704
4705                if (exportPvs)
4706                {
4707                        Intersectable::NewMail();
4708
4709                        ObjectPvsIterator pit = pvs.GetIterator();
4710
4711                        cout << endl;
4712
4713                        // output PVS of view cell
4714                        while (pit.HasMoreEntries())
4715                        {
4716                                ObjectPvsEntry entry = pit.Next();             
4717                                Intersectable *intersect = entry.mObject;
4718                               
4719                                if (!intersect->Mailed())
4720                                {
4721                                        intersect->Mail();
4722
4723                                        m = RandomMaterial();
4724                                        exporter->SetForcedMaterial(m);
4725                                        exporter->ExportIntersectable(intersect);
4726                                }
4727                        }
4728                        cout << endl;
4729                }
4730               
4731                DEL_PTR(exporter);
4732                cout << "finished" << endl;
4733        }
4734}
4735
4736
4737void VspBspViewCellsManager::TestFilter(const ObjectContainer &objects)
4738{
4739        Exporter *exporter = Exporter::GetExporter("filter.x3d");
4740
4741        Vector3 bsize = mViewSpaceBox.Size();
4742        const Vector3 viewPoint(mViewSpaceBox.Center());
4743        float w = Magnitude(mViewSpaceBox.Size()) * mFilterWidth;
4744        const Vector3 width = Vector3(w);
4745       
4746        PrVs testPrVs;
4747       
4748        if (exporter)
4749        {
4750                ViewCellContainer viewCells;
4751       
4752        const AxisAlignedBox3 tbox = GetFilterBBox(viewPoint, mFilterWidth);
4753
4754                GetPrVS(viewPoint, testPrVs, GetFilterWidth());
4755
4756                exporter->SetWireframe();
4757
4758                exporter->SetForcedMaterial(RgbColor(1,1,1));
4759                exporter->ExportBox(tbox);
4760               
4761                exporter->SetFilled();
4762
4763                exporter->SetForcedMaterial(RgbColor(0,1,0));
4764                ExportViewCellGeometry(exporter, GetViewCell(viewPoint), NULL, NULL);
4765
4766                //exporter->ResetForcedMaterial();
4767                exporter->SetForcedMaterial(RgbColor(0,0,1));
4768                ExportViewCellGeometry(exporter, testPrVs.mViewCell, NULL, NULL);
4769
4770        exporter->SetForcedMaterial(RgbColor(1,0,0));
4771                exporter->ExportGeometry(objects);
4772
4773                delete exporter;
4774        }
4775}
4776
4777
4778int VspBspViewCellsManager::ComputeBoxIntersections(const AxisAlignedBox3 &box,
4779                                                                                                        ViewCellContainer &viewCells) const
4780{
4781        return mVspBspTree->ComputeBoxIntersections(box, viewCells);
4782}
4783
4784
4785int VspBspViewCellsManager::CastLineSegment(const Vector3 &origin,
4786                                                                                        const Vector3 &termination,
4787                                                                                        ViewCellContainer &viewcells)
4788{
4789        return mVspBspTree->CastLineSegment(origin, termination, viewcells);
4790}
4791
4792
4793void VspBspViewCellsManager::VisualizeWithFromPointQueries()
4794{
4795        int numSamples;
4796       
4797        Environment::GetSingleton()->GetIntValue("RenderSampler.samples", numSamples);
4798        cout << "samples" << numSamples << endl;
4799
4800        vector<RenderCostSample> samples;
4801 
4802        if (!mPreprocessor->GetRenderer())
4803                return;
4804
4805        //start the view point queries
4806        long startTime = GetTime();
4807        cout << "starting sampling of render cost ... ";
4808       
4809        mPreprocessor->GetRenderer()->SampleRenderCost(numSamples, samples, true);
4810
4811        cout << "finished in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
4812
4813
4814        // for each sample:
4815        //    find view cells associated with the samples
4816        //    store the sample pvs with the pvs associated with the view cell
4817        //
4818        // for each view cell:
4819        //    compute difference point sampled pvs - view cell pvs
4820        //    export geometry with color coded pvs difference
4821       
4822    std::map<ViewCell *, ObjectPvs> sampleMap;
4823
4824        vector<RenderCostSample>::const_iterator rit, rit_end = samples.end();
4825
4826        for (rit = samples.begin(); rit != rit_end; ++ rit)
4827        {
4828                RenderCostSample sample = *rit;
4829       
4830                ViewCell *vc = GetViewCell(sample.mPosition);
4831
4832                std::map<ViewCell *, ObjectPvs>::iterator it = sampleMap.find(vc);
4833
4834                if (it == sampleMap.end())
4835                {
4836                        sampleMap[vc] = sample.mPvs;
4837                }
4838                else
4839                {
4840                        (*it).second.MergeInPlace(sample.mPvs);
4841                }
4842        }
4843
4844        // visualize the view cells
4845        std::map<ViewCell *, ObjectPvs>::const_iterator vit, vit_end = sampleMap.end();
4846
4847        Material m;//= RandomMaterial();
4848
4849        for (vit = sampleMap.begin(); vit != vit_end; ++ vit)
4850        {
4851                ViewCell *vc = (*vit).first;
4852               
4853                const int pvsVc = mViewCellsTree->GetPvsEntries(vc);
4854                const int pvsPtSamples = (*vit).second.GetSize();
4855
4856        m.mDiffuseColor.r = (float) (pvsVc - pvsPtSamples);
4857                m.mDiffuseColor.b = 1.0f;
4858                //exporter->SetForcedMaterial(m);
4859                //ExportViewCellGeometry(exporter, vc, mClipPlaneForViz);
4860
4861                /*      // counting the pvss
4862                for (rit = samples.begin(); rit != rit_end; ++ rit)
4863                {
4864                        RenderCostSample sample = *rit;
4865                        ViewCell *vc = GetViewCell(sample.mPosition);
4866
4867                        AxisAlignedBox3 box(sample.mPosition - Vector3(1, 1, 1), sample.mPosition + Vector3(1, 1, 1));
4868                        Mesh *hMesh = CreateMeshFromBox(box);
4869
4870                        DEL_PTR(hMesh);
4871                }
4872                */
4873        }
4874}
4875
4876
4877void VspBspViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
4878                                                                                                        ViewCell *vc,
4879                                                                                                        const AxisAlignedBox3 *sceneBox,
4880                                                                                                        const AxisAlignedPlane *clipPlane
4881                                                                                                        ) const
4882{
4883        if (clipPlane)
4884        {
4885                const Plane3 plane = clipPlane->GetPlane();
4886
4887                ViewCellContainer leaves;
4888                mViewCellsTree->CollectLeaves(vc, leaves);
4889                ViewCellContainer::const_iterator it, it_end = leaves.end();
4890
4891                for (it = leaves.begin(); it != it_end; ++ it)
4892                {
4893                        BspNodeGeometry geom;
4894                        BspNodeGeometry front;
4895                        BspNodeGeometry back;
4896
4897                        mVspBspTree->ConstructGeometry(*it, geom);
4898
4899                        const float eps = 0.0001f;
4900                        const int cf = geom.Side(plane, eps);
4901
4902                        if (cf == -1)
4903                        {
4904                                exporter->ExportPolygons(geom.GetPolys());
4905                        }
4906                        else if (cf == 0)
4907                        {
4908                                geom.SplitGeometry(front,
4909                                                                   back,
4910                                                                   plane,
4911                                                                   mViewSpaceBox,
4912                                                                   eps);
4913
4914                                if (back.Valid())
4915                                {
4916                                        exporter->ExportPolygons(back.GetPolys());
4917                                }                       
4918                        }
4919                }
4920        }
4921        else
4922        {
4923                // export mesh if available
4924                // TODO: some bug here?
4925                if (1 && vc->GetMesh())
4926                {
4927                        exporter->ExportMesh(vc->GetMesh());
4928                }
4929                else
4930                {
4931                        BspNodeGeometry geom;
4932                        mVspBspTree->ConstructGeometry(vc, geom);
4933                        exporter->ExportPolygons(geom.GetPolys());
4934                }
4935        }
4936}
4937
4938
4939int VspBspViewCellsManager::GetMaxTreeDiff(ViewCell *vc) const
4940{
4941        ViewCellContainer leaves;
4942        mViewCellsTree->CollectLeaves(vc, leaves);
4943
4944        int maxDist = 0;
4945       
4946        // compute max height difference
4947        for (int i = 0; i < (int)leaves.size(); ++ i)
4948        {
4949                for (int j = 0; j < (int)leaves.size(); ++ j)
4950                {
4951                        BspLeaf *leaf = dynamic_cast<BspViewCell *>(leaves[i])->mLeaves[0];
4952
4953                        if (i != j)
4954                        {
4955                                BspLeaf *leaf2 =dynamic_cast<BspViewCell *>(leaves[j])->mLeaves[0];
4956                                const int dist = mVspBspTree->TreeDistance(leaf, leaf2);
4957                               
4958                                if (dist > maxDist)
4959                                        maxDist = dist;
4960                        }
4961                }
4962        }
4963
4964        return maxDist;
4965}
4966
4967
4968ViewCell *VspBspViewCellsManager::GetViewCell(const Vector3 &point, const bool active) const
4969{
4970        if (!ViewCellsConstructed())
4971                return NULL;
4972
4973        if (!mViewSpaceBox.IsInside(point))
4974          return NULL;
4975
4976        return mVspBspTree->GetViewCell(point, active);
4977}
4978
4979
4980void VspBspViewCellsManager::CreateMesh(ViewCell *vc)
4981{
4982        BspNodeGeometry geom;
4983        mVspBspTree->ConstructGeometry(vc, geom);
4984       
4985        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
4986        IncludeNodeGeomInMesh(geom, *mesh);
4987
4988        vc->SetMesh(mesh);
4989}
4990
4991
4992int VspBspViewCellsManager::CastBeam(Beam &beam)
4993{
4994        return mVspBspTree->CastBeam(beam);
4995}
4996
4997
4998void VspBspViewCellsManager::Finalize(ViewCell *viewCell,
4999                                                                          const bool createMesh)
5000{
5001        float area = 0;
5002        float volume = 0;
5003
5004        ViewCellContainer leaves;
5005        mViewCellsTree->CollectLeaves(viewCell, leaves);
5006
5007        ViewCellContainer::const_iterator it, it_end = leaves.end();
5008
5009    for (it = leaves.begin(); it != it_end; ++ it)
5010        {
5011                BspNodeGeometry geom;
5012                mVspBspTree->ConstructGeometry(*it, geom);
5013
5014                const float lVol = geom.GetVolume();
5015                const float lArea = geom.GetArea();
5016
5017                area += lArea;
5018                volume += lVol;
5019
5020                if (createMesh)
5021                        CreateMesh(*it);
5022        }
5023
5024        viewCell->SetVolume(volume);
5025        viewCell->SetArea(area);
5026}
5027
5028
5029void VspBspViewCellsManager::TestSubdivision()
5030{
5031        ViewCellContainer leaves;
5032        mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
5033
5034        ViewCellContainer::const_iterator it, it_end = leaves.end();
5035
5036        const float vol = mViewSpaceBox.GetVolume();
5037        float subdivVol = 0;
5038        float newVol = 0;
5039
5040        for (it = leaves.begin(); it != it_end; ++ it)
5041        {
5042                BspNodeGeometry geom;
5043                mVspBspTree->ConstructGeometry(*it, geom);
5044
5045                const float lVol = geom.GetVolume();
5046               
5047                newVol += lVol;
5048                subdivVol += (*it)->GetVolume();
5049               
5050                float thres = 0.9f;
5051                if ((lVol < ((*it)->GetVolume() * thres)) || (lVol * thres > ((*it)->GetVolume())))
5052                        Debug << "warning: " << lVol << " " << (*it)->GetVolume() << endl;
5053        }
5054       
5055        Debug << "exact volume: " << vol << endl;
5056        Debug << "subdivision volume: " << subdivVol << endl;
5057        Debug << "new volume: " << newVol << endl;
5058}
5059
5060
5061void VspBspViewCellsManager::PrepareLoadedViewCells()
5062{
5063        // TODO: do I still need this here?
5064        if (0)
5065                mVspBspTree->RepairViewCellsLeafLists();
5066}
5067
5068
5069
5070/**************************************************************************/
5071/*                   VspOspViewCellsManager implementation                */
5072/**************************************************************************/
5073
5074
5075VspOspViewCellsManager::VspOspViewCellsManager(ViewCellsTree *vcTree, const string &hierarchyType)
5076: ViewCellsManager(vcTree)
5077{
5078        Environment::GetSingleton()->GetIntValue("Hierarchy.Construction.samples", mInitialSamples);
5079
5080        mHierarchyManager = CreateHierarchyManager(hierarchyType);
5081        mHierarchyManager->SetViewCellsManager(this);
5082        mHierarchyManager->SetViewCellsTree(mViewCellsTree);
5083}
5084
5085
5086VspOspViewCellsManager::VspOspViewCellsManager(ViewCellsTree *vcTree, HierarchyManager *hm)
5087: ViewCellsManager(vcTree), mHierarchyManager(hm)
5088{
5089        Environment::GetSingleton()->GetIntValue("Hierarchy.Construction.samples", mInitialSamples);
5090
5091        mHierarchyManager->SetViewCellsManager(this);
5092        mHierarchyManager->SetViewCellsTree(mViewCellsTree);
5093}
5094
5095Intersectable *
5096VspOspViewCellsManager::GetIntersectable(const VssRay &ray, const bool isTermination) const
5097{
5098  return mHierarchyManager->GetIntersectable(ray, isTermination);
5099}
5100
5101HierarchyManager *VspOspViewCellsManager::CreateHierarchyManager(const string &hierarchyType)
5102{
5103        HierarchyManager *hierarchyManager;
5104
5105        if (strcmp(hierarchyType.c_str(), "osp") == 0)
5106        {
5107                Debug << "hierarchy manager: osp" << endl;
5108                hierarchyManager = new HierarchyManager(HierarchyManager::KD_BASED_OBJ_SUBDIV);
5109        }
5110        else if (strcmp(hierarchyType.c_str(), "bvh") == 0)
5111        {
5112                Debug << "hierarchy manager: bvh" << endl;
5113                hierarchyManager = new HierarchyManager(HierarchyManager::BV_BASED_OBJ_SUBDIV);
5114        }
5115        else // only view space partition
5116        {
5117                Debug << "hierarchy manager: obj" << endl;
5118                hierarchyManager = new HierarchyManager(HierarchyManager::NO_OBJ_SUBDIV);
5119        }
5120
5121        return hierarchyManager;
5122}
5123
5124
5125VspOspViewCellsManager::~VspOspViewCellsManager()
5126{
5127        DEL_PTR(mHierarchyManager);
5128}
5129
5130
5131float VspOspViewCellsManager::GetProbability(ViewCell *viewCell)
5132{
5133        return GetVolume(viewCell) / mViewSpaceBox.GetVolume();
5134}
5135
5136
5137void VspOspViewCellsManager::CollectViewCells()
5138{
5139        // view cells tree constructed
5140        if (!ViewCellsTreeConstructed())
5141        {
5142                mHierarchyManager->GetVspTree()->CollectViewCells(mViewCells, false);
5143        }
5144        else
5145        {       // we can use the view cells tree hierarchy to get the right set
5146                mViewCellsTree->CollectBestViewCellSet(mViewCells, mNumActiveViewCells);
5147        }
5148}
5149
5150
5151bool VspOspViewCellsManager::ViewCellsConstructed() const
5152{
5153        return mHierarchyManager->GetVspTree()->GetRoot() != NULL;
5154}
5155
5156
5157ViewCell *VspOspViewCellsManager::GenerateViewCell(Mesh *mesh) const
5158{
5159        return new VspViewCell(mesh);
5160}
5161
5162
5163int VspOspViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
5164                                                                                                 const VssRayContainer &rays)
5165{
5166        mMaxPvsSize = (int)(mMaxPvsRatio * (float)objects.size());
5167
5168        // skip rest if view cells were already constructed
5169        if (ViewCellsConstructed())
5170                return 0;
5171
5172        int sampleContributions = 0;
5173        VssRayContainer sampleRays;
5174
5175        int limit = min (mInitialSamples, (int)rays.size());
5176
5177        VssRayContainer constructionRays;
5178        VssRayContainer savedRays;
5179
5180        Debug << "samples used for vsp bsp subdivision: " << mInitialSamples
5181                  << ", actual rays: " << (int)rays.size() << endl;
5182
5183        GetRaySets(rays, mInitialSamples, constructionRays, &savedRays);
5184
5185        Debug << "initial rays used for construction: " << (int)constructionRays.size() << endl;
5186        Debug << "saved rays: " << (int)savedRays.size() << endl;
5187
5188        mHierarchyManager->Construct(constructionRays, objects, &mViewSpaceBox);
5189
5190#if TEST_EVALUATION
5191        VssRayContainer::const_iterator tit, tit_end = constructionRays.end();
5192        for (tit = constructionRays.begin(); tit != tit_end; ++ tit)
5193        {
5194                storedRays.push_back(new VssRay(*(*tit)));
5195        }
5196#endif
5197
5198        /////////////////////////
5199        //-- print satistics for subdivision and view cells
5200
5201        Debug << endl << endl << *mHierarchyManager << endl;
5202
5203        ResetViewCells();
5204        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
5205
5206        //////////////
5207        //-- recast rest of rays
5208       
5209        const long startTime = GetTime();
5210        cout << "Computing remaining ray contributions ... ";
5211
5212        if (SAMPLE_AFTER_SUBDIVISION)
5213                ComputeSampleContributions(savedRays, true, false);
5214
5215        Debug << "finished computing remaining ray contribution in " << TimeDiff(startTime, GetTime()) * 1e-3
5216                  << " secs" << endl;
5217
5218        if (0)
5219        {       // real meshes are constructed at this stage
5220                cout << "finalizing view cells ... ";
5221                FinalizeViewCells(true);
5222                cout << "finished" << endl;
5223        }
5224
5225        return sampleContributions;
5226}
5227
5228
5229int VspOspViewCellsManager::PostProcess(const ObjectContainer &objects,
5230                                                                                const VssRayContainer &rays)
5231{
5232        if (!ViewCellsConstructed())
5233        {
5234                Debug << "postprocess error: no view cells constructed" << endl;
5235                return 0;
5236        }
5237
5238        // if view cells were already constructed before post processing step
5239        // (e.g., because they were loaded), we are finished
5240        if (mViewCellsFinished)
5241        {
5242                FinalizeViewCells(true);
5243                EvaluateViewCellsStats();
5244
5245                return 0;
5246        }
5247
5248        // check if new view cells turned invalid
5249        int minPvs, maxPvs;
5250
5251        if (0)
5252        {
5253                minPvs = mMinPvsSize;
5254                maxPvs = mMaxPvsSize;
5255        }
5256        else
5257        {
5258                // problem matt: why did I start here from zero?
5259                minPvs = 0;
5260                maxPvs = mMaxPvsSize;
5261        }
5262
5263        Debug << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
5264        cout << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
5265       
5266        SetValidity(minPvs, maxPvs);
5267
5268       
5269        // area is not up to date, has to be recomputed
5270        mTotalAreaValid = false;
5271        VssRayContainer postProcessRays;
5272        GetRaySets(rays, mPostProcessSamples, postProcessRays);
5273
5274        Debug << "post processing using " << (int)postProcessRays.size() << " samples" << endl;
5275
5276
5277        // compute tree by merging the nodes of the spatial hierarchy
5278        ViewCell *root = ConstructSpatialMergeTree(mHierarchyManager->GetVspTree()->GetRoot());
5279        mViewCellsTree->SetRoot(root);
5280
5281        //////////////////////////
5282        //-- update pvs up to the root of the hierarchy
5283
5284        ObjectPvs pvs;
5285        UpdatePvsForEvaluation(root, pvs);
5286
5287
5288        //////////////////////
5289        //-- render simulation after merge + refine
5290
5291        cout << "\nview cells partition render time before compress" << endl << endl;
5292        dynamic_cast<RenderSimulator *>(mRenderer)->RenderScene();
5293        SimulationStatistics ss;
5294        dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
5295        cout << ss << endl;
5296       
5297
5298        ///////////
5299        //-- compression
5300
5301        if (ViewCellsTreeConstructed() && mCompressViewCells)
5302        {
5303                int pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
5304                Debug << "number of entries before compress: " << pvsEntries << endl;
5305
5306                mViewCellsTree->SetViewCellsStorage(ViewCellsTree::COMPRESSED);
5307
5308                pvsEntries = mViewCellsTree->CountStoredPvsEntries(mViewCellsTree->GetRoot());
5309                Debug << "number of entries after compress: " << pvsEntries << endl;
5310        }
5311
5312        /////////////
5313        //-- some tasks still to do on the view cells:
5314        //-- Compute meshes from view cell geometry, evaluate volume and / or area
5315
5316        if (1) FinalizeViewCells(true);
5317
5318        return 0;
5319}
5320
5321
5322int VspOspViewCellsManager::GetType() const
5323{
5324        return VSP_OSP;
5325}
5326
5327
5328ViewCell *VspOspViewCellsManager::ConstructSpatialMergeTree(VspNode *root)
5329{
5330        // terminate recursion
5331        if (root->IsLeaf())
5332        {
5333                VspLeaf *leaf = dynamic_cast<VspLeaf *>(root);
5334                leaf->GetViewCell()->SetMergeCost(0.0f);
5335                return leaf->GetViewCell();
5336        }
5337       
5338        VspInterior *interior = dynamic_cast<VspInterior *>(root);
5339        ViewCellInterior *viewCellInterior = new ViewCellInterior();
5340               
5341        // evaluate merge cost for priority traversal
5342        const float mergeCost = -(float)root->mTimeStamp;
5343        viewCellInterior->SetMergeCost(mergeCost);
5344
5345        float volume = 0;
5346       
5347        VspNode *front = interior->GetFront();
5348        VspNode *back = interior->GetBack();
5349
5350        ObjectPvs frontPvs, backPvs;
5351
5352        /////////
5353        //-- recursivly compute child hierarchies
5354
5355        ViewCell *backVc = ConstructSpatialMergeTree(back);
5356        ViewCell *frontVc = ConstructSpatialMergeTree(front);
5357
5358        viewCellInterior->SetupChildLink(backVc);
5359        viewCellInterior->SetupChildLink(frontVc);
5360
5361        volume += backVc->GetVolume();
5362        volume += frontVc->GetVolume();
5363
5364        viewCellInterior->SetVolume(volume);
5365
5366        return viewCellInterior;
5367}
5368
5369
5370bool VspOspViewCellsManager::GetViewPoint(Vector3 &viewPoint) const
5371{
5372        if (!ViewCellsConstructed())
5373                return ViewCellsManager::GetViewPoint(viewPoint);
5374
5375        // TODO: set reasonable limit
5376        const int limit = 20;
5377
5378        for (int i = 0; i < limit; ++ i)
5379        {
5380                viewPoint = mViewSpaceBox.GetRandomPoint();
5381
5382                if (mHierarchyManager->GetVspTree()->ViewPointValid(viewPoint))
5383                {
5384                        return true;
5385                }
5386        }
5387
5388        Debug << "failed to find valid view point, taking " << viewPoint << endl;
5389        return false;
5390}
5391
5392
5393void VspOspViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
5394                                                                                                        ViewCell *vc,
5395                                                                                                        const AxisAlignedBox3 *sceneBox,
5396                                                                                                        const AxisAlignedPlane *clipPlane
5397                                                                                                        ) const
5398{
5399        ViewCellContainer leaves;
5400        mViewCellsTree->CollectLeaves(vc, leaves);
5401        ViewCellContainer::const_iterator it, it_end = leaves.end();
5402
5403        Plane3 plane;
5404        if (clipPlane)
5405        {
5406                // arbitrary plane definition
5407                plane = clipPlane->GetPlane();
5408        }
5409
5410        for (it = leaves.begin(); it != it_end; ++ it)
5411        {
5412                VspViewCell *vspVc = dynamic_cast<VspViewCell *>(*it);
5413                VspLeaf *l = vspVc->mLeaves[0];
5414
5415                const AxisAlignedBox3 box =
5416                        mHierarchyManager->GetVspTree()->GetBoundingBox(vspVc->mLeaves[0]);
5417               
5418                if (sceneBox && !Overlap(*sceneBox, box))
5419                        continue;
5420
5421                if (clipPlane)
5422                {
5423                        if (box.Side(plane) == -1)
5424                        {
5425                                exporter->ExportBox(box);
5426                        }
5427                        else if (box.Side(plane) == 0)
5428                        {
5429                                // intersection
5430                                AxisAlignedBox3 fbox, bbox;
5431                                box.Split(clipPlane->mAxis, clipPlane->mPosition, fbox, bbox);
5432                                exporter->ExportBox(bbox);
5433                        }
5434                }
5435                else
5436                {
5437                        exporter->ExportBox(box);
5438                }
5439        }
5440}
5441
5442
5443bool VspOspViewCellsManager::ViewPointValid(const Vector3 &viewPoint) const
5444{
5445  // $$JB -> implemented in viewcellsmanager (slower, but allows dynamic
5446  // validy update in preprocessor for all managers)
5447  return ViewCellsManager::ViewPointValid(viewPoint);
5448
5449  //    return mViewSpaceBox.IsInside(viewPoint) &&
5450  //               mVspTree->ViewPointValid(viewPoint);
5451}
5452
5453
5454void VspOspViewCellsManager::Visualize(const ObjectContainer &objects,
5455                                                                           const VssRayContainer &sampleRays)
5456{
5457        if (!ViewCellsConstructed())
5458                return;
5459
5460        VssRayContainer visRays;
5461        GetRaySets(sampleRays, mVisualizationSamples, visRays);
5462
5463        ////////////
5464        //-- export final view cells
5465
5466        Exporter *exporter = Exporter::GetExporter("final_view_cells.wrl");
5467
5468        if (exporter)
5469        {
5470                // hack color code (show pvs size)
5471                const int savedColorCode = mColorCode;
5472                mColorCode = 0;
5473
5474                const long starttime = GetTime();
5475                cout << "exporting final view cells (after initial construction + post process) ... ";
5476
5477                // matt: hack for clamping scene
5478                AxisAlignedBox3 bbox = mViewSpaceBox;
5479                bbox.Scale(Vector3(0.5, 1, 0.5));
5480
5481                if (CLAMP_TO_BOX)
5482                {       
5483                        exporter->SetWireframe();
5484                        exporter->ExportBox(bbox);
5485                        exporter->SetFilled();
5486                }
5487
5488                if (0 && mExportGeometry)
5489                {
5490                        exporter->ExportGeometry(objects, true, CLAMP_TO_BOX ? &bbox : NULL);
5491                }
5492
5493                if (1 && mExportRays)
5494                {       
5495                        exporter->ExportRays(visRays, RgbColor(0, 1, 0));
5496                }
5497
5498                mHierarchyManager->ExportObjectSpaceHierarchy(exporter, objects,
5499                                                                                                          CLAMP_TO_BOX ? &bbox : NULL, false);
5500                ExportViewCellsForViz(exporter, CLAMP_TO_BOX ? &bbox : NULL, mColorCode, GetClipPlane());
5501
5502                delete exporter;
5503
5504                cout << "finished in " << TimeDiff(starttime, GetTime()) * 1e-3f << " secs" << endl;
5505                mColorCode = savedColorCode;
5506        }
5507
5508        // export final object partition
5509        exporter = Exporter::GetExporter("final_object_partition.wrl");
5510
5511        if (exporter)
5512        {
5513                const long starttime = GetTime();
5514
5515                // matt: hack for making visualization smaller in size
5516                AxisAlignedBox3 bbox = mHierarchyManager->GetObjectSpaceBox();
5517                bbox.Scale(Vector3(0.5, 1, 0.5));
5518
5519                cout << "exporting object space hierarchy ... ";
5520                mHierarchyManager->ExportObjectSpaceHierarchy(exporter, objects, CLAMP_TO_BOX ? &bbox : NULL);
5521
5522                delete exporter;
5523                cout << "finished in " << TimeDiff(starttime, GetTime()) * 1e-3f << " secs" << endl;
5524        }
5525       
5526        cout << "here92 " << mHierarchyManager->GetVspTree()->GetStatistics().maxPvs << endl;
5527
5528        // visualization of the view cells
5529    if (1)
5530        {       
5531                EvaluateViewCellsStats();
5532                ExportMergedViewCells(objects);
5533        }
5534
5535        // export some view cell
5536        int leafOut;
5537        Environment::GetSingleton()->GetIntValue("ViewCells.Visualization.maxOutput", leafOut);
5538        const int raysOut = 100;
5539
5540        ExportSingleViewCells(objects, leafOut, false, true, false, raysOut, "");
5541}
5542
5543
5544void VspOspViewCellsManager::ExportSingleViewCells(const ObjectContainer &objects,
5545                                                                                                   const int maxViewCells,
5546                                                                                                   const bool sortViewCells,
5547                                                                                                   const bool exportPvs,
5548                                                                                                   const bool exportRays,
5549                                                                                                   const int maxRays,
5550                                                                                                   const string prefix,
5551                                                                                                   VssRayContainer *visRays)
5552{
5553        if (sortViewCells)
5554        {
5555                // sort view cells to visualize the view cells with highest render cost
5556                stable_sort(mViewCells.begin(), mViewCells.end(), ViewCell::LargerRenderCost);
5557        }
5558
5559        ViewCell::NewMail();
5560        const int limit = min(maxViewCells, (int)mViewCells.size());
5561       
5562        cout << "\nExporting " << limit << " single view cells: " << endl;
5563       
5564        for (int i = 0; i < limit; ++ i)
5565        {
5566                cout << "creating output for view cell " << i << " ... ";
5567               
5568                // largest view cell pvs first of random view cell
5569                ViewCell *vc = sortViewCells ?
5570                        mViewCells[i] : mViewCells[(int)RandomValue(0, (float)mViewCells.size() - 1)];
5571               
5572                if (vc->Mailed()) // already used
5573                        continue;
5574
5575                vc->Mail();
5576
5577                ObjectPvs pvs;
5578                mViewCellsTree->GetPvs(vc, pvs);
5579
5580                char s[64]; sprintf(s, "%sviewcell%04d.wrl", prefix.c_str(), i);
5581                Exporter *exporter = Exporter::GetExporter(s);
5582               
5583                cout << "view cell " << vc->GetId() << ": pvs cost=" << mViewCellsTree->GetPvsCost(vc) << endl;
5584
5585                if (exportPvs)
5586                {
5587                        Material m;
5588
5589                        Intersectable::NewMail();
5590                       
5591                        ObjectPvsIterator pit = pvs.GetIterator();
5592
5593                        // output PVS of view cell
5594                        while (pit.HasMoreEntries())
5595                        {               
5596                                ObjectPvsEntry entry = pit.Next();
5597                               
5598                                Intersectable *intersect = entry.mObject;
5599
5600                                if (!intersect->Mailed())
5601                                {
5602                                        m = RandomMaterial();
5603                                        exporter->SetForcedMaterial(m);
5604
5605                                        exporter->ExportIntersectable(intersect);
5606                                        intersect->Mail();
5607                                }
5608                        }
5609                }
5610
5611                if (exportRays)
5612                {
5613                        ////////////
5614                        //-- export the sample rays
5615
5616                        // output rays stored with the view cells during subdivision
5617                        VssRayContainer vcRays;
5618                        VssRayContainer collectRays;
5619
5620                        // collect intial view cells
5621                        ViewCellContainer leaves;
5622                        mViewCellsTree->CollectLeaves(vc, leaves);
5623
5624                        ViewCellContainer::const_iterator vit, vit_end = leaves.end();
5625
5626                        for (vit = leaves.begin(); vit != vit_end; ++ vit)
5627                        {
5628                                VspLeaf *vcLeaf = dynamic_cast<VspViewCell *>(*vit)->mLeaves[0];
5629                                VssRayContainer::const_iterator rit, rit_end = vcLeaf->mVssRays.end();
5630
5631                                for (rit = vcLeaf->mVssRays.begin(); rit != rit_end; ++ rit)
5632                                {
5633                                        collectRays.push_back(*rit);
5634                                }
5635                        }
5636
5637                        const int raysOut = min((int)collectRays.size(), maxRays);
5638
5639                        VssRayContainer::const_iterator rit, rit_end = collectRays.end();
5640
5641                        for (rit = collectRays.begin(); rit != rit_end; ++ rit)
5642                        {
5643                                const float p = RandomValue(0.0f, (float)collectRays.size());
5644
5645                                if (p < raysOut)
5646                                        vcRays.push_back(*rit);
5647                        }
5648
5649                        exporter->ExportRays(vcRays, RgbColor(1, 1, 1));
5650                }
5651               
5652       
5653                /////////////////
5654                //-- export view cell geometry
5655
5656                exporter->SetWireframe();
5657
5658                Material m;
5659                m.mDiffuseColor = RgbColor(0, 1, 0);
5660                exporter->SetForcedMaterial(m);
5661
5662                ExportViewCellGeometry(exporter, vc, NULL, NULL);
5663                exporter->SetFilled();
5664
5665                DEL_PTR(exporter);
5666                cout << "finished" << endl;
5667        }
5668
5669        cout << endl;
5670}
5671
5672
5673int VspOspViewCellsManager::ComputeBoxIntersections(const AxisAlignedBox3 &box,
5674                                                                                                        ViewCellContainer &viewCells) const
5675{
5676        return mHierarchyManager->GetVspTree()->ComputeBoxIntersections(box, viewCells);
5677}
5678
5679
5680int VspOspViewCellsManager::CastLineSegment(const Vector3 &origin,
5681                                                                                        const Vector3 &termination,
5682                                                                                        ViewCellContainer &viewcells)
5683{
5684        return mHierarchyManager->GetVspTree()->CastLineSegment(origin, termination, viewcells);
5685}
5686
5687
5688bool VspOspViewCellsManager::ExportViewCells(const string filename,
5689                                                                                         const bool exportPvs,
5690                                                                                         const ObjectContainer &objects)
5691{
5692        if (!ViewCellsConstructed() || !ViewCellsTreeConstructed())
5693                return false;
5694
5695        const long starttime = GetTime();
5696        cout << "exporting view cells to xml ... ";
5697       
5698        OUT_STREAM stream(filename.c_str());
5699
5700        // for output we need unique ids for each view cell
5701        CreateUniqueViewCellIds();
5702
5703        stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<endl;
5704        stream << "<VisibilitySolution>" << endl;
5705
5706        if (exportPvs)
5707        {
5708        ///////////////
5709                //-- export bounding boxes
5710                //-- The bounding boxes are used to identify
5711                //-- the objects in the rendering engine
5712                mHierarchyManager->ExportBoundingBoxes(stream, objects);
5713        }
5714
5715        //////////////////////////
5716        //-- export the view cells and the pvs
5717
5718        const int numViewCells = mCurrentViewCellsStats.viewCells;
5719
5720        stream << "<ViewCells number=\"" << numViewCells << "\" >" << endl;
5721        mViewCellsTree->Export(stream, exportPvs);
5722        stream << "</ViewCells>" << endl;
5723
5724        //////////////////////
5725        //-- export the view space hierarchy
5726       
5727        stream << "<ViewSpaceHierarchy type=\"vsp\""
5728                   << " min=\"" << mViewSpaceBox.Min().x << " " << mViewSpaceBox.Min().y << " " << mViewSpaceBox.Min().z << "\""
5729                   << " max=\"" << mViewSpaceBox.Max().x << " " << mViewSpaceBox.Max().y << " " << mViewSpaceBox.Max().z << "\">" << endl;
5730
5731        mHierarchyManager->GetVspTree()->Export(stream);
5732        stream << "</ViewSpaceHierarchy>" << endl;
5733
5734        ////////////////////// 
5735        //-- export the object space partition
5736       
5737        mHierarchyManager->ExportObjectSpaceHierarchy(stream);
5738       
5739        stream << "</VisibilitySolution>" << endl;
5740        stream.close();
5741       
5742        cout << "finished in " << TimeDiff(starttime, GetTime()) * 1e-3 << " secs" << endl;
5743        return true;
5744}
5745
5746
5747
5748ViewCell *VspOspViewCellsManager::GetViewCell(const Vector3 &point,
5749                                                                                          const bool active) const
5750{
5751        if (!ViewCellsConstructed())
5752                return NULL;
5753
5754        if (!mViewSpaceBox.IsInside(point))
5755                return NULL;
5756
5757        return mHierarchyManager->GetVspTree()->GetViewCell(point, active);
5758}
5759
5760
5761void VspOspViewCellsManager::CreateMesh(ViewCell *vc)
5762{
5763        // matt: TODO
5764        Mesh *mesh = MeshManager::GetSingleton()->CreateResource();
5765
5766        ViewCellContainer leaves;
5767        mViewCellsTree->CollectLeaves(vc, leaves);
5768
5769        ViewCellContainer::const_iterator it, it_end = leaves.end();
5770
5771    for (it = leaves.begin(); it != it_end; ++ it)
5772        {
5773                VspLeaf *leaf = dynamic_cast<VspViewCell *>(*it)->mLeaves[0];
5774                const AxisAlignedBox3 box = mHierarchyManager->GetVspTree()->GetBoundingBox(leaf);
5775        IncludeBoxInMesh(box, *mesh);
5776        }
5777
5778        vc->SetMesh(mesh);
5779}
5780
5781
5782int VspOspViewCellsManager::CastBeam(Beam &beam)
5783{
5784        // matt: TODO
5785        return 0;
5786}
5787
5788
5789void VspOspViewCellsManager::Finalize(ViewCell *viewCell, const bool createMesh)
5790{
5791        float area = 0;
5792        float volume = 0;
5793
5794        ViewCellContainer leaves;
5795        mViewCellsTree->CollectLeaves(viewCell, leaves);
5796
5797        ViewCellContainer::const_iterator it, it_end = leaves.end();
5798
5799    for (it = leaves.begin(); it != it_end; ++ it)
5800        {
5801                VspLeaf *leaf = dynamic_cast<VspViewCell *>(*it)->mLeaves[0];
5802               
5803                const AxisAlignedBox3 box = mHierarchyManager->GetVspTree()->GetBoundingBox(leaf);
5804
5805                const float lVol = box.GetVolume();
5806                const float lArea = box.SurfaceArea();
5807
5808                area += lArea;
5809                volume += lVol;
5810
5811        CreateMesh(*it);
5812        }
5813
5814        viewCell->SetVolume(volume);
5815        viewCell->SetArea(area);
5816}
5817       
5818
5819float VspOspViewCellsManager::ComputeSampleContribution(VssRay &ray,
5820                                                                                                                const bool addRays,
5821                                                                                                                const bool storeViewCells)
5822{
5823        ViewCellContainer viewcells;
5824
5825        ray.mPvsContribution = 0;
5826        ray.mRelativePvsContribution = 0.0f;
5827
5828        static Ray hray;
5829        hray.Init(ray);
5830        //hray.mFlags |= Ray::CULL_BACKFACES;
5831        //Ray hray(ray);
5832
5833        float tmin = 0, tmax = 1.0;
5834
5835        if (!GetViewSpaceBox().GetRaySegment(hray, tmin, tmax) || (tmin > tmax))
5836                return 0;
5837
5838        Vector3 origin = hray.Extrap(tmin);
5839        Vector3 termination = hray.Extrap(tmax);
5840
5841        ViewCell::NewMail();
5842
5843        // traverse the view space subdivision
5844        CastLineSegment(origin, termination, viewcells);
5845
5846        if (storeViewCells)
5847        {       
5848                // copy viewcells memory efficiently
5849                ray.mViewCells.reserve(viewcells.size());
5850                ray.mViewCells = viewcells;
5851        }
5852
5853        ViewCellContainer::const_iterator it = viewcells.begin();
5854
5855        for (; it != viewcells.end(); ++ it)
5856        {
5857                ViewCell *viewcell = *it;
5858
5859                if (viewcell->GetValid())
5860                {       // if ray not outside of view space
5861                        float contribution;
5862
5863                        if (ray.mTerminationObject)
5864                        {
5865                                // todo: maybe not correct for kd node pvs
5866                                Intersectable *obj = mHierarchyManager->GetIntersectable(ray, true);
5867
5868                                if (viewcell->GetPvs().GetSampleContribution(obj,
5869                                        ray.mPdf,
5870                                        contribution))
5871                                {
5872                                        ++ ray.mPvsContribution;
5873                                }
5874
5875                                ray.mRelativePvsContribution += contribution;
5876                        }
5877
5878                        ////////////////
5879                        //-- for directional sampling it is important to count only contributions
5880                        //-- made in one direction!
5881                        //-- the other contributions of this sample will be counted for the opposite ray!
5882#if SAMPLE_ORIGIN_OBJECTS
5883                        if (ray.mOriginObject &&
5884                                viewcell->GetPvs().GetSampleContribution(ray.mOriginObject,
5885                                ray.mPdf,
5886                                contribution))
5887                        {
5888                                ++ ray.mPvsContribution;
5889                                ray.mRelativePvsContribution += contribution;
5890                        }
5891#endif
5892                }
5893        }
5894
5895        if (!addRays)
5896        {
5897                return ray.mRelativePvsContribution;
5898        }
5899
5900        // sampled objects are stored in the pvs
5901        for (it = viewcells.begin(); it != viewcells.end(); ++ it)
5902        {
5903                ViewCell *viewCell = *it;
5904
5905                if (!viewCell->GetValid())
5906                        break;
5907
5908                AddSampleToPvs(
5909                        ray.mTerminationObject,
5910                        ray.mTermination,
5911                        viewCell,
5912                        ray.mPdf,
5913                        ray.mRelativePvsContribution);
5914
5915#if SAMPLE_ORIGIN_OBJECTS
5916
5917                AddSampleToPvs(
5918                        ray.mOriginObject,
5919                        ray.mOrigin,
5920                        viewCell,
5921                        ray.mPdf,
5922                        ray.mRelativePvsContribution);
5923#endif                 
5924        }
5925
5926       
5927
5928        return ABS_CONTRIBUTION_WEIGHT*ray.mPvsContribution +
5929          (1.0f - ABS_CONTRIBUTION_WEIGHT)*ray.mRelativePvsContribution;
5930}
5931
5932
5933bool VspOspViewCellsManager::AddSampleToPvs(Intersectable *obj,
5934                                                                                        const Vector3 &hitPoint,
5935                                                                                        ViewCell *vc,
5936                                                                                        const float pdf,
5937                                                                                        float &contribution) const
5938{
5939        // The hierarchy manager decides about the type of sample cast
5940        return mHierarchyManager->AddSampleToPvs(obj, hitPoint, vc, pdf, contribution);
5941}
5942
5943
5944void VspOspViewCellsManager::PrepareLoadedViewCells()
5945{
5946        // TODO
5947}
5948
5949
5950ViewCellsManager *VspOspViewCellsManager::LoadViewCells(const string &filename,
5951                                                                                                                ObjectContainer *objects,
5952                                                                                                                const bool finalizeViewCells,
5953                                                                                                                BoundingBoxConverter *bconverter)
5954                                                                                                 
5955{
5956        ViewCellsManager *vm =
5957                ViewCellsManager::LoadViewCells(filename, objects, finalizeViewCells, bconverter);
5958#if 0
5959        // insert scene objects in tree
5960        mOspTree->InsertObjects(mOspTree->GetRoot(), *objects);
5961#endif
5962        return vm;
5963}
5964
5965void
5966VspOspViewCellsManager::CollectObjects(const AxisAlignedBox3 &box, ObjectContainer &objects)
5967{
5968  mHierarchyManager->CollectObjects(box, objects);
5969}
5970
5971
5972#if 1
5973
5974void VspOspViewCellsManager::EvalViewCellPartition()
5975{
5976        int samplesPerPass;
5977        int numSamples;
5978        int castSamples = 0;
5979        int oldSamples = 0;
5980        int samplesForStats;
5981        char statsPrefix[100];
5982        char suffix[100];
5983        int splitsStepSize;
5984
5985
5986        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesPerPass", samplesPerPass);
5987        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samplesForStats", samplesForStats);
5988        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.samples", numSamples);
5989        Environment::GetSingleton()->GetStringValue("ViewCells.Evaluation.statsPrefix", statsPrefix);
5990        Environment::GetSingleton()->GetIntValue("ViewCells.Evaluation.stepSize", splitsStepSize);
5991       
5992        Debug << "step size: " << splitsStepSize << endl;
5993        Debug << "view cell evaluation samples per pass: " << samplesPerPass << endl;
5994        Debug << "view cell evaluation samples: " << numSamples << endl;
5995        Debug << "view cell stats prefix: " << statsPrefix << endl;
5996
5997        // should directional sampling be used?
5998        bool dirSamples =
5999                (mEvaluationSamplingType == SamplingStrategy::DIRECTION_BASED_DISTRIBUTION);
6000
6001        cout << "reseting pvs ... ";
6002               
6003        // reset pvs and start over from zero
6004        mViewCellsTree->ResetPvs();
6005       
6006        cout << "finished" << endl;
6007    cout << "Evaluating view cell partition ... " << endl;
6008
6009        while (castSamples < numSamples)
6010        {               
6011                ///////////////
6012                //-- we have to use uniform sampling strategy for construction rays
6013
6014                VssRayContainer evaluationSamples;
6015                const int samplingType = mEvaluationSamplingType;
6016
6017                long startTime = GetTime();
6018
6019                cout << "casting " << samplesPerPass << " samples ... ";
6020                Debug << "casting " << samplesPerPass << " samples ... ";
6021
6022                CastPassSamples(samplesPerPass, samplingType, evaluationSamples);
6023               
6024                castSamples += samplesPerPass;
6025
6026                Real timeDiff = TimeDiff(startTime, GetTime());
6027               
6028                cout << "finished in " << timeDiff * 1e-3f << " secs" << endl;
6029                cout << "computing sample contributions of " << (int)evaluationSamples.size()  << " samples ... ";
6030               
6031                Debug << "finished in " << timeDiff * 1e-3f << " secs" << endl;
6032                Debug << "computing sample contributions of " << (int)evaluationSamples.size()  << " samples ... ";
6033
6034                startTime = GetTime();
6035
6036                ComputeSampleContributions(evaluationSamples, true, false);
6037
6038                timeDiff = TimeDiff(startTime, GetTime());
6039                cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
6040                Debug << "finished in " << timeDiff * 1e-3 << " secs" << endl;
6041
6042                if ((castSamples >= samplesForStats + oldSamples) ||
6043                        (castSamples >= numSamples))
6044                {
6045                        oldSamples += samplesForStats;
6046
6047                        ///////////
6048                        //-- output stats
6049
6050                        sprintf(suffix, "-%09d-eval.log", castSamples);
6051                        const string filename = string(statsPrefix) + string(suffix);
6052
6053                        startTime = GetTime();
6054                       
6055                        cout << "compute new statistics ... " << endl;
6056
6057                        ofstream ofstr(filename.c_str());
6058                        mHierarchyManager->EvaluateSubdivision2(ofstr, splitsStepSize, false);
6059
6060                        timeDiff = TimeDiff(startTime, GetTime());
6061                        cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
6062                        cout << "*************************************" << endl;
6063
6064                        Debug << "statistics computed in " << timeDiff * 1e-3 << " secs" << endl;
6065
6066#if 0
6067                        ////////////////////////////
6068                        // filtered stats
6069                        sprintf(suffix, "-%09d-eval-filter.log", castSamples);
6070                        const string filename2 = string(statsPrefix) + string(suffix);
6071
6072                        startTime = GetTime();
6073                       
6074                        cout << "compute new statistics for filtered pvs ... " << endl;
6075
6076                        ofstream ofstr2(filename2.c_str());
6077                        mHierarchyManager->EvaluateSubdivision2(ofstr2, splitsStepSize, true);
6078
6079                        timeDiff = TimeDiff(startTime, GetTime());
6080                        cout << "finished in " << timeDiff * 1e-3 << " secs" << endl;
6081                        cout << "*************************************" << endl;
6082
6083                        Debug << "statistics computed in " << timeDiff * 1e-3 << " secs" << endl;
6084#endif
6085
6086                        // only for debugging purpose
6087                        if (0)
6088                        {
6089                                ViewCellContainer viewCells;
6090                                mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), viewCells);
6091
6092                                ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
6093                                int pvsSize = 0;
6094
6095                                for (vit = viewCells.begin(); vit != vit_end; ++ vit)
6096                                {
6097                                        pvsSize += (*vit)->GetPvs().GetSize();
6098                                }
6099
6100                                cout << "debug entries: " << pvsSize << ", memcost: " << (float)pvsSize * ObjectPvs::GetEntrySize() << endl;
6101                        }
6102                }
6103
6104                disposeRays(evaluationSamples, NULL);
6105        }
6106       
6107}
6108#endif
6109}
Note: See TracBrowser for help on using the repository browser.