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

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