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

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