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

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