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

Revision 1919, 160.1 KB checked in by mattausch, 17 years ago (diff)

added mechanism for histogram on certain MB in hierarchymanager
no more bug in undersampling estimation
added sampling strategy to spatial box based (also for eval)
added testing scripts

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