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

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