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

Revision 1761, 156.1 KB checked in by bittner, 18 years ago (diff)

filter updates, kd + bvh PVS coexistence

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