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

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