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

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