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

Revision 1989, 167.2 KB checked in by bittner, 17 years ago (diff)

mutation updates

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