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

Revision 752, 113.3 KB checked in by mattausch, 18 years ago (diff)

after rendering workshop submissioin
x3dparser can use def - use constructs
implemented improved evaluation (samples are only stored in leaves, only propagate pvs size)

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"
10#include "VspKdTree.h"
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"
[440]17
[712]18// HACK
19const static bool SAMPLE_AFTER_SUBDIVISION = true;
20const static bool TEST_EMPTY_VIEW_CELLS = false;
[517]21
[697]22
23
24template <typename T> class myless
25{
26public:
27        //bool operator() (HierarchyNode *v1, HierarchyNode *v2) const
28        bool operator() (T v1, T v2) const
29        {
30                return (v1->GetMergeCost() < v2->GetMergeCost());
31        }
32};
33
[706]34//typedef priority_queue<ViewCell *, vector<ViewCell *>, myless<vector<ViewCell *>::value_type> > FilterQueue;
[697]35
36
37
[440]38ViewCellsManager::ViewCellsManager():
[480]39mRenderer(NULL),
[574]40mInitialSamples(0),
[440]41mConstructionSamples(0),
42mPostProcessSamples(0),
[470]43mVisualizationSamples(0),
44mTotalAreaValid(false),
[517]45mTotalArea(0.0f),
[547]46mViewCellsFinished(false),
[562]47mMaxPvsSize(9999999),
[564]48mMinPvsSize(0), // one means only empty view cells are invalid
[719]49mMaxPvsRatio(1.0),
50mViewCellPvsIsUpdated(false)
[440]51{
[542]52        mViewSpaceBox.Initialize();
[482]53        ParseEnvironment();
[580]54
55        mViewCellsTree = new ViewCellsTree(this);
[440]56}
57
[517]58
[482]59void ViewCellsManager::ParseEnvironment()
60{
[503]61        // visualization stuff
[485]62        environment->GetBoolValue("ViewCells.Visualization.exportRays", mExportRays);
63        environment->GetBoolValue("ViewCells.Visualization.exportGeometry", mExportGeometry);
[547]64        environment->GetFloatValue("ViewCells.maxPvsRatio", mMaxPvsRatio);
[664]65       
[710]66        environment->GetBoolValue("ViewCells.pruneEmptyViewCells", mPruneEmptyViewCells);
[664]67
[710]68        // HACK
69        if (0)
70                mMinPvsSize = mPruneEmptyViewCells ? 1 : 0;
71        else
72                mMinPvsSize = 0;
73
[564]74        environment->GetBoolValue("ViewCells.processOnlyValidViewCells", mOnlyValidViewCells);
[485]75
[574]76        environment->GetIntValue("ViewCells.Construction.samples", mConstructionSamples);
77        environment->GetIntValue("ViewCells.PostProcess.samples", mPostProcessSamples);
[595]78        environment->GetBoolValue("ViewCells.PostProcess.useRaysForMerge", mUseRaysForMerge);
79
[574]80        environment->GetIntValue("ViewCells.Visualization.samples", mVisualizationSamples);
81
82        environment->GetIntValue("ViewCells.Construction.samplesPerPass", mSamplesPerPass);
[577]83        environment->GetBoolValue("ViewCells.exportToFile", mExportViewCells);
[581]84       
[600]85        environment->GetIntValue("ViewCells.active", mNumActiveViewCells);
[586]86        environment->GetBoolValue("ViewCells.PostProcess.compress", mCompressViewCells);
[660]87        environment->GetBoolValue("ViewCells.Visualization.useClipPlane", mUseClipPlaneForViz);
[591]88        environment->GetBoolValue("ViewCells.PostProcess.merge", mMergeViewCells);
[664]89        environment->GetBoolValue("ViewCells.evaluateViewCells", mEvaluateViewCells);
[666]90        environment->GetBoolValue("ViewCells.showVisualization", mShowVisualization);
[697]91        environment->GetIntValue("ViewCells.Filter.maxSize", mMaxFilterSize);
92        environment->GetFloatValue("ViewCells.Filter.width", mFilterWidth);
[734]93        environment->GetIntValue("ViewCells.renderCostEvaluationType", mRenderCostEvaluationType);
[710]94
[664]95        char buf[100];
96        environment->GetStringValue("ViewCells.samplingType", buf);
97
[660]98       
[664]99        if (strcmp(buf, "box") == 0)
[722]100        {
[660]101                mSamplingType = Preprocessor::SPATIAL_BOX_BASED_DISTRIBUTION;
[722]102        }
[664]103        else if (strcmp(buf, "directional") == 0)
[722]104        {
[660]105                mSamplingType = Preprocessor::DIRECTION_BASED_DISTRIBUTION;
[722]106        }
[666]107        else
108        {
109                Debug << "error! wrong sampling type" << endl;
110                exit(0);
111        }
[660]112
[722]113        environment->GetStringValue("ViewCells.Evaluation.samplingType", buf);
114       
115        if (strcmp(buf, "box") == 0)
116        {
117                mEvaluationSamplingType = Preprocessor::SPATIAL_BOX_BASED_DISTRIBUTION;
118        }
119        else if (strcmp(buf, "directional") == 0)
120        {
121                mEvaluationSamplingType = Preprocessor::DIRECTION_BASED_DISTRIBUTION;
122        }
123        else
124        {
125                Debug << "error! wrong sampling type" << endl;
126                exit(0);
127        }
[503]128
[728]129        environment->GetStringValue("ViewCells.renderCostEvaluationType", buf);
130       
[734]131        if (strcmp(buf, "perobject") == 0)
[728]132        {
133                mRenderCostEvaluationType = ViewCellsManager::PER_OBJECT;
134        }
135        else if (strcmp(buf, "directional") == 0)
136        {
137                mRenderCostEvaluationType = ViewCellsManager::PER_TRIANGLE;
138        }
139        else
140        {
141                Debug << "error! wrong sampling type" << endl;
142                exit(0);
143        }
144
[722]145    environment->GetStringValue("ViewCells.Visualization.colorCode", buf);
146
[482]147        if (strcmp(buf, "PVS") == 0)
148                mColorCode = 1;
149        else if (strcmp(buf, "MergedLeaves") == 0)
150                mColorCode = 2;
151        else if (strcmp(buf, "MergedTreeDiff") == 0)
152                mColorCode = 3;
153        else
154                mColorCode = 0;
155
[664]156
[710]157
[664]158        Debug << "***********View Cells options ****************" << endl;
159        Debug << "color code: " << mColorCode << endl;
160
161        Debug << "export rays: " << mExportRays << endl;
162        Debug << "export geometry: " << mExportGeometry << endl;
163        Debug << "max pvs ratio: " << mMaxPvsRatio << endl;
164       
[710]165        Debug << "prune empty view cells: " << mPruneEmptyViewCells << endl;
[664]166       
167        Debug << "process only valid view cells: " << mOnlyValidViewCells << endl;
168        Debug << "construction samples: " << mConstructionSamples << endl;
169        Debug << "post process samples: " << mPostProcessSamples << endl;
170        Debug << "post process use rays for merge: " << mUseRaysForMerge << endl;
171        Debug << "visualization samples: " << mVisualizationSamples << endl;
172        Debug << "construction samples per pass: " << mSamplesPerPass << endl;
173        Debug << "export to file: " << mExportViewCells << endl;
174       
175        Debug << "active: " << mNumActiveViewCells << endl;
176        Debug << "post process compress: " << mCompressViewCells << endl;
177        Debug << "visualization use clipPlane: " << mUseClipPlaneForViz << endl;
178        Debug << "post process merge: " << mMergeViewCells << endl;
179        Debug << "evaluate view cells: " << mEvaluateViewCells << endl;
180        Debug << "sampling type: " << mSamplingType << endl;
[728]181        Debug << "render cost evaluation type" << mRenderCostEvaluationType << endl;
182        Debug << "evaluation sampling type: " << mEvaluationSamplingType << endl;
[666]183        Debug << "show visualization: " << mShowVisualization << endl;
[697]184        Debug << "filter width: " << mFilterWidth << endl;
[710]185        Debug << "sample after subdivision: " << SAMPLE_AFTER_SUBDIVISION << endl;
[664]186        Debug << endl;
[440]187}
188
[485]189
[440]190ViewCellsManager::~ViewCellsManager()
191{
[480]192        DEL_PTR(mRenderer);
[580]193
[598]194        if (!ViewCellsTreeConstructed())
195                CLEAR_CONTAINER(mViewCells);
196        else
197                DEL_PTR(mViewCellsTree);
198
[503]199        CLEAR_CONTAINER(mMeshContainer);
[440]200}
201
[485]202
[693]203void ViewCellsManager::CollectEmptyViewCells()
204{
205        mEmptyViewCells.clear();
206        ViewCellContainer leaves;
207        mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
208
209        ViewCellContainer::const_iterator it, it_end = leaves.end();
210
211        cout << "collecting empty view cells" << endl;
[694]212       
[693]213        for (it = leaves.begin(); it != it_end; ++ it)
214        {
215                if ((*it)->GetPvs().Empty())
216                {
217                        mEmptyViewCells.push_back(*it);
218                }
219        }
[694]220        Debug << "empty view cells found: " << (int)mEmptyViewCells.size() << endl;
[693]221}
222
223
[694]224void ViewCellsManager::TestEmptyViewCells(const ObjectContainer &obj)
[693]225{
226        ViewCellContainer::const_iterator it, it_end = mEmptyViewCells.end();
227
228        char buf[50];
229        int i = 0;
230        for (it = mEmptyViewCells.begin(); it != it_end; ++ it)
231        {
232                if (!(*it)->GetPvs().Empty())
233                {
[694]234                        sprintf(buf, "empty-viewcells-%09d.x3d", i/*(*it)->GetId()*/);
[693]235                        Exporter *exporter = Exporter::GetExporter(buf);
236                       
237                        if (exporter && i < 20)
238                        {
[694]239                                Ray *pray = (*it)->mPiercingRays[0];
[728]240                                Debug << "view cell " << (*it)->GetId() << " not empty, pvs: "
241                                          << (*it)->GetPvs().GetSize() << " " << (int)pray->intersections.size() << endl;
[694]242
243                                exporter->ExportRays((*it)->mPiercingRays);
244                                                       
245                                exporter->SetFilled();
246                                exporter->SetForcedMaterial(RgbColor(0,0,1));
247
248                                for (int j = 0; j < (int)pray->intersections.size(); ++ j)
249                                {
250                                        if (pray->intersections[j].mObject)
251                                                exporter->ExportIntersectable(pray->intersections[j].mObject);
252                                }
253
254                                //exporter->SetWireframe();
255                                exporter->SetForcedMaterial(RgbColor(0,1,0));
256                                exporter->ExportGeometry(obj);
257
258                                exporter->SetFilled();
259
260                                exporter->SetForcedMaterial(RgbColor(1,0,0));
[693]261                                ExportViewCellGeometry(exporter, *it);
[694]262
263                                delete exporter;               
[693]264                        }
265
[694]266               
[693]267                        ++ i;
268                }
269        }
[694]270        Debug << "\nSampled " << i << " new view cells (" << " of " << (int)mEmptyViewCells.size() << ")" << endl << endl;
[693]271}
272
273
[574]274int ViewCellsManager::CastPassSamples(const int samplesPerPass,
275                                                                          const int sampleType,
276                                                                          VssRayContainer &passSamples) const
[527]277{
[570]278        SimpleRayContainer simpleRays;
[540]279
[573]280        preprocessor->GenerateRays(samplesPerPass,
281                                                           sampleType,
[570]282                                                           simpleRays);
[564]283
[573]284        // shoot simple ray and add it to importance samples
285        preprocessor->CastRays(simpleRays, passSamples);
[570]286
[574]287        return (int)passSamples.size();
288}
[570]289
[574]290
[607]291
[574]292/// helper function which destroys rays or copies them into the output ray container
[639]293inline void disposeRays(VssRayContainer &rays, VssRayContainer *outRays)
[574]294{
295        cout << "disposing samples ... ";
[582]296        long startTime = GetTime();
297        int n = (int)rays.size();
298
[573]299        if (outRays)
[542]300        {
[574]301                VssRayContainer::const_iterator it, it_end = rays.end();
302
303                for (it = rays.begin(); it != it_end; ++ it)
304                {
305                        outRays->push_back(*it);
306                }
[573]307        }
308        else
309        {
[639]310                VssRayContainer::const_iterator it, it_end = rays.end();
311
312                for (it = rays.begin(); it != it_end; ++ it)
313                {
314                        //(*it)->Unref();
315                        if (!(*it)->IsActive())
316                                delete (*it);
317                }
[573]318        }
[639]319
[574]320        cout << "finished" << endl;
[582]321        Debug << "disposed " << n << " samples in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
[573]322}
[570]323
324
[573]325int ViewCellsManager::Construct(Preprocessor *preprocessor, VssRayContainer *outRays)
326{
327        int numSamples = 0;
328        SimpleRayContainer simpleRays;
329       
[574]330        VssRayContainer initialSamples;
[540]331
[574]332        cout << "view cell construction: casting " << mInitialSamples << " initial samples ... ";
[712]333
[752]334        long startTime = GetTime();
335
[573]336        //-- construction rays => we use uniform samples for this
[574]337        CastPassSamples(mInitialSamples,
[660]338                                        mSamplingType,
[574]339                                        initialSamples);
[573]340       
[574]341        cout << "finished" << endl;
342
[660]343       
[573]344        // construct view cells
[752]345        ConstructSubdivision(preprocessor->mObjects, initialSamples);
[540]346
[727]347        // initial samples count for overall samples ...
[752]348        numSamples += mInitialSamples;
[542]349
[574]350        // rays can be passed or deleted
[639]351        disposeRays(initialSamples, outRays);
[752]352
353        cout << "time needed for initial construction: "
354                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
355
356        Debug << "time needed for initial construction: "
357                  << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
358
359
360        // take post processing time
361        startTime = GetTime();
362
363
[720]364        // testing the view cell filter functionality   
365        if (0) TestFilter(preprocessor->mObjects);
[570]366
[660]367        // -- stats after contruction
368        ResetViewCells();
369
[667]370        Debug << "\nView cells after initial sampling:\n" << mCurrentViewCellsStats << endl;
371
[683]372        if (1) // export initial view cells
[660]373        {
[712]374                const char filename[] = "view_cells.wrl";
375                Exporter *exporter = Exporter::GetExporter(filename);
[660]376
[712]377       
[660]378                if (exporter)
379                {
[712]380                        cout << "exporting initial view cells (=leaves) to " << filename << " ... ";
[660]381                        if (mExportGeometry)
[712]382                        {
[660]383                                exporter->ExportGeometry(preprocessor->mObjects);
[712]384                        }
[660]385
[750]386                        exporter->SetWireframe();
[660]387                        ExportViewCellsForViz(exporter);
388
389                        delete exporter;
[712]390                        cout << "finished" << endl;
[660]391                }
392        }
393
[573]394        //-- guided rays are used for further sampling
[574]395        const int n = mConstructionSamples; //+initialSamples;
[570]396
[666]397        // should we use directional samples?
[694]398        bool dirSamples = (mSamplingType == Preprocessor::DIRECTION_BASED_DISTRIBUTION);
[573]399
[712]400        // -- the main loop
[573]401        while (numSamples < n)
402        {
[596]403                cout << "casting " << mSamplesPerPass << " samples of " << n << " ... ";
[727]404                Debug << "casting " << mSamplesPerPass << " samples of " << n << " ... ";
405
[574]406                VssRayContainer constructionSamples;
407
[694]408                const int samplingType = mSamplingType;
409                        /*dirSamples ?
[574]410                                                Preprocessor::DIRECTION_BASED_DISTRIBUTION :
[694]411                                                Preprocessor::SPATIAL_BOX_BASED_DISTRIBUTION;*/
[667]412
[720]413                if (0) dirSamples = !dirSamples; // toggle sampling method
[667]414
[727]415                // cast new samples
[574]416                numSamples += CastPassSamples(mSamplesPerPass,
[666]417                                                                          samplingType,
[574]418                                                                          constructionSamples);
419
420                cout << "finished" << endl;
421
422                cout << "computing sample contribution for " << (int)constructionSamples.size() << " samples ... ";
423
[727]424                // computes sample contribution of cast rays TODO: leak?
425                if (SAMPLE_AFTER_SUBDIVISION)
[605]426                        ComputeSampleContributions(constructionSamples, true, false);
[712]427
[574]428                cout << "finished" << endl;
429
430
[639]431                disposeRays(constructionSamples, outRays);
[574]432
433                cout << "total samples: " << numSamples << endl;
[542]434        }
[752]435
[573]436       
[570]437
[573]438        //-- post processing
439        VssRayContainer postProcessSamples;
[570]440
[694]441        //-- construction rays
[574]442        CastPassSamples(mPostProcessSamples,
[694]443                                        mSamplingType,
[574]444                                        postProcessSamples);
[660]445
446
447        // stats before post processing (i.e., merge)
448        EvaluateViewCellsStats();
449        Debug << "\noriginal view cell partition before post process:\n" << mCurrentViewCellsStats << endl;
450
451        mRenderer->RenderScene();
452        SimulationStatistics ss;
453        dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
454
455    Debug << ss << endl;
456
457
458
[574]459        cout << "starting post processing and visualization" << endl;
460
[660]461
[666]462        // store view cells for postprocessing
[574]463        const bool storeViewCells = true;
[605]464
[660]465
[605]466        if (SAMPLE_AFTER_SUBDIVISION)
467                ComputeSampleContributions(postProcessSamples, true, storeViewCells);
[663]468
[720]469        //-- post processing (e.g.,merging) of the view cells
[573]470        PostProcess(preprocessor->mObjects, postProcessSamples);
[570]471
[752]472        cout << "time needed for  post processing (merge) step: "
473                 << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl;
474
475        Debug << "time needed for  post processing (merge) step: "
476                 << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl;
477
[720]478        // only for debugging purpose
[694]479        if (TEST_EMPTY_VIEW_CELLS)
480                CollectEmptyViewCells();
[570]481
[693]482
[574]483        //-- visualization
[666]484        if (mShowVisualization)
485        {
486                VssRayContainer visualizationSamples;
[574]487
[666]488                //-- construction rays => we use uniform samples for this
489                CastPassSamples(mVisualizationSamples,
490                                            Preprocessor::DIRECTION_BASED_DISTRIBUTION,
491                                                visualizationSamples);
[574]492
[666]493                if (SAMPLE_AFTER_SUBDIVISION)
494                        ComputeSampleContributions(visualizationSamples, true, storeViewCells);
[574]495
[666]496                // different visualizations
497                Visualize(preprocessor->mObjects, visualizationSamples);
[574]498
[666]499                disposeRays(visualizationSamples, outRays);
500        }
[574]501
[720]502        // evaluation of the paritition, i.e., a number of new samples are cast
[664]503        if (mEvaluateViewCells)
504        {
[666]505                EvalViewCellPartition(preprocessor);
[664]506        }
[666]507       
[573]508        return numSamples;
[527]509}
510
[547]511
[752]512void ViewCellsManager::EvalViewCellHistogram(const string filename,
513                                                                                         const int nViewCells)
[728]514{
515        std::ofstream outstream;
516        outstream.open(filename.c_str());
517
518        ViewCellContainer viewCells;
[735]519        mViewCellsTree->CollectBestViewCellSet(viewCells, nViewCells);
[728]520
521        float maxRenderCost, minRenderCost;
[734]522
523        // sort by render cost
524        sort(viewCells.begin(), viewCells.end(), ViewCell::SmallerRenderCost);
525
526        minRenderCost = viewCells.front()->GetRenderCost();
527        maxRenderCost = viewCells.back()->GetRenderCost();
528
[736]529        Debug << "histogram minrc: " << minRenderCost << " maxrc: " << maxRenderCost << endl;
530
[752]531        const int intervals = min(50, (int)viewCells.size());
[735]532
[728]533        const float range = maxRenderCost - minRenderCost;
[735]534        const float stepSize = range / (float)intervals;
[728]535
[735]536        float currentRenderCost = minRenderCost;//(int)ceil(minRenderCost);
537
538        const float totalRenderCost = mViewCellsTree->GetRoot()->GetRenderCost();
539        const float totalVol = GetViewSpaceBox().GetVolume();
[736]540        //const float totalVol = mViewCellsTree->GetRoot()->GetVolume();
[735]541
[736]542        //float vol = 0;
543        //int smallerCost = 0;
544        int j = 0;
[735]545        int i = 0;
546       
[734]547        ViewCellContainer::const_iterator it = viewCells.begin(), it_end = viewCells.end();             
548
[744]549        // count for integral
550        float volSum = 0;
551        int smallerCostSum = 0;
[735]552       
[734]553        // note can skip computations for view cells already evaluated and delete them from vector ...
554    while (1)
555        {
[744]556                // count for histogram value
557                float volDif = 0;
558                int smallerCostDif = 0;
[736]559
[734]560                while ((i < (int)viewCells.size()) && (viewCells[i]->GetRenderCost() < currentRenderCost))
561                {
[744]562                        volSum += viewCells[i]->GetVolume();
563                        volDif += viewCells[i]->GetVolume();
564
[734]565                        ++ i;
[744]566                        ++ smallerCostSum;
567                        ++ smallerCostDif;
[734]568                }
[736]569               
[744]570                if ((i >= (int)viewCells.size()) || (currentRenderCost >= maxRenderCost))
[735]571                        break;
[736]572               
[744]573                const float rcRatio = currentRenderCost / maxRenderCost;
574                const float volRatioSum = volSum / totalVol;
575                const float volRatioDif = volDif / totalVol;
[735]576
[736]577                outstream << "#Pass\n" << j << endl;
578                outstream << "#RenderCostRatio\n" << rcRatio << endl;
579                outstream << "#WeightedCost\n" << currentRenderCost / totalVol << endl;
[744]580                outstream << "#ViewCellsDif\n" << smallerCostDif << endl;
581                outstream << "#ViewCellsSum\n" << smallerCostSum << endl;       
582                outstream << "#VolumeDif\n" << volRatioDif << endl << endl;
583                outstream << "#VolumeSum\n" << volRatioSum << endl << endl;
[735]584
585                // increase current render cost
[734]586                currentRenderCost += stepSize;
[736]587                ++ j;
[734]588        }
[735]589
[734]590        outstream.close();
591}
592
[735]593
594void ViewCellsManager::EvalViewCellHistogramForPvsSize(const string filename,
595                                                                                                           const int nViewCells)
[734]596{
597        std::ofstream outstream;
598        outstream.open(filename.c_str());
599
600        ViewCellContainer viewCells;
[735]601        mViewCellsTree->CollectBestViewCellSet(viewCells, nViewCells);
[734]602
[735]603        int maxPvsSize, minPvsSize;
[734]604
[735]605        // sort by render cost
606        sort(viewCells.begin(), viewCells.end(), ViewCell::SmallerPvs);
607
608        minPvsSize = viewCells.front()->GetPvs().GetSize();
609        maxPvsSize = viewCells.back()->GetPvs().GetSize();
[736]610       
[752]611        minPvsSize = 0;
612        maxPvsSize = 1200;
613
[736]614        Debug << "histogram minpvssize: " << minPvsSize << " maxpvssize: " << maxPvsSize << endl;
[735]615
[752]616        const int intervals = min(20, (int)viewCells.size());
[735]617        const int range = maxPvsSize - minPvsSize;
618        int stepSize = range / intervals;
619
[752]620       
[735]621        if (!stepSize) stepSize = 1;
[752]622Debug << "stepsize: " << stepSize << endl;
623        cout << "stepsize: " << stepSize << endl;
[735]624
625        const float totalRenderCost = mViewCellsTree->GetRoot()->GetRenderCost();
626        const float totalVol = GetViewSpaceBox().GetVolume();
627
628        int currentPvsSize = minPvsSize;//(int)ceil(minRenderCost);
629
[736]630        //float vol = 0;
[735]631        int i = 0;
632        int j = 0;
[734]633
[744]634        float volSum = 0;
635        int smallerSum = 0;
636
[735]637        ViewCellContainer::const_iterator it = viewCells.begin(), it_end = viewCells.end();             
638       
[736]639        while (1)
[728]640        {
[744]641                float volDif = 0;
642                int smallerDif = 0;
[736]643
[735]644                while ((i < (int)viewCells.size()) && (viewCells[i]->GetPvs().GetSize() < currentPvsSize))
645                {
[744]646                        volDif += viewCells[i]->GetVolume();
647                        volSum += viewCells[i]->GetVolume();
[735]648                        ++ i;
[744]649                        ++ smallerDif;
650                        ++ smallerSum;
[735]651                }
[736]652               
[744]653                //if (i < (int)viewCells.size())
654                //      Debug << "new pvs size increase: " << viewCells[i]->GetPvs().GetSize() << " " << currentPvsSize << endl;
[728]655
[735]656                if ((i >= (int)viewCells.size()) || (currentPvsSize >= maxPvsSize))
657                        break;
[728]658
[744]659                const float volRatioDif = volDif / totalVol;
660                const float volRatioSum = volSum / totalVol;
[728]661
[735]662                outstream << "#Pass\n" << j ++ << endl;
663                outstream << "#Pvs\n" << currentPvsSize << endl;
[744]664                outstream << "#ViewCellsDif\n" << smallerDif << endl;
665                outstream << "#ViewCellsSum\n" << smallerSum << endl;   
666                outstream << "#VolumeDif\n" << volRatioDif << endl << endl;
667                outstream << "#VolumeSum\n" << volRatioSum << endl << endl;
[729]668
[735]669                // increase current pvs size
670                currentPvsSize += stepSize;
[728]671        }
[735]672        outstream.close();
[728]673}
674
[735]675
[664]676void ViewCellsManager::EvalViewCellPartition(Preprocessor *preprocessor)
[660]677{
678        int samplesPerPass;
679        int numSamples;
680        int castSamples = 0;
681
[664]682        char s[64];
683
[660]684        environment->GetIntValue("ViewCells.Evaluation.samplesPerPass", samplesPerPass);
685        environment->GetIntValue("ViewCells.Evaluation.samples", numSamples);
686
[664]687        char statsPrefix[100];
688        environment->GetStringValue("ViewCells.Evaluation.statsPrefix", statsPrefix);
[663]689
[664]690        Debug << "view cell evaluation samples per pass: " << samplesPerPass << endl;
691        Debug << "view cell evaluation samples: " << numSamples << endl;
692        Debug << "view cell stats prefix: " << statsPrefix << endl;
693
694        //VssRayContainer outRays;
[666]695        // should directional sampling be used?
[722]696        bool dirSamples = (mEvaluationSamplingType == Preprocessor::DIRECTION_BASED_DISTRIBUTION);
[664]697
[744]698        cout << "collect leaf view cells and reseting pvs ... ";
[664]699
700        ViewCellContainer leaves;
701        mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
[744]702        cout << " ... ";
[666]703        bool startFromZero = true;
704
705        // reset pvs and start over from zero
706        if (startFromZero)
707        {
708                mViewCellsTree->ResetPvs();
709        }
710        else // statistics without addidtional samples
711        {
712                cout << "compute new statistics ... ";
713                sprintf(s, "-%09d-eval.log", castSamples);
714                string fName = string(statsPrefix) + string(s);
715
716                mViewCellsTree->ExportStats(fName);
717                cout << "finished" << endl;
718        }
719       
[744]720        cout << "finished" << endl;
721
722        cout << "Evaluating view cell partition" << endl;
723
[660]724        while (castSamples < numSamples)
725        {
[664]726                VssRayContainer evaluationSamples;
[663]727
[722]728                const int samplingType = mEvaluationSamplingType;
[666]729                /*      dirSamples ?
[664]730                                                Preprocessor::DIRECTION_BASED_DISTRIBUTION :
731                                                Preprocessor::SPATIAL_BOX_BASED_DISTRIBUTION;
[666]732                */
[664]733                //-- construction rays => we use uniform samples for this
[744]734                cout << "casting " << samplesPerPass << " samples " << endl;
[664]735                CastPassSamples(samplesPerPass, samplingType, evaluationSamples);
736               
737                castSamples += samplesPerPass;
738
[752]739                cout << "computing sample contributions of " << (int)evaluationSamples.size()
740                         << " samples " << endl;
[664]741
742                ComputeSampleContributions(evaluationSamples, true, false);
743
744                cout << "compute new statistics ... ";
745
[752]746                // propagate pvs or pvs size information
747                ObjectPvs pvs;
748                UpdatePvsForEvaluation(mViewCellsTree->GetRoot(), pvs);
[664]749
750
751                // output stats
[667]752                sprintf(s, "-%09d-eval.log", castSamples);
[664]753                string fileName = string(statsPrefix) + string(s);
754
755                mViewCellsTree->ExportStats(fileName);
756
757                cout << "finished" << endl;
758       
759                disposeRays(evaluationSamples, NULL);
[660]760        }
[728]761       
[735]762        bool useHisto;
763        int histoPasses;
[693]764
[735]765        environment->GetBoolValue("ViewCells.Evaluation.histogram", useHisto);
766        environment->GetIntValue("ViewCells.Evaluation.histoPasses", histoPasses);
[728]767
[744]768        const int numLeaves = mViewCellsTree->GetNumInitialViewCells(mViewCellsTree->GetRoot());
[736]769
770        Debug << "number of leaves: " << numLeaves << endl;
771        cout << "number of leaves: " << numLeaves << endl;
772
[735]773        if (useHisto)
[734]774        {
[735]775                // evaluate view cells in a histogram           
776                char s[64];
[744]777#if 0
[735]778                for (int passes = 1; passes <= histoPasses; ++ passes)
779                {
[736]780                        int n = numLeaves * passes / histoPasses;
[734]781               
[735]782                        cout << "computing histogram for " << n << " view cells" << endl;
783
784                        //-- evaluate histogram for render cost
785                        sprintf(s, "-%09d-histo.log", n);
786                        string filename = string(statsPrefix) + string(s);
787
788                        EvalViewCellHistogram(filename, n);
789
790                        //////////////////////////////////////////
791            // --evaluate histogram for pvs size
792
793                        cout << "computing pvs histogram for " << n << " view cells" << endl;
794
795                        sprintf(s, "-%09d-histo-pvs.log", n);
796                        filename = string(statsPrefix) + string(s);
797
798                        EvalViewCellHistogramForPvsSize(filename, n);
799                }
[744]800#else
[752]801                for (int pass = histoPasses; pass <= numLeaves; pass += histoPasses)
[744]802                {
803                        cout << "computing histogram for " << pass << " view cells" << endl;
804
805                        //-- evaluate histogram for render cost
806                        sprintf(s, "-%09d-histo.log", pass);
807                        string filename = string(statsPrefix) + string(s);
808
809                        EvalViewCellHistogram(filename, pass);
810
811                        //////////////////////////////////////////
[752]812            //-- evaluate histogram for pvs size
[744]813
814                        cout << "computing pvs histogram for " << pass << " view cells" << endl;
815
816                        sprintf(s, "-%09d-histo-pvs.log", pass);
817                        filename = string(statsPrefix) + string(s);
818
819                        EvalViewCellHistogramForPvsSize(filename, pass);
820                }
821#endif
[734]822        }
823
[693]824        // find empty view cells bug
[694]825        if (TEST_EMPTY_VIEW_CELLS)
[719]826        {
[694]827                TestEmptyViewCells(preprocessor->mObjects);
[719]828        }
[660]829}
830
[704]831
832inline float EvalMergeCost(ViewCell *root, ViewCell *candidate)
[703]833{
[704]834        return root->GetPvs().GetPvsHomogenity(candidate->GetPvs());
835}
[660]836
[703]837
[728]838// Returns index of the best view cells of the neighborhood
[704]839int GetBestViewCellIdx(ViewCell *root, const ViewCellContainer &neighborhood)
840{
[705]841        int bestViewCellIdx = 0;
[703]842
[704]843        float mergeCost = Limits::Infinity;
844        int i = 0;
[703]845
[734]846        ViewCellContainer::const_iterator vit, vit_end = neighborhood.end();
[703]847
[734]848        for (vit = neighborhood.begin(); vit != vit_end; ++ vit, ++ i)
[703]849        {
[734]850                const float mc = EvalMergeCost(root, *vit);
[705]851               
852                if (mc < mergeCost)
[704]853                {
854                        mergeCost = mc;
855                        bestViewCellIdx = i;
[703]856                }
[704]857        }
[703]858
[704]859        return bestViewCellIdx;
860}
[703]861
862
[728]863void ViewCellsManager::SetMaxFilterSize(const int size)
864{
865        mMaxFilterSize = size;
866}
867
868
869float ViewCellsManager::EvalRenderCost(Intersectable *obj) const
870{
871        switch (mRenderCostEvaluationType)
872        {
873        case PER_OBJECT:
[752]874                //cout << "perobject" << endl;
875                return 1.0f;
[728]876       
877        case PER_TRIANGLE:
[735]878                {cout << "pertriangle" << endl;
[728]879                        // HACK
880                        MeshInstance *mi = dynamic_cast<MeshInstance *>(obj);
881
882                        // HACK: assume meshes are triangles
883                        if (mi->GetMesh())
884                        {
885                                return mi->GetMesh()->mFaces.size();
886                        }
887                }
888        default:
[752]889                cout << "default" << endl;
890                return 1.0f;
[728]891        }
892
893        // should not come here
[752]894        return 0.0f;
[728]895}
896
897
[704]898ViewCell *ViewCellsManager::ConstructLocalMergeTree(ViewCell *currentViewCell,
899                                                                                                        const ViewCellContainer &viewCells)
900{
901        ViewCell *root = currentViewCell;
902        ViewCellContainer neighborhood = viewCells;
[703]903
[704]904        ViewCellContainer::const_iterator it, it_end = neighborhood.end();
[703]905
[704]906        const int n = min(mMaxFilterSize, (int)neighborhood.size());
907        //-- use priority queue to merge leaf pairs
[703]908
[705]909        //cout << "neighborhood: " << neighborhood.size() << endl;
[704]910        //const float maxAvgCost = 350;
911        for (int nMergedViewCells = 0; nMergedViewCells < n; ++ nMergedViewCells)
[703]912        {
[704]913                const int bestViewCellIdx = GetBestViewCellIdx(root, neighborhood);
[703]914               
[704]915                ViewCell *bestViewCell = neighborhood[bestViewCellIdx];
[706]916       
[704]917                // remove from vector
918                swap(neighborhood[bestViewCellIdx], neighborhood.back());
919                neighborhood.pop_back();
[705]920       
[713]921                //              cout << "vc idx: " << bestViewCellIdx << endl;
[704]922                if (!bestViewCell || !root)
923                        cout << "warning!!" << endl;
[705]924               
[704]925                // create new root of the hierarchy
926                root = MergeViewCells(root, bestViewCell);
[703]927        }
928
[704]929        return root;   
[703]930}
931
[704]932
[713]933struct SortableViewCellEntry {
934
935  SortableViewCellEntry() {}
936  SortableViewCellEntry(const float v, ViewCell *cell):mValue(v), mViewCell(cell) {}
937 
938  float mValue;
939  ViewCell *mViewCell;
940
941  friend bool operator<(const SortableViewCellEntry &a, const SortableViewCellEntry &b) {
942        return a.mValue < b.mValue;
943  }
944};
945
946ViewCell *
947ViewCellsManager::ConstructLocalMergeTree2(ViewCell *currentViewCell,
948                                                                                   const ViewCellContainer &viewCells)
949{
950 
951  vector<SortableViewCellEntry> neighborhood(viewCells.size());
952  int i, j;
953  for (i = 0, j = 0; i < viewCells.size(); i++) {
954        if (viewCells[i] != currentViewCell)
955          neighborhood[j++] = SortableViewCellEntry(
956                                                                                                EvalMergeCost(currentViewCell, viewCells[i]),
957                                                                                                viewCells[i]);
958  }
959  neighborhood.resize(j);
960 
961  sort(neighborhood.begin(), neighborhood.end());
962 
963  ViewCell *root = currentViewCell;
964 
965  vector<SortableViewCellEntry>::const_iterator it, it_end = neighborhood.end();
966 
967  const int n = min(mMaxFilterSize, (int)neighborhood.size());
968  //-- use priority queue to merge leaf pairs
969 
970  //cout << "neighborhood: " << neighborhood.size() << endl;
971  for (int nMergedViewCells = 0; nMergedViewCells < n; ++ nMergedViewCells)
[728]972  {
[713]973          ViewCell *bestViewCell = neighborhood[nMergedViewCells].mViewCell;
974          //cout <<nMergedViewCells<<":"<<"homogenity=" <<neighborhood[nMergedViewCells].mValue<<endl;
975          // create new root of the hierarchy
976          root = MergeViewCells(root, bestViewCell);
977          // set negative cost so that this view cell gets deleted
978          root->SetMergeCost(-1.0f);
[728]979  }
[713]980 
981  return root; 
982}
983
984void
985ViewCellsManager::DeleteLocalMergeTree(ViewCell *vc
986                                                                           ) const
987{
988  if (!vc->IsLeaf() && vc->GetMergeCost() < 0.0f) {
989        ViewCellInterior *vci = (ViewCellInterior *) vc;
990        ViewCellContainer::const_iterator it, it_end = vci->mChildren.end();
991       
992        for (it = vci->mChildren.begin(); it != it_end; ++ it)
993          DeleteLocalMergeTree(*it);
994        vci->mChildren.clear();
995        delete vci;
996  }
997}
998
[564]999bool ViewCellsManager::CheckValidity(ViewCell *vc,
1000                                                                         int minPvsSize,
[562]1001                                                                         int maxPvsSize) const
[547]1002{
[569]1003
[710]1004        if ((vc->GetPvs().GetSize() > maxPvsSize) ||
1005                (vc->GetPvs().GetSize() < minPvsSize))
[564]1006        {
[710]1007                return false;
[561]1008        }
[570]1009
[710]1010        return true;
[547]1011}
1012
1013
[710]1014bool ViewCellsManager::EqualToSpatialNode(ViewCell *viewCell) const
1015{
1016        return false;
1017}
1018
1019int ViewCellsManager::ComputeBoxIntersections(const AxisAlignedBox3 &box,
1020                                                                                          ViewCellContainer &viewCells) const
1021{
1022        return 0;
1023};
1024
[697]1025AxisAlignedBox3 ViewCellsManager::GetFilterBBox(const Vector3 &viewPoint,
1026                                                                                                const float width) const
1027{
[746]1028  float w = Magnitude(mViewSpaceBox.Size())*width;
1029  Vector3 min = viewPoint - w * 0.5f;
1030  Vector3 max = viewPoint + w * 0.5f;
1031 
1032  return AxisAlignedBox3(min, max);
[697]1033}
1034
1035
1036void ViewCellsManager::GetPrVS(const Vector3 &viewPoint, PrVs &prvs)
1037{
[746]1038  const AxisAlignedBox3 box = GetFilterBBox(viewPoint, mFilterWidth);
1039       
1040  ViewCell *currentViewCell = GetViewCell(viewPoint);
[697]1041
[746]1042  if (currentViewCell) {
[697]1043        ViewCellContainer viewCells;
1044        ComputeBoxIntersections(box, viewCells);
[746]1045       
[713]1046        ViewCell *root = ConstructLocalMergeTree2(currentViewCell, viewCells);
[704]1047        prvs.mViewCell = root;
[746]1048  } else
1049        prvs.mViewCell = NULL;
1050  //prvs.mPvs = root->GetPvs();
[697]1051}
1052
1053
[581]1054bool ViewCellsManager::ViewCellsTreeConstructed() const
1055{
1056        return mViewCellsTree->GetRoot();
1057}
1058
1059
[564]1060void ViewCellsManager::SetValidity(ViewCell *vc,
1061                                                                   int minPvs,
[562]1062                                                                   int maxPvs) const
1063{
1064        vc->SetValid(CheckValidity(vc, minPvs, maxPvs));
1065}
1066
[577]1067
[569]1068void
1069ViewCellsManager::SetValidity(
[570]1070                                                          int minPvsSize,
[569]1071                                                          int maxPvsSize) const
1072{
1073  ViewCellContainer::const_iterator it, it_end = mViewCells.end();
[570]1074
[569]1075  for (it = mViewCells.begin(); it != it_end; ++ it) {
1076        SetValidity(*it, minPvsSize, maxPvsSize);
1077  }
1078}
[562]1079
[569]1080void
1081ViewCellsManager::SetValidityPercentage(
1082                                                                                const float minValid,
1083                                                                                const float maxValid
1084                                                                                )
1085{
1086  sort(mViewCells.begin(), mViewCells.end(), ViewCell::SmallerPvs);
[570]1087
[569]1088  int start = mViewCells.size()*minValid;
1089  int end = mViewCells.size()*maxValid;
[570]1090
[569]1091  for (int i=0; i < mViewCells.size(); i++)
1092        mViewCells[i]->SetValid(i >= start && i <= end);
1093}
1094
1095int
1096ViewCellsManager::CountValidViewcells() const
1097{
1098  ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1099  int valid = 0;
1100  for (it = mViewCells.begin(); it != it_end; ++ it) {
1101        if ((*it)->GetValid())
[706]1102          valid ++;
[569]1103  }
1104  return valid;
1105}
1106
[577]1107
1108bool ViewCellsManager::LoadViewCellsGeometry(const string filename)
[440]1109{
1110        X3dParser parser;
[503]1111
[440]1112        environment->GetFloatValue("ViewCells.height", parser.mViewCellHeight);
[503]1113
[440]1114        bool success = parser.ParseFile(filename, *this);
1115        Debug << (int)mViewCells.size() << " view cells loaded" << endl;
1116
1117        return success;
1118}
1119
[485]1120
[487]1121bool ViewCellsManager::GetViewPoint(Vector3 &viewPoint) const
1122{
[542]1123        viewPoint = mViewSpaceBox.GetRandomPoint();
[487]1124
1125        return true;
1126}
1127
1128
[557]1129float ViewCellsManager::GetViewSpaceVolume()
1130{
[610]1131        return mViewSpaceBox.GetVolume() * (2.0f * sqr((float)M_PI));
[557]1132}
1133
1134
[490]1135bool ViewCellsManager::ViewPointValid(const Vector3 &viewPoint) const
1136{
[569]1137  if (!ViewCellsConstructed())
[542]1138        return mViewSpaceBox.IsInside(viewPoint);
[569]1139  else {
1140        if (!mViewSpaceBox.IsInside(viewPoint))
1141          return false;
1142        ViewCell *viewcell = GetViewCell(viewPoint);
1143        if (!viewcell || !viewcell->GetValid())
1144          return false;
1145  }
1146  return true;
[490]1147}
1148
[501]1149
[563]1150float
1151ViewCellsManager::ComputeSampleContributions(const VssRayContainer &rays,
[574]1152                                                                                         const bool addRays,
1153                                                                                         const bool storeViewCells
[563]1154                                                                                         )
[440]1155{
[563]1156  // view cells not yet constructed
1157  if (!ViewCellsConstructed())
1158        return 0.0f;
[564]1159
[563]1160  VssRayContainer::const_iterator it, it_end = rays.end();
[503]1161
[563]1162  float sum = 0.0f;
[664]1163  for (it = rays.begin(); it != it_end; ++ it)
1164  {
1165          sum += ComputeSampleContributions(*(*it), addRays, storeViewCells);
1166          //ComputeSampleContributions(*(*it), addRays);
1167          //    sum += (*it)->mPvsContribution;
[563]1168  }
[664]1169
[563]1170  return sum;
[440]1171}
1172
[485]1173
[479]1174void ViewCellsManager::EvaluateViewCellsStats()
1175{
[660]1176        mCurrentViewCellsStats.Reset();
[479]1177
1178        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1179
1180        for (it = mViewCells.begin(); it != it_end; ++ it)
[487]1181        {
[660]1182                mViewCellsTree->UpdateViewCellsStats(*it, mCurrentViewCellsStats);
[487]1183        }
[479]1184}
1185
[485]1186
[580]1187void ViewCellsManager::EvaluateRenderStatistics(float &totalRenderCost,
[579]1188                                                                                                float &expectedRenderCost,
[580]1189                                                                                                float &deviation,
1190                                                                                                float &variance,
1191                                                                                                int &totalPvs,
1192                                                                                                float &avgRenderCost)
[579]1193{
1194        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1195
[580]1196
[579]1197        //-- compute expected value
1198
1199        totalRenderCost = 0;
[580]1200        totalPvs = 0;
[579]1201
1202        for (it = mViewCells.begin(); it != it_end; ++ it)
1203        {
1204                ViewCell *vc = *it;
1205                totalRenderCost += vc->GetPvs().GetSize() * vc->GetVolume();
[580]1206                totalPvs += (int)vc->GetPvs().GetSize();
[579]1207        }
1208
[580]1209        // normalize with view space box
1210        totalRenderCost /= mViewSpaceBox.GetVolume();
[579]1211        expectedRenderCost = totalRenderCost / (float)mViewCells.size();
[580]1212        avgRenderCost = totalPvs / (float)mViewCells.size();
[579]1213
1214
[580]1215        //-- compute standard defiation
[579]1216        variance = 0;
[580]1217        deviation = 0;
[579]1218
1219        for (it = mViewCells.begin(); it != it_end; ++ it)
1220        {
1221                ViewCell *vc = *it;
1222
1223                float renderCost = vc->GetPvs().GetSize() * vc->GetVolume();
[580]1224                float dev;
[579]1225
[580]1226                if (1)
1227                        dev = fabs(avgRenderCost - (float)vc->GetPvs().GetSize());
1228                else
1229                        dev = fabs(expectedRenderCost - renderCost);
[579]1230
[580]1231                deviation += dev;
1232                variance += dev * dev;
[579]1233        }
[580]1234
[579]1235        variance /= (float)mViewCells.size();
[580]1236        deviation /= (float)mViewCells.size();
[579]1237}
1238
1239
1240
[440]1241void ViewCellsManager::AddViewCell(ViewCell *viewCell)
1242{
1243        mViewCells.push_back(viewCell);
1244}
1245
[485]1246
[478]1247float ViewCellsManager::GetArea(ViewCell *viewCell) const
1248{
1249        return viewCell->GetArea();
1250}
1251
1252
1253float ViewCellsManager::GetVolume(ViewCell *viewCell) const
1254{
1255        return viewCell->GetVolume();
1256}
1257
[485]1258
[503]1259void ViewCellsManager::DeriveViewCells(const ObjectContainer &objects,
1260                                                                           ViewCellContainer &viewCells,
[440]1261                                                                           const int maxViewCells) const
1262{
1263        // maximal max viewcells
[503]1264        int limit = maxViewCells > 0 ?
[440]1265                Min((int)objects.size(), maxViewCells) : (int)objects.size();
1266
1267        for (int i = 0; i < limit; ++ i)
1268        {
1269                Intersectable *object = objects[i];
[503]1270
[440]1271                // extract the mesh instances
1272                if (object->Type() == Intersectable::MESH_INSTANCE)
1273                {
1274                        MeshInstance *inst = dynamic_cast<MeshInstance *>(object);
1275
1276                        ViewCell *viewCell = GenerateViewCell(inst->GetMesh());
1277                        viewCells.push_back(viewCell);
1278                }
1279                //TODO: transformed meshes
1280        }
1281}
1282
[485]1283
[503]1284ViewCell *ViewCellsManager::ExtrudeViewCell(const Triangle3 &baseTri,
[440]1285                                                                                        const float height) const
1286{
1287        // one mesh per view cell
1288        Mesh *mesh = new Mesh();
[503]1289
[440]1290        //-- construct prism
1291
[503]1292        // bottom
[440]1293        mesh->mFaces.push_back(new Face(2,1,0));
1294        // top
1295    mesh->mFaces.push_back(new Face(3,4,5));
1296        // sides
1297        mesh->mFaces.push_back(new Face(1, 4, 3, 0));
1298        mesh->mFaces.push_back(new Face(2, 5, 4, 1));
1299        mesh->mFaces.push_back(new Face(3, 5, 2, 0));
1300
1301        //--- extrude new vertices for top of prism
1302        Vector3 triNorm = baseTri.GetNormal();
1303
[503]1304        Triangle3 topTri;
[440]1305
1306        // add base vertices and calculate top vertices
1307        for (int i = 0; i < 3; ++ i)
1308                mesh->mVertices.push_back(baseTri.mVertices[i]);
[503]1309
1310        // add top vertices
[440]1311        for (int i = 0; i < 3; ++ i)
1312                mesh->mVertices.push_back(baseTri.mVertices[i] + height * triNorm);
[503]1313
[440]1314        mesh->Preprocess();
1315
1316        return GenerateViewCell(mesh);
1317}
1318
[485]1319
[551]1320void ViewCellsManager::FinalizeViewCells(const bool createMesh)
1321{
1322        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
[693]1323
1324        // volume and area of the view cells are recomputed and a view cell mesh is created
[551]1325        for (it = mViewCells.begin(); it != it_end; ++ it)
1326        {
1327                Finalize(*it, createMesh);
1328        }
[555]1329
1330        mTotalAreaValid = false;
[551]1331}
1332
1333
1334void ViewCellsManager::Finalize(ViewCell *viewCell, const bool createMesh)
1335{
1336        // implemented in subclasses
1337}
1338
[752]1339// fast way of merging 2 view cells
[582]1340ViewCellInterior *ViewCellsManager::MergeViewCells(ViewCell *left, ViewCell *right) const
[440]1341{
[580]1342        // generate parent view cell
[752]1343        ViewCellInterior *vc = new ViewCellInterior();
[710]1344
[752]1345        vc->GetPvs().Clear();
[610]1346        vc->GetPvs() = left->GetPvs();
[752]1347
1348        // merge pvs of right cell
[610]1349        vc->GetPvs().Merge(right->GetPvs());
[440]1350
[462]1351        //-- merge ray sets
[564]1352        if (0)
1353        {
[582]1354                stable_sort(left->mPiercingRays.begin(), left->mPiercingRays.end());
1355                stable_sort(right->mPiercingRays.begin(), right->mPiercingRays.end());
[440]1356
[582]1357                std::merge(left->mPiercingRays.begin(), left->mPiercingRays.end(),
1358                                   right->mPiercingRays.begin(), right->mPiercingRays.end(),
[564]1359                                   vc->mPiercingRays.begin());
1360        }
[440]1361
[710]1362        // set only links to child (not from child to parent, maybe not wished!!)
1363        vc->mChildren.push_back(left);
1364        vc->mChildren.push_back(right);
1365
[752]1366        // update pvs size
1367        vc->mPvsSize = vc->GetPvs().GetSize();
1368        vc->mPvsSizeValid = true;
1369
[440]1370        return vc;
1371}
1372
[485]1373
[582]1374ViewCellInterior *ViewCellsManager::MergeViewCells(ViewCellContainer &children) const
1375{
[752]1376        ViewCellInterior *vc = new ViewCellInterior();
[582]1377
1378        ViewCellContainer::const_iterator it, it_end = children.end();
1379
1380        for (it = children.begin(); it != it_end; ++ it)
1381        {
1382                // merge pvs
[610]1383                vc->GetPvs().Merge((*it)->GetPvs());
[710]1384                vc->mChildren.push_back(*it);
[582]1385        }
1386
1387        return vc;
1388}
1389
1390
[480]1391void ViewCellsManager::SetRenderer(Renderer *renderer)
1392{
1393        mRenderer = renderer;
1394}
[441]1395
[485]1396
[580]1397ViewCellsTree *ViewCellsManager::GetViewCellsTree()
[440]1398{
[580]1399        return mViewCellsTree;
[440]1400}
1401
1402
1403void ViewCellsManager::SetVisualizationSamples(const int visSamples)
1404{
[444]1405        mVisualizationSamples = visSamples;
[440]1406}
1407
[485]1408
[440]1409void ViewCellsManager::SetConstructionSamples(const int constructionSamples)
1410{
1411        mConstructionSamples = constructionSamples;
1412}
1413
[485]1414
[574]1415void ViewCellsManager::SetInitialSamples(const int initialSamples)
1416{
1417        mInitialSamples = initialSamples;
1418}
1419
1420
[440]1421void ViewCellsManager::SetPostProcessSamples(const int postProcessSamples)
1422{
1423        mPostProcessSamples = postProcessSamples;
1424}
1425
[485]1426
[440]1427int ViewCellsManager::GetVisualizationSamples() const
1428{
1429        return mVisualizationSamples;
1430}
1431
[485]1432
[440]1433int ViewCellsManager::GetConstructionSamples() const
1434{
1435        return mConstructionSamples;
1436}
1437
[485]1438
[440]1439int ViewCellsManager::GetPostProcessSamples() const
1440{
1441        return mPostProcessSamples;
1442}
1443
[485]1444
[719]1445void ViewCellsManager::UpdatePvs()
1446{
[720]1447        if (mViewCellPvsIsUpdated || !ViewCellsTreeConstructed())
[719]1448                return;
1449
1450        mViewCellPvsIsUpdated = true;
1451
1452        ViewCellContainer leaves;
1453        mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
1454
1455        ViewCellContainer::const_iterator it, it_end = leaves.end();
1456
1457        for (it = leaves.begin(); it != it_end; ++ it)
1458        {
1459                mViewCellsTree->PropagatePvs(*it);
1460        }
1461}
1462
1463
[485]1464void ViewCellsManager::GetPvsStatistics(PvsStatistics &stat)
[467]1465{
[719]1466        // update pvs of view cells tree if necessary
1467        UpdatePvs();
[467]1468
[719]1469        ViewCellContainer::const_iterator it = mViewCells.begin();
1470
1471        stat.viewcells = 0;
1472        stat.minPvs = 100000000;
1473        stat.maxPvs = 0;
1474        stat.avgPvs = 0.0f;
1475
1476        for (; it != mViewCells.end(); ++ it)
1477        {
1478                ViewCell *viewcell = *it;
1479               
1480                const int pvsSize = mViewCellsTree->GetPvsSize(viewcell);
1481               
1482                if (pvsSize < stat.minPvs)
1483                        stat.minPvs = pvsSize;
1484                if (pvsSize > stat.maxPvs)
1485                        stat.maxPvs = pvsSize;
1486                stat.avgPvs += pvsSize;
1487               
1488                ++ stat.viewcells;
1489        }
1490
1491        if (stat.viewcells)
1492                stat.avgPvs/=stat.viewcells;
[467]1493}
1494
[485]1495
[480]1496void ViewCellsManager::PrintPvsStatistics(ostream &s)
[467]1497{
1498  s<<"############# Viewcell PVS STAT ##################\n";
1499  PvsStatistics pvsStat;
1500  GetPvsStatistics(pvsStat);
1501  s<<"#AVG_PVS\n"<<pvsStat.avgPvs<<endl;
1502  s<<"#MAX_PVS\n"<<pvsStat.maxPvs<<endl;
1503  s<<"#MIN_PVS\n"<<pvsStat.minPvs<<endl;
1504}
1505
[485]1506
[532]1507int ViewCellsManager::CastBeam(Beam &beam)
1508{
1509        return 0;
1510}
1511
[547]1512
[468]1513ViewCellContainer &ViewCellsManager::GetViewCells()
1514{
1515        return mViewCells;
1516}
1517
[485]1518
[487]1519void ViewCellsManager::SetViewSpaceBox(const AxisAlignedBox3 &box)
1520{
[542]1521        mViewSpaceBox = box;
[591]1522
[660]1523        CreateClipPlane();
[591]1524       
[577]1525        mTotalAreaValid = false;
[487]1526}
1527
1528
[660]1529void ViewCellsManager::CreateClipPlane()
[591]1530{
1531        int axis = 0;
[667]1532        float pos;
[591]1533
[667]1534        environment->GetFloatValue("ViewCells.Visualization.clipPlanePos", pos);
[591]1535
[667]1536        Vector3 point = mViewSpaceBox.Min() +  mViewSpaceBox.Size() * pos;
1537
[660]1538        if (mUseClipPlaneForViz)
1539        environment->GetIntValue("ViewCells.Visualization.clipPlaneAxis", axis);
[591]1540
1541        Vector3 normal(0,0,0);
1542        normal[axis] = 1;
1543
[660]1544        mClipPlane = Plane3(normal, point);
[591]1545}
1546
1547
[519]1548AxisAlignedBox3 ViewCellsManager::GetViewSpaceBox() const
1549{
[542]1550        return mViewSpaceBox;
[519]1551}
1552
1553
[480]1554void ViewCellsManager::ResetViewCells()
1555{
[720]1556        // recollect view cells
[480]1557        mViewCells.clear();
1558        CollectViewCells();
[590]1559       
[720]1560       
1561        // stats are computed once more
[660]1562        mCurrentViewCellsStats.Reset();
[480]1563        EvaluateViewCellsStats();
[590]1564
[520]1565        // has to be recomputed
[480]1566        mTotalAreaValid = false;
1567}
1568
[485]1569
[547]1570int ViewCellsManager::GetMaxPvsSize() const
1571{
1572        return mMaxPvsSize;
1573}
1574
[590]1575
[563]1576void
1577ViewCellsManager::AddSampleContributions(const VssRayContainer &rays)
1578{
1579  if (!ViewCellsConstructed())
1580        return;
[564]1581
[563]1582  VssRayContainer::const_iterator it, it_end = rays.end();
[564]1583
[563]1584  for (it = rays.begin(); it != it_end; ++ it) {
1585        AddSampleContributions(*(*it));
1586  }
1587}
[547]1588
[581]1589
[562]1590int ViewCellsManager::GetMinPvsSize() const
1591{
1592        return mMinPvsSize;
1593}
1594
1595
1596
[561]1597float ViewCellsManager::GetMaxPvsRatio() const
1598{
1599        return mMaxPvsRatio;
1600}
1601
1602
[563]1603void
1604ViewCellsManager::AddSampleContributions(VssRay &ray)
[468]1605{
[563]1606  // assumes viewcells have been stored...
1607  ViewCellContainer *viewcells = &ray.mViewCells;
1608  ViewCellContainer::const_iterator it;
1609  for (it = viewcells->begin(); it != viewcells->end(); ++it) {
1610        ViewCell *viewcell = *it;
[569]1611        if (viewcell->GetValid()) {
1612          // if ray not outside of view space
1613          viewcell->GetPvs().AddSample(ray.mTerminationObject, ray.mPdf);
1614        }
[563]1615  }
1616}
[503]1617
[574]1618
[570]1619float ViewCellsManager::ComputeSampleContributions(VssRay &ray,
[574]1620                                                                                                   const bool addRays,
1621                                                                                                   const bool storeViewCells)
[563]1622{
[570]1623        ViewCellContainer viewcells;
[564]1624
[570]1625        ray.mPvsContribution = 0;
1626        ray.mRelativePvsContribution = 0.0f;
[485]1627
[570]1628        static Ray hray;
[564]1629        hray.Init(ray);
1630        //hray.mFlags |= Ray::CULL_BACKFACES;
1631        //Ray hray(ray);
1632
1633        float tmin = 0, tmax = 1.0;
1634
1635        if (!GetViewSpaceBox().GetRaySegment(hray, tmin, tmax) || (tmin > tmax))
[565]1636                return 0;
[564]1637
1638        Vector3 origin = hray.Extrap(tmin);
1639        Vector3 termination = hray.Extrap(tmax);
1640
1641        CastLineSegment(origin, termination, viewcells);
[664]1642
[570]1643        // copy viewcells memory efficiently
[574]1644        //const bool storeViewcells = !addRays;
[564]1645
[574]1646        if (storeViewCells)
[570]1647        {
1648                ray.mViewCells.reserve(viewcells.size());
1649                ray.mViewCells = viewcells;
1650        }
[564]1651
[570]1652        ViewCellContainer::const_iterator it = viewcells.begin();
[564]1653
[664]1654        for (; it != viewcells.end(); ++ it)
1655        {
1656                ViewCell *viewcell = *it;
[694]1657
[708]1658                if (viewcell->GetValid())
[664]1659                {
[694]1660                        // HACK
[706]1661#if TEST_EMPTY_VIEW_CELLS
[694]1662                                for (int i = 0; i < mEmptyViewCells.size(); ++i)
1663                                {
1664                                        if (viewcell == mEmptyViewCells[i])
1665                                        {
1666                                                viewcell->mPiercingRays.push_back(new Ray(ray));
1667                                                Debug << "empty view cell ray found: " << ray.mOriginObject << ", " << ray.mTerminationObject << endl;
1668                                        }
1669                                }
[706]1670#endif
[664]1671                        // if ray not outside of view space
1672                        float contribution;
[666]1673                        if (ray.mTerminationObject &&
1674                                viewcell->GetPvs().GetSampleContribution(ray.mTerminationObject,
[664]1675                                                                                                                 ray.mPdf,
1676                                                                                                                 contribution))
1677                        {
1678                                ++ ray.mPvsContribution;
1679                                ray.mRelativePvsContribution += contribution;
1680                        }
[718]1681
1682                        //for directional sampling it is important to count only contributions
1683                        // made in one direction!!!
1684                        // the other contributions of this sample will be counted for the oposite ray!
1685#if 0
[666]1686                        if (ray.mOriginObject &&
1687                                viewcell->GetPvs().GetSampleContribution(ray.mOriginObject,
1688                                                                                                                 ray.mPdf,
1689                                                                                                                 contribution))
1690                        {
1691                                ++ ray.mPvsContribution;
1692                                ray.mRelativePvsContribution += contribution;
1693                        }
[718]1694#endif
[664]1695                }
[569]1696        }
[564]1697
[664]1698       
1699        if (addRays)
1700        {
1701                for (it = viewcells.begin(); it != viewcells.end(); ++ it)
1702                {
1703                        ViewCell *viewcell = *it;
1704           
[706]1705                        if (viewcell->GetValid())
[664]1706                        {
1707                                // if ray not outside of view space
[666]1708                                 if (ray.mTerminationObject)
1709                                         viewcell->GetPvs().AddSample(ray.mTerminationObject, ray.mPdf);
[718]1710
1711#if 0
[666]1712                                 if (ray.mOriginObject)
1713                                         viewcell->GetPvs().AddSample(ray.mOriginObject, ray.mPdf);
[718]1714#endif
[664]1715                        }
1716                }
[563]1717        }
[570]1718
1719        return ray.mRelativePvsContribution;
[468]1720}
1721
1722
[469]1723void ViewCellsManager::GetRaySets(const VssRayContainer &sourceRays,
[485]1724                                                                  const int maxSize,
[503]1725                                                                  VssRayContainer &usedRays,
[485]1726                                                                  VssRayContainer *savedRays) const
[469]1727{
[485]1728        const int limit = min(maxSize, (int)sourceRays.size());
[473]1729        const float prop = (float)limit / ((float)sourceRays.size() + Limits::Small);
[469]1730
[485]1731        VssRayContainer::const_iterator it, it_end = sourceRays.end();
[469]1732        for (it = sourceRays.begin(); it != it_end; ++ it)
1733        {
[473]1734                if (Random(1.0f) < prop)
[485]1735                        usedRays.push_back(*it);
1736                else if (savedRays)
1737                        savedRays->push_back(*it);
[469]1738        }
1739}
1740
[477]1741
[728]1742float ViewCellsManager::GetRendercost(ViewCell *viewCell) const
[605]1743{
[728]1744        return mViewCellsTree->GetPvsSize(viewCell);
[605]1745}
1746
1747
[477]1748float ViewCellsManager::GetAccVcArea()
[470]1749{
1750        // if already computed
1751        if (mTotalAreaValid)
[728]1752        {
[470]1753                return mTotalArea;
[728]1754        }
[470]1755
1756        mTotalArea = 0;
1757        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1758
1759        for (it = mViewCells.begin(); it != it_end; ++ it)
[480]1760        {
1761                //Debug << "area: " << GetArea(*it);
[470]1762        mTotalArea += GetArea(*it);
[480]1763        }
1764
[470]1765        mTotalAreaValid = true;
1766
1767        return mTotalArea;
1768}
1769
[482]1770
[475]1771void ViewCellsManager::PrintStatistics(ostream &s) const
1772{
[660]1773        s << mCurrentViewCellsStats << endl;
[475]1774}
1775
[477]1776
[508]1777void ViewCellsManager::CreateUniqueViewCellIds()
[482]1778{
[651]1779        if (ViewCellsTreeConstructed())
1780                mViewCellsTree->CreateUniqueViewCellsIds();
1781        else
1782                for (int i = 0; i < (int)mViewCells.size(); ++ i)
1783                        mViewCells[i]->SetId(i);
[508]1784}
1785
1786
1787void ViewCellsManager::ExportViewCellsForViz(Exporter *exporter) const
1788{
[482]1789        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1790
1791        for (it = mViewCells.begin(); it != it_end; ++ it)
1792        {
[574]1793                if (!mOnlyValidViewCells || (*it)->GetValid())
1794                {
[582]1795                        ExportColor(exporter, *it);             
[591]1796                        ExportViewCellGeometry(exporter, *it,
[660]1797                                mUseClipPlaneForViz ? &mClipPlane : NULL);
[574]1798                }
[482]1799        }
1800}
1801
1802
[517]1803void ViewCellsManager::CreateViewCellMeshes()
[503]1804{
1805        // convert to meshes
1806        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1807
1808        for (it = mViewCells.begin(); it != it_end; ++ it)
1809        {
[517]1810                if (!(*it)->GetMesh())
1811                        CreateMesh(*it);
[503]1812        }
1813}
1814
[508]1815
[564]1816bool ViewCellsManager::ExportViewCells(const string filename)
1817{
[508]1818        return false;
1819}
1820
1821
[610]1822void ViewCellsManager::CollectViewCells(const int n)
[508]1823{
[610]1824        mNumActiveViewCells = n;
1825        mViewCells.clear();
1826        CollectViewCells();
1827}
[508]1828
1829
[660]1830void ViewCellsManager::SetViewCellsActive()
1831{
1832        ++ ViewCell::sLastUpdated;
1833        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
1834        for (it = mViewCells.begin(); it != it_end; ++ it)
1835        {
1836                (*it)->SetActive();
1837        }
1838}
[508]1839
[440]1840/**********************************************************************/
1841/*                   BspViewCellsManager implementation               */
1842/**********************************************************************/
1843
[482]1844
[574]1845BspViewCellsManager::BspViewCellsManager(BspTree *bspTree):
1846ViewCellsManager(), mBspTree(bspTree)
[440]1847{
[574]1848        environment->GetIntValue("BspTree.Construction.samples", mInitialSamples);
[587]1849        mBspTree->SetViewCellsManager(this);
[590]1850        mBspTree->mViewCellsTree = mViewCellsTree;
[440]1851}
1852
[462]1853
[440]1854bool BspViewCellsManager::ViewCellsConstructed() const
1855{
1856        return mBspTree->GetRoot() != NULL;
1857}
1858
[480]1859
[440]1860ViewCell *BspViewCellsManager::GenerateViewCell(Mesh *mesh) const
1861{
1862        return new BspViewCell(mesh);
1863}
1864
[480]1865
[574]1866int BspViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
1867                                                                                          const VssRayContainer &rays)
[440]1868{
[441]1869        // if view cells were already constructed
[440]1870        if (ViewCellsConstructed())
1871                return 0;
1872
1873        int sampleContributions = 0;
[503]1874
[469]1875        // construct view cells using the collected samples
1876        RayContainer constructionRays;
1877        VssRayContainer savedRays;
[440]1878
[574]1879        const int limit = min(mInitialSamples, (int)rays.size());
[440]1880
[469]1881        VssRayContainer::const_iterator it, it_end = rays.end();
[448]1882
[473]1883        const float prop = (float)limit / ((float)rays.size() + Limits::Small);
1884
[469]1885        for (it = rays.begin(); it != it_end; ++ it)
1886        {
[473]1887                if (Random(1.0f) < prop)
[469]1888                        constructionRays.push_back(new Ray(*(*it)));
1889                else
1890                        savedRays.push_back(*it);
1891        }
[440]1892
[503]1893    if (mViewCells.empty())
1894        {
1895                // no view cells loaded
[587]1896                mBspTree->Construct(objects, constructionRays, &mViewSpaceBox);
[469]1897                // collect final view cells
1898                mBspTree->CollectViewCells(mViewCells);
[503]1899        }
[469]1900        else
1901        {
1902                mBspTree->Construct(mViewCells);
1903        }
1904
1905        // destroy rays created only for construction
1906        CLEAR_CONTAINER(constructionRays);
1907
[440]1908        Debug << mBspTree->GetStatistics() << endl;
[503]1909
1910        //EvaluateViewCellsStats();
[660]1911        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
[480]1912
[469]1913        // recast rest of the rays
[649]1914        if (SAMPLE_AFTER_SUBDIVISION)
1915                ComputeSampleContributions(savedRays, true, false);
[469]1916
[719]1917        // real meshes are contructed at this stage
1918        if (0)
1919        {
1920                cout << "finalizing view cells ... ";
1921                FinalizeViewCells(true);
1922                cout << "finished" << endl;     
1923        }
1924
[440]1925        return sampleContributions;
1926}
1927
[503]1928
[480]1929void BspViewCellsManager::CollectViewCells()
1930{
[587]1931        // view cells tree constructed
1932        if (!ViewCellsTreeConstructed())
[591]1933        {               
[587]1934                mBspTree->CollectViewCells(mViewCells);
1935        }
1936        else
1937        {
1938                // we can use the view cells tree hierarchy to get the right set
[591]1939                mViewCellsTree->CollectBestViewCellSet(mViewCells,
[600]1940                                                                                           mNumActiveViewCells);
[587]1941        }
[480]1942}
[468]1943
[503]1944
[471]1945float BspViewCellsManager::GetProbability(ViewCell *viewCell)
[440]1946{
[471]1947        // compute view cell area as subsititute for probability
[591]1948        if (1)
1949                return GetVolume(viewCell) / GetViewSpaceBox().GetVolume();
1950        else
1951                return GetArea(viewCell) / GetAccVcArea();
[466]1952}
[440]1953
[503]1954
[440]1955
[468]1956int BspViewCellsManager::CastLineSegment(const Vector3 &origin,
1957                                                                                 const Vector3 &termination,
1958                                                                                 ViewCellContainer &viewcells)
[440]1959{
[468]1960        return mBspTree->CastLineSegment(origin, termination, viewcells);
1961}
1962
1963
[503]1964int BspViewCellsManager::PostProcess(const ObjectContainer &objects,
[468]1965                                                                         const VssRayContainer &rays)
1966{
[469]1967        if (!ViewCellsConstructed())
[441]1968        {
1969                Debug << "view cells not constructed" << endl;
1970                return 0;
1971        }
[590]1972       
1973        // view cells already finished before post processing step (i.e. because they were loaded)
1974        if (mViewCellsFinished)
1975        {
1976                FinalizeViewCells(true);
1977                EvaluateViewCellsStats();
1978
1979                return 0;
1980        }
1981
[440]1982        //-- post processing of bsp view cells
[600]1983
[440]1984    int vcSize = 0;
1985        int pvsSize = 0;
1986
[591]1987        //-- merge view cells
[649]1988        cout << "starting post processing using " << mPostProcessSamples << " samples ... ";
1989        long startTime = GetTime();
1990       
1991        VssRayContainer postProcessRays;
1992        GetRaySets(rays, mPostProcessSamples, postProcessRays);
1993
[592]1994        if (mMergeViewCells)
[591]1995        {
[660]1996                cout << "constructing visibility based merge tree" << endl;
[650]1997                mViewCellsTree->ConstructMergeTree(rays, objects);
[649]1998        }
1999        else
2000        {
[660]2001                cout << "constructing spatial merge tree" << endl;
[752]2002
[649]2003                // create spatial merge hierarchy
[752]2004                ViewCell *root = ConstructSpatialMergeTree(mBspTree->GetRoot());
2005                mViewCellsTree->SetRoot(root);
2006
2007                // compute pvs
2008                ObjectPvs pvs;
2009                UpdatePvsForEvaluation(root, pvs);
[649]2010        }
[440]2011
[660]2012        // export statistics after merge
[666]2013        if (1)
2014        {
2015                char mstats[100];
2016                environment->GetStringValue("ViewCells.mergeStats", mstats);
2017                mViewCellsTree->ExportStats(mstats);
2018        }
[650]2019
[649]2020        //-- stats and visualizations
2021        cout << "finished" << endl;
[650]2022        cout << "merged view cells in "
[752]2023                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
[440]2024
[650]2025        Debug << "Postprocessing: Merged view cells in "
[752]2026                << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl << endl;
[649]2027       
[503]2028
[660]2029        //-- visualization and statistics
[600]2030    // reset view cells and stats
[480]2031        ResetViewCells();
[660]2032        Debug << "\nView cells after merge:\n" << mCurrentViewCellsStats << endl;
[600]2033
[660]2034
[600]2035        int savedColorCode  = mColorCode;
[605]2036       
[600]2037        //BspLeaf::NewMail();
2038        if (1) // export merged view cells
2039        {
2040                mColorCode = 0;
[605]2041               
[744]2042                Exporter *exporter = Exporter::GetExporter("merged_view_cells.wrl");
[605]2043               
[600]2044
2045                cout << "exporting view cells after merge ... ";
2046
2047                if (exporter)
2048                {
2049                        if (mExportGeometry)
2050                                exporter->ExportGeometry(objects);
2051
2052                        //exporter->SetWireframe();
2053                        exporter->SetFilled();
2054                        ExportViewCellsForViz(exporter);
2055
2056
2057                        delete exporter;
2058                }
2059                cout << "finished" << endl;
2060        }
2061
[752]2062        if (1) // export merged view cells using pvs color coding
[600]2063        {
2064                mColorCode = 1;
2065
[744]2066                Exporter *exporter = Exporter::GetExporter("merged_view_cells_pvs.wrl");
[600]2067       
2068                cout << "exporting view cells after merge (pvs size) ... ";     
2069
2070                if (exporter)
2071                {
2072                        //exporter->SetWireframe();
[752]2073                        //exporter->SetForcedMaterial(RandomMaterial());
2074
[600]2075                        if (mExportGeometry)
2076                                exporter->ExportGeometry(objects);
2077
2078                        //exporter->SetWireframe();
2079                        exporter->SetFilled();
2080                        ExportViewCellsForViz(exporter);
2081
2082                        delete exporter;
2083                }
2084                cout << "finished" << endl;
2085        }
2086
[693]2087       
2088        // only for testing
2089        TestSubdivision();
2090
[600]2091        mColorCode = savedColorCode;
2092
[719]2093        // compute final meshes and volume / area
2094        if (1) FinalizeViewCells(true);
2095
[587]2096        // write view cells to disc
2097        if (mExportViewCells)
2098        {
2099                char buff[100];
2100                environment->GetStringValue("ViewCells.filename", buff);
2101                string vcFilename(buff);
2102
2103                ExportViewCells(buff);
2104        }
2105
[650]2106        return 0;
[440]2107}
2108
[477]2109
2110BspViewCellsManager::~BspViewCellsManager()
2111{
2112}
2113
2114
[440]2115int BspViewCellsManager::GetType() const
2116{
2117        return BSP;
2118}
2119
2120
2121void BspViewCellsManager::Visualize(const ObjectContainer &objects,
[466]2122                                                                        const VssRayContainer &sampleRays)
[440]2123{
[469]2124        if (!ViewCellsConstructed())
2125                return;
[574]2126       
[600]2127        int savedColorCode = mColorCode;
2128
2129       
2130       
2131        if (1) // export final view cells
[440]2132        {
[600]2133                mColorCode = 1;
[587]2134
[712]2135                Exporter *exporter = Exporter::GetExporter("final_view_cells.wrl");
[600]2136       
2137                cout << "exporting view cells after merge (pvs size) ... ";     
[587]2138
[469]2139                if (exporter)
[440]2140                {
[600]2141                        //exporter->SetWireframe();
2142                       
2143                        if (mExportGeometry)
2144                                exporter->ExportGeometry(objects);
[590]2145
[600]2146                        //exporter->SetWireframe();
2147                        exporter->SetFilled();
[508]2148                        ExportViewCellsForViz(exporter);
[587]2149
[469]2150                        delete exporter;
[440]2151                }
[469]2152                cout << "finished" << endl;
[503]2153        }
[477]2154
[600]2155        mColorCode = savedColorCode;
2156
[469]2157        //-- visualization of the BSP splits
2158        bool exportSplits = false;
2159        environment->GetBoolValue("BspTree.Visualization.exportSplits", exportSplits);
[503]2160
[469]2161        if (exportSplits)
[440]2162        {
[469]2163                cout << "exporting splits ... ";
[477]2164                ExportSplits(objects);
[469]2165                cout << "finished" << endl;
[440]2166        }
[477]2167
[600]2168        // export single view cells
[477]2169        ExportBspPvs(objects);
[440]2170}
2171
2172
[503]2173inline bool vc_gt(ViewCell *a, ViewCell *b)
2174{
[440]2175        return a->GetPvs().GetSize() > b->GetPvs().GetSize();
2176}
2177
[477]2178
2179void BspViewCellsManager::ExportSplits(const ObjectContainer &objects)
[440]2180{
2181        Exporter *exporter = Exporter::GetExporter("bsp_splits.x3d");
2182
[503]2183        if (exporter)
2184        {
[598]2185                //exporter->SetFilled();
2186
2187                if (mExportGeometry)
2188                        exporter->ExportGeometry(objects);
2189
[503]2190                Material m;
[440]2191                m.mDiffuseColor = RgbColor(1, 0, 0);
2192                exporter->SetForcedMaterial(m);
2193                exporter->SetWireframe();
[503]2194
[440]2195                exporter->ExportBspSplits(*mBspTree, true);
2196
[482]2197                //NOTE: take forced material, else big scenes cannot be viewed
[440]2198                m.mDiffuseColor = RgbColor(0, 1, 0);
2199                exporter->SetForcedMaterial(m);
[482]2200                //exporter->ResetForcedMaterial();
2201
[440]2202                delete exporter;
2203        }
2204}
2205
[477]2206
2207void BspViewCellsManager::ExportBspPvs(const ObjectContainer &objects)
[440]2208{
[477]2209        const int leafOut = 10;
[503]2210
[477]2211        ViewCell::NewMail();
[440]2212
[477]2213        //-- some rays for output
2214        const int raysOut = min((int)mBspRays.size(), mVisualizationSamples);
[503]2215
[477]2216        cout << "visualization using " << mVisualizationSamples << " samples" << endl;
2217        Debug << "\nOutput view cells: " << endl;
[503]2218
[478]2219        // sort view cells to get largest view cells
[587]2220        if (0)
2221                stable_sort(mViewCells.begin(), mViewCells.end(), vc_gt);
2222
[503]2223        int limit = min(leafOut, (int)mViewCells.size());
2224
[478]2225        for (int i = 0; i < limit; ++ i)
[477]2226        {
[478]2227                cout << "creating output for view cell " << i << " ... ";
2228                VssRayContainer vcRays;
2229                Intersectable::NewMail();
[582]2230                ViewCell *vc;
2231
2232                if (0)
2233                        vc = mViewCells[i];
2234                else
2235                        vc = mViewCells[Random((int)mViewCells.size())];
2236
[478]2237                cout << "creating output for view cell " << i << " ... ";
[469]2238
[587]2239                if(0)
[477]2240                {
[587]2241                        // check whether we can add the current ray to the output rays
2242                        for (int k = 0; k < raysOut; ++ k)
[477]2243                        {
[587]2244                                BspRay *ray = mBspRays[k];
2245                                for     (int j = 0; j < (int)ray->intersections.size(); ++ j)
2246                                {
2247                                        BspLeaf *leaf = ray->intersections[j].mLeaf;
2248                                        if (vc == leaf->GetViewCell())
2249                                                vcRays.push_back(ray->vssRay);
2250                                }
[477]2251                        }
2252                }
[587]2253
[478]2254                //bspLeaves[j]->Mail();
2255                char s[64]; sprintf(s, "bsp-pvs%04d.x3d", i);
[477]2256
[478]2257                Exporter *exporter = Exporter::GetExporter(s);
[503]2258
[478]2259                exporter->SetWireframe();
[477]2260
[478]2261                Material m;//= RandomMaterial();
2262                m.mDiffuseColor = RgbColor(0, 1, 0);
2263                exporter->SetForcedMaterial(m);
[477]2264
[587]2265                ExportViewCellGeometry(exporter, vc);
2266               
[478]2267                // export rays piercing this view cell
2268                exporter->ExportRays(vcRays, RgbColor(0, 1, 0));
[580]2269
[478]2270                m.mDiffuseColor = RgbColor(1, 0, 0);
2271                exporter->SetForcedMaterial(m);
[440]2272
[478]2273                ObjectPvsMap::const_iterator it,
2274                        it_end = vc->GetPvs().mEntries.end();
[440]2275
[478]2276                exporter->SetFilled();
[469]2277
[478]2278                // output PVS of view cell
[503]2279                for (it = vc->GetPvs().mEntries.begin(); it != it_end; ++ it)
[478]2280                {
2281                        Intersectable *intersect = (*it).first;
[469]2282
[478]2283                        if (!intersect->Mailed())
2284                        {
2285                                Material m = RandomMaterial();
2286                                exporter->SetForcedMaterial(m);
2287
2288                                exporter->ExportIntersectable(intersect);
2289                                intersect->Mail();
[503]2290                        }
[477]2291                }
[503]2292
[478]2293                DEL_PTR(exporter);
2294                cout << "finished" << endl;
[477]2295        }
2296
2297        Debug << endl;
[440]2298}
2299
[441]2300
[503]2301void BspViewCellsManager::ExportColor(Exporter *exporter,
[482]2302                                                                          ViewCell *vc) const
2303{
[600]2304        const bool vcValid = CheckValidity(vc, mMinPvsSize, mMaxPvsSize);
[482]2305
2306        float importance = 0;
[598]2307        static Material m;
[482]2308
2309        switch (mColorCode)
2310        {
[598]2311        case 0: // Random
2312                {
2313                        if (vcValid)
2314                        {
2315                                m.mDiffuseColor.r = 0.5f + RandomValue(0.0f, 0.5f);
2316                                m.mDiffuseColor.g = 0.5f + RandomValue(0.0f, 0.5f);
[600]2317                                m.mDiffuseColor.b = 0.5f + RandomValue(0.0f, 0.5f);
[598]2318                        }
2319                        else
2320                        {
2321                                m.mDiffuseColor.r = 0.0f;
2322                                m.mDiffuseColor.g = 1.0f;
2323                                m.mDiffuseColor.b = 0.0f;
2324                        }
2325
2326                        exporter->SetForcedMaterial(m);
2327                        return;
2328                }
2329               
[482]2330        case 1: // pvs
2331                {
[503]2332                        importance = (float)vc->GetPvs().GetSize() /
[660]2333                                (float)mCurrentViewCellsStats.maxPvs;
[598]2334
[482]2335                }
2336                break;
2337        case 2: // merges
2338                {
[736]2339            int lSize = mViewCellsTree->GetNumInitialViewCells(vc);
[660]2340                        importance = (float)lSize / (float)mCurrentViewCellsStats.maxLeaves;
[482]2341                }
[598]2342                //break;
[482]2343        case 3: // merge tree differene
2344                {
2345                        // TODO
[598]2346                        //importance = (float)GetMaxTreeDiff(vc) /
2347                        //      (float)(mVspBspTree->GetStatistics().maxDepth * 2);
2348
[482]2349                }
2350                break;
2351        default:
2352                break;
2353        }
2354
[598]2355        // special color code for invalid view cells
[482]2356        m.mDiffuseColor.r = importance;
2357        m.mDiffuseColor.g = 1.0f - m.mDiffuseColor.r;
[598]2358        m.mDiffuseColor.b = vcValid ? 1.0f : 0.0f;
[503]2359
[598]2360        //Debug << "importance: " << importance << endl;
[482]2361        exporter->SetForcedMaterial(m);
2362}
2363
[587]2364
[693]2365void BspViewCellsManager::TestSubdivision()
2366{
2367        ViewCellContainer leaves;
2368        mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
2369
2370        ViewCellContainer::const_iterator it, it_end = leaves.end();
2371
2372        const float vol = mViewSpaceBox.GetVolume();
2373        float subdivVol = 0;
2374        float newVol = 0;
2375
2376        for (it = leaves.begin(); it != it_end; ++ it)
2377        {
2378                BspNodeGeometry geom;
2379                BspLeaf *leaf = dynamic_cast<BspViewCell *>(*it)->mLeaf;
2380                mBspTree->ConstructGeometry(leaf, geom);
2381
2382                const float lVol = geom.GetVolume();
2383               
2384                newVol += lVol;
2385                subdivVol += (*it)->GetVolume();
[694]2386
[704]2387                float thres = 0.9f;
[694]2388                if ((lVol < ((*it)->GetVolume() * thres)) ||
2389                        (lVol * thres > ((*it)->GetVolume())))
2390                        Debug << "warning: " << lVol << " " << (*it)->GetVolume() << endl;
[693]2391        }
2392       
2393        Debug << "exact volume: " << vol << endl;
2394        Debug << "subdivision volume: " << subdivVol << endl;
2395        Debug << "new volume: " << newVol << endl;
2396}
2397
2398
[580]2399void BspViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
[591]2400                                                                                                 ViewCell *vc,
[660]2401                                                                                                 const Plane3 *clipPlane) const
[482]2402{
2403        if (vc->GetMesh())
2404        {
[587]2405                exporter->ExportMesh(vc->GetMesh());
[726]2406       
[587]2407                return;
[482]2408        }
[587]2409
[726]2410       
[660]2411        if (clipPlane)
[591]2412        {
[726]2413                ViewCellContainer leaves;
2414                mViewCellsTree->CollectLeaves(vc, leaves);
2415                ViewCellContainer::const_iterator it, it_end = leaves.end();
[591]2416
[726]2417                for (it = leaves.begin(); it != it_end; ++ it)
[681]2418                {
[726]2419                        BspNodeGeometry geom;
2420
[681]2421                        BspNodeGeometry front;
2422                        BspNodeGeometry back;
[591]2423
[726]2424                        BspLeaf *leaf = dynamic_cast<BspViewCell *>(*it)->mLeaf;
2425                        mBspTree->ConstructGeometry(leaf, geom);
[681]2426
[726]2427                        const float eps = 0.00000001f;
2428                        const int cf = geom.Side(*clipPlane, eps);
2429
2430                        if (cf == -1)
2431                        {
2432                                exporter->ExportPolygons(geom.GetPolys());
2433                        }
2434                        else if (cf == 0)
2435                        {
2436                                geom.SplitGeometry(front,
2437                                                                   back,
2438                                                                   *clipPlane,
2439                                                                   mViewSpaceBox,
2440                                                                   eps);
2441       
2442                                //Debug << "geo size: " << geom.Size() << endl;
2443                                //Debug << "size b: " << back.Size() << " f: " << front.Size() << endl;
2444                                if (back.Valid())
2445                                {
2446                                        exporter->ExportPolygons(back.GetPolys());
2447                                }                       
2448                        }
[681]2449                }
[591]2450        }
2451        else
2452        {
[726]2453                BspNodeGeometry geom;
2454                mBspTree->ConstructGeometry(vc, geom);
2455                       
[678]2456                exporter->ExportPolygons(geom.GetPolys());
[591]2457        }
[482]2458}
2459
[503]2460
2461void BspViewCellsManager::CreateMesh(ViewCell *vc)
2462{
[726]2463        // delete previous mesh
2464        ///DEL_PTR(vc->GetMesh());
[587]2465        BspNodeGeometry geom;
2466        mBspTree->ConstructGeometry(vc, geom);
2467
2468        Mesh *mesh = new Mesh();
[726]2469
[587]2470        geom.AddToMesh(*mesh);
2471        vc->SetMesh(mesh);
[726]2472        // put mesh into mesh container so we can savely delete it
[587]2473        mMeshContainer.push_back(mesh);
[503]2474}
2475
[551]2476
[587]2477void BspViewCellsManager::Finalize(ViewCell *viewCell,
2478                                                                   const bool createMesh)
[502]2479{
[587]2480        float area = 0;
2481        float volume = 0;
[572]2482
[587]2483        ViewCellContainer leaves;
2484        mViewCellsTree->CollectLeaves(viewCell, leaves);
2485
2486        ViewCellContainer::const_iterator it, it_end = leaves.end();
2487
[693]2488    for (it = leaves.begin(); it != it_end; ++ it)
[587]2489        {
2490                BspNodeGeometry geom;
2491                BspLeaf *leaf = dynamic_cast<BspViewCell *>(*it)->mLeaf;
2492                mBspTree->ConstructGeometry(leaf, geom);
2493
[719]2494                const float lVol = geom.GetVolume();
2495                const float lArea = geom.GetArea();
[693]2496
2497                //(*it)->SetVolume(vol);
2498                //(*it)->SetArea(area);
2499
2500                area += lArea;
2501                volume += lVol;
2502
2503        CreateMesh(*it);
[587]2504        }
2505
2506        viewCell->SetVolume(volume);
2507        viewCell->SetArea(area);
[502]2508}
2509
[580]2510
[587]2511ViewCell *BspViewCellsManager::GetViewCell(const Vector3 &point) const
[580]2512{
[587]2513        if (!mBspTree)
2514                return NULL;
2515
2516        if (!mViewSpaceBox.IsInside(point))
2517                return NULL;
2518       
2519        return mBspTree->GetViewCell(point);
[580]2520}
2521
2522
[587]2523void BspViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
2524                                                                                                 vector<MergeCandidate> &candidates)
2525{
2526        cout << "collecting merge candidates ... " << endl;
2527
2528        if (mUseRaysForMerge)
2529        {
2530                mBspTree->CollectMergeCandidates(rays, candidates);
2531        }
2532        else
2533        {
2534                vector<BspLeaf *> leaves;
2535                mBspTree->CollectLeaves(leaves);
2536                mBspTree->CollectMergeCandidates(leaves, candidates);
2537        }
2538
2539        cout << "fininshed collecting candidates" << endl;
2540}
2541
2542
[440]2543
[590]2544bool BspViewCellsManager::ExportViewCells(const string filename)
2545{
2546        cout << "exporting view cells to xml ... ";
2547        std::ofstream stream;
[503]2548
[590]2549        // for output we need unique ids for each view cell
2550        CreateUniqueViewCellIds();
[503]2551
[590]2552
2553        stream.open(filename.c_str());
2554        stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<endl;
2555        stream << "<Visibility_Solution>" << endl;
2556
2557        //-- the view space bounding box
2558        stream << "<ViewSpaceBox"
2559                   << " min=\"" << mViewSpaceBox.Min().x << " " << mViewSpaceBox.Min().y << " " << mViewSpaceBox.Min().z << "\""
2560                   << " max=\"" << mViewSpaceBox.Max().x << " " << mViewSpaceBox.Max().y << " " << mViewSpaceBox.Max().z << "\" />" << endl;
2561
2562        //-- the type of the view cells hierarchy
2563        //stream << "<Hierarchy name=\"bspTree\" />" << endl;
2564        stream << "<Hierarchy name=\"vspBspTree\" />" << endl; // write vsp bsp here because can use same tree and is bug free
2565        //-- load the view cells itself, i.e., the ids and the pvs
2566        stream << "<ViewCells>" << endl;
[610]2567
2568#if 0
2569       
[590]2570        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
[610]2571               
[590]2572        for (it = mViewCells.begin(); it != it_end; ++ it)
2573                ExportViewCell(*it, stream);
[610]2574#else
2575        mViewCellsTree->Export(stream);
2576#endif
[590]2577
2578        stream << "</ViewCells>" << endl;
2579
2580        //-- load the hierarchy
2581        stream << "<Hierarchy>" << endl;
2582        mBspTree->Export(stream);
2583        stream << endl << "</Hierarchy>" << endl;
2584
2585        stream << "</Visibility_Solution>" << endl;
2586        stream.close();
2587
2588        cout << "finished" << endl;
2589
2590        return true;
2591}
2592
2593
2594void BspViewCellsManager::AddCurrentViewCellsToHierarchy()
2595{
2596        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
2597        for (it = mViewCells.begin(); it != it_end; ++ it)
2598        {
2599                ViewCell *vc = *it;
2600                ViewCellContainer leaves;
2601                mViewCellsTree->CollectLeaves(vc, leaves);
2602               
2603                ViewCellContainer::const_iterator lit, lit_end = leaves.end();
2604
2605                for (lit = leaves.begin(); lit != lit_end; ++ lit)
2606                {
2607                        BspViewCell *bspVc = dynamic_cast<BspViewCell *>(*lit);
2608                        bspVc->mLeaf->SetViewCell(vc);
2609                }
2610        }
2611}
2612
[610]2613
[650]2614ViewCell *BspViewCellsManager::ConstructSpatialMergeTree(BspNode *root)
[610]2615{
[752]2616        // terminate recursion
[650]2617        if (root->IsLeaf())
2618        {
[752]2619                BspLeaf *leaf = dynamic_cast<BspLeaf *>(root);
2620                leaf->GetViewCell()->SetMergeCost(0.0f);
2621                return leaf->GetViewCell();
[650]2622        }
2623       
2624        BspInterior *interior = dynamic_cast<BspInterior *>(root);
2625        ViewCellInterior *viewCellInterior = new ViewCellInterior();
2626               
[752]2627        // evaluate merge cost for priority traversal
[650]2628        float mergeCost = 1.0f / (float)root->mTimeStamp;
2629        viewCellInterior->SetMergeCost(mergeCost);
[649]2630
[650]2631        float volume = 0;
[649]2632       
[650]2633        BspNode *front = interior->GetFront();
2634        BspNode *back = interior->GetBack();
[649]2635
[752]2636
2637        //-- recursivly compute child hierarchies
[650]2638        ViewCell *backVc = ConstructSpatialMergeTree(back);
2639        ViewCell *frontVc = ConstructSpatialMergeTree(front);
[610]2640
[752]2641
2642        viewCellInterior->SetupChildLink(backVc);
[650]2643        viewCellInterior->SetupChildLink(frontVc);
[610]2644
[650]2645        volume += backVc->GetVolume();
2646        volume += frontVc->GetVolume();
[649]2647
[650]2648        viewCellInterior->SetVolume(volume);
[649]2649
[650]2650        return viewCellInterior;
[610]2651}
2652
[650]2653
[752]2654void BspViewCellsManager::UpdatePvsForEvaluation(ViewCell *root, ObjectPvs &pvs)
2655{
2656        // terminate traversal
2657        if (root->IsLeaf())
2658        {
2659                pvs = root->GetPvs();
2660
2661                root->mPvsSize = pvs.GetSize();
2662                root->mPvsSizeValid = true;
2663
2664                return;
2665        }
2666
2667        ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(root);
2668        ViewCellContainer::const_iterator vit, vit_end = interior->mChildren.end();
2669
2670        vector<ObjectPvs> pvsList;
2671       
2672       
2673        for (vit = interior->mChildren.begin(); vit != vit_end; ++ vit)
2674        {
2675                ObjectPvs objPvs;
2676               
2677                //-- recursivly compute child pvss
2678                UpdatePvsForEvaluation(*vit, objPvs);
2679
2680                // store pvs in vector
2681                pvsList.push_back(objPvs);
2682        }
2683
2684#if 1
2685        Intersectable::NewMail();
2686
2687        //-- faster way of computing pvs:
2688        //   construct merged pvs by adding
2689        //   and only those of the next pvs which were not mailed.
2690        //   note: sumpdf is not correct!!
2691        vector<ObjectPvs>::iterator oit = pvsList.begin();
2692
2693        for (vit = interior->mChildren.begin(); vit != vit_end; ++ vit, ++ oit)
2694        {
2695               
2696        ObjectPvsMap::iterator pit, pit_end = (*oit).mEntries.end();
2697       
2698                for (pit = (*oit).mEntries.begin(); pit != pit_end; ++ pit)
2699                {
2700                       
2701                        Intersectable *intersect = (*pit).first;
2702
2703                        if (!intersect->Mailed())
2704                        {
2705                                pvs.AddSample(intersect, (*pit).second.mSumPdf);
2706                                intersect->Mail();
2707                        }
2708                }
2709        }
2710
2711        // store pvs in this node
2712        if (mViewCellsTree->ViewCellsStorage() == ViewCellsTree::PVS_IN_INTERIORS)
2713        {
2714                interior->mPvs = pvs;
2715        }
2716       
2717        // set new pvs size
2718        interior->mPvsSize = pvs.GetSize();
2719        interior->mPvsSizeValid = true;
2720
2721#else
2722        // really merge cells: slow put sumpdf is correct
2723        ViewCellInterior *viewCellInterior = new ViewCellInterior();
2724
2725        viewCellInterior->GetPvs().Merge(backVc->GetPvs());
2726        viewCellInterior->GetPvs().Merge(frontVc->GetPvs());
2727#endif
2728
2729}
2730
[590]2731/************************************************************************/
2732/*                   KdViewCellsManager implementation                  */
2733/************************************************************************/
2734
2735
2736
[440]2737KdViewCellsManager::KdViewCellsManager(KdTree *kdTree):
[469]2738ViewCellsManager(), mKdTree(kdTree), mKdPvsDepth(100)
[440]2739{
2740}
2741
[605]2742
[471]2743float KdViewCellsManager::GetProbability(ViewCell *viewCell)
[468]2744{
[479]2745        // compute view cell area / volume as subsititute for probability
[605]2746        if (0)
2747                return GetArea(viewCell) / GetViewSpaceBox().SurfaceArea();
2748        else
2749                return GetVolume(viewCell) / GetViewSpaceBox().GetVolume();
[468]2750}
2751
2752
2753
[479]2754
[480]2755void KdViewCellsManager::CollectViewCells()
2756{
2757        //mKdTree->CollectViewCells(mViewCells); TODO
2758}
[479]2759
[519]2760
[574]2761int KdViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
[487]2762                                                                  const VssRayContainer &rays)
[440]2763{
[441]2764        // if view cells already constructed
[440]2765        if (ViewCellsConstructed())
2766                return 0;
[441]2767
[440]2768        mKdTree->Construct();
2769
[480]2770        mTotalAreaValid = false;
[469]2771        // create the view cells
2772        mKdTree->CreateAndCollectViewCells(mViewCells);
[503]2773
[480]2774        // cast rays
[574]2775        ComputeSampleContributions(rays, true, false);
[480]2776
[479]2777        EvaluateViewCellsStats();
[660]2778        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
[469]2779
[440]2780        return 0;
2781}
2782
[587]2783
[440]2784bool KdViewCellsManager::ViewCellsConstructed() const
2785{
2786        return mKdTree->GetRoot() != NULL;
2787}
2788
[503]2789int KdViewCellsManager::PostProcess(const ObjectContainer &objects,
[466]2790                                                                        const VssRayContainer &rays)
[440]2791{
2792        return 0;
2793}
2794
2795void KdViewCellsManager::Visualize(const ObjectContainer &objects,
[466]2796                                                                   const VssRayContainer &sampleRays)
[440]2797{
[441]2798        if (!ViewCellsConstructed())
2799                return;
2800
[469]2801        // using view cells instead of the kd PVS of objects
2802        const bool useViewCells = true;
2803        bool exportRays = false;
[440]2804
2805        int limit = min(mVisualizationSamples, (int)sampleRays.size());
[469]2806        const int pvsOut = min((int)objects.size(), 10);
[466]2807        VssRayContainer *rays = new VssRayContainer[pvsOut];
[440]2808
[469]2809        if (useViewCells)
[440]2810        {
[469]2811                const int leafOut = 10;
[503]2812
[469]2813                ViewCell::NewMail();
[503]2814
[469]2815                //-- some rays for output
2816                const int raysOut = min((int)sampleRays.size(), mVisualizationSamples);
2817                Debug << "visualization using " << raysOut << " samples" << endl;
2818
2819                //-- some random view cells and rays for output
2820                vector<KdLeaf *> kdLeaves;
[503]2821
[469]2822                for (int i = 0; i < leafOut; ++ i)
2823                        kdLeaves.push_back(dynamic_cast<KdLeaf *>(mKdTree->GetRandomLeaf()));
[503]2824
[469]2825                for (int i = 0; i < kdLeaves.size(); ++ i)
[440]2826                {
[469]2827                        KdLeaf *leaf = kdLeaves[i];
2828                        RayContainer vcRays;
[503]2829
[469]2830                        cout << "creating output for view cell " << i << " ... ";
[503]2831#if 0
[469]2832                        // check whether we can add the current ray to the output rays
[503]2833                        for (int k = 0; k < raysOut; ++ k)
[440]2834                        {
[469]2835                                Ray *ray = sampleRays[k];
[503]2836
[469]2837                                for (int j = 0; j < (int)ray->bspIntersections.size(); ++ j)
2838                                {
2839                                        BspLeaf *leaf2 = ray->bspIntersections[j].mLeaf;
[503]2840
2841                                        if (leaf->GetViewCell() == leaf2->GetViewCell())
[469]2842                                        {
2843                                                vcRays.push_back(ray);
2844                                        }
2845                                }
[479]2846                        }
[503]2847#endif
[469]2848                        Intersectable::NewMail();
[503]2849
[469]2850                        ViewCell *vc = leaf->mViewCell;
[503]2851
[469]2852                        //bspLeaves[j]->Mail();
2853                        char s[64]; sprintf(s, "kd-pvs%04d.x3d", i);
[503]2854
[469]2855                        Exporter *exporter = Exporter::GetExporter(s);
2856                        exporter->SetFilled();
2857
2858                        exporter->SetWireframe();
2859                        //exporter->SetFilled();
[503]2860
[469]2861                        Material m;//= RandomMaterial();
2862                        m.mDiffuseColor = RgbColor(1, 1, 0);
2863                        exporter->SetForcedMaterial(m);
[503]2864
[469]2865                        AxisAlignedBox3 box = mKdTree->GetBox(leaf);
2866                        exporter->ExportBox(box);
2867
2868                        // export rays piercing this view cell
[503]2869                        exporter->ExportRays(vcRays, 1000, RgbColor(0, 1, 0));
2870
[469]2871                        m.mDiffuseColor = RgbColor(1, 0, 0);
2872                        exporter->SetForcedMaterial(m);
[503]2873
[469]2874                        // exporter->SetWireframe();
2875                        exporter->SetFilled();
[503]2876
[469]2877                        ObjectPvsMap::iterator it, it_end = vc->GetPvs().mEntries.end();
[752]2878                        // -- output PVS of view cell
[503]2879                        for (it = vc->GetPvs().mEntries.begin(); it !=  it_end; ++ it)
[469]2880                        {
2881                                Intersectable *intersect = (*it).first;
2882                                if (!intersect->Mailed())
2883                                {
2884                                        exporter->ExportIntersectable(intersect);
2885                                        intersect->Mail();
[503]2886                                }
[440]2887                        }
[503]2888
[469]2889                        DEL_PTR(exporter);
2890                        cout << "finished" << endl;
[440]2891                }
[469]2892
2893                DEL_PTR(rays);
[440]2894        }
[469]2895        else // using kd PVS of objects
2896        {
2897                for (int i = 0; i < limit; ++ i)
2898                {
2899                        VssRay *ray = sampleRays[i];
[503]2900
[469]2901                        // check whether we can add this to the rays
[503]2902                        for (int j = 0; j < pvsOut; j++)
[469]2903                        {
2904                                if (objects[j] == ray->mTerminationObject)
2905                                {
2906                                        rays[j].push_back(ray);
2907                                }
2908                        }
2909                }
[440]2910
[503]2911                if (exportRays)
[469]2912                {
2913                        Exporter *exporter = NULL;
2914                        exporter = Exporter::GetExporter("sample-rays.x3d");
2915                        exporter->SetWireframe();
2916                        exporter->ExportKdTree(*mKdTree);
[503]2917
[728]2918                        for (i = 0; i < pvsOut; i++)
[469]2919                                exporter->ExportRays(rays[i], RgbColor(1, 0, 0));
2920
2921                        exporter->SetFilled();
[503]2922
[469]2923                        delete exporter;
2924                }
[440]2925
[503]2926                for (int k=0; k < pvsOut; k++)
[469]2927                {
2928                        Intersectable *object = objects[k];
[503]2929                        char s[64];
[469]2930                        sprintf(s, "sample-pvs%04d.x3d", k);
[440]2931
[469]2932                        Exporter *exporter = Exporter::GetExporter(s);
2933                        exporter->SetWireframe();
[503]2934
[469]2935                        KdPvsMap::iterator i = object->mKdPvs.mEntries.begin();
2936                        Intersectable::NewMail();
[503]2937
[469]2938                        // avoid adding the object to the list
2939                        object->Mail();
2940                        ObjectContainer visibleObjects;
[503]2941
2942                        for (; i != object->mKdPvs.mEntries.end(); i++)
[469]2943                        {
2944                                KdNode *node = (*i).first;
2945                                exporter->ExportBox(mKdTree->GetBox(node));
[503]2946
[469]2947                                mKdTree->CollectObjects(node, visibleObjects);
2948                        }
[503]2949
[469]2950                        exporter->ExportRays(rays[k],  RgbColor(0, 1, 0));
2951                        exporter->SetFilled();
[503]2952
[469]2953                        for (int j = 0; j < visibleObjects.size(); j++)
2954                                exporter->ExportIntersectable(visibleObjects[j]);
[503]2955
[469]2956                        Material m;
2957                        m.mDiffuseColor = RgbColor(1, 0, 0);
2958                        exporter->SetForcedMaterial(m);
2959                        exporter->ExportIntersectable(object);
[503]2960
[469]2961                        delete exporter;
[440]2962                }
[503]2963        }
[440]2964}
2965
[469]2966
[482]2967void KdViewCellsManager::ExportColor(Exporter *exporter,
2968                                                                         ViewCell *vc) const
2969{
2970        // TODO
2971}
2972
[666]2973
[580]2974ViewCell *KdViewCellsManager::GenerateViewCell(Mesh *mesh) const
2975{
2976        return new KdViewCell(mesh);
2977}
[482]2978
[580]2979
2980void KdViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
[591]2981                                                                                                ViewCell *vc,
[660]2982                                                                                                const Plane3 *clipPlane) const
[482]2983{
[580]2984        ViewCellContainer leaves;
[485]2985
[580]2986        mViewCellsTree->CollectLeaves(vc, leaves);
2987        ViewCellContainer::const_iterator it, it_end = leaves.end();
2988
2989        for (it = leaves.begin(); it != it_end; ++ it)
2990        {
2991                KdViewCell *kdVc = dynamic_cast<KdViewCell *>(*it);
2992       
2993                exporter->ExportBox(mKdTree->GetBox(kdVc->mLeaf));
2994        }
[482]2995}
2996
2997
[440]2998int KdViewCellsManager::GetType() const
2999{
3000        return ViewCellsManager::KD;
3001}
3002
3003
[441]3004
[440]3005KdNode *KdViewCellsManager::GetNodeForPvs(KdLeaf *leaf)
3006{
3007        KdNode *node = leaf;
3008
3009        while (node->mParent && node->mDepth > mKdPvsDepth)
3010                node = node->mParent;
3011        return node;
3012}
3013
[469]3014int KdViewCellsManager::CastLineSegment(const Vector3 &origin,
3015                                                                                const Vector3 &termination,
3016                                                                                ViewCellContainer &viewcells)
[466]3017{
[469]3018        return mKdTree->CastLineSegment(origin, termination, viewcells);
[466]3019}
3020
[469]3021
[503]3022void KdViewCellsManager::CreateMesh(ViewCell *vc)
3023{
[551]3024        // TODO
[503]3025}
3026
[580]3027
3028
3029void KdViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
3030                                                                                                vector<MergeCandidate> &candidates)
3031{
3032        // TODO
3033}
3034
3035
[440]3036/**********************************************************************/
3037/*                   VspKdViewCellsManager implementation             */
3038/**********************************************************************/
3039
[482]3040
[574]3041VspKdViewCellsManager::VspKdViewCellsManager(VspKdTree *vspKdTree):
3042ViewCellsManager(), mVspKdTree(vspKdTree)
[440]3043{
[574]3044        environment->GetIntValue("VspKdTree.Construction.samples", mInitialSamples);
[468]3045        mVspKdTree->SetViewCellsManager(this);
3046}
[462]3047
[471]3048float VspKdViewCellsManager::GetProbability(ViewCell *viewCell)
[468]3049{
[605]3050        // compute view cell area / volume as subsititute for probability
3051        if (0)
3052                return GetArea(viewCell) / GetViewSpaceBox().SurfaceArea();
3053        else
3054                return GetVolume(viewCell) / GetViewSpaceBox().GetVolume();
[440]3055}
3056
[462]3057
[468]3058
[503]3059
[480]3060void VspKdViewCellsManager::CollectViewCells()
3061{
3062        mVspKdTree->CollectViewCells(mViewCells);
3063}
[462]3064
[570]3065
[574]3066int VspKdViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
3067                                                                                                const VssRayContainer &rays)
[440]3068{
[441]3069        // if view cells already constructed
[440]3070        if (ViewCellsConstructed())
3071                return 0;
[503]3072
[469]3073        VssRayContainer constructionRays;
3074        VssRayContainer savedRays;
[440]3075
[503]3076        GetRaySets(rays,
[574]3077                           mInitialSamples,
[503]3078                           constructionRays,
[485]3079                           &savedRays);
[503]3080
3081        Debug << "constructing vsp kd tree using "
[469]3082                  << (int)constructionRays.size() << " samples" << endl;
[452]3083
[542]3084        mVspKdTree->Construct(constructionRays, &mViewSpaceBox);
[452]3085        Debug << mVspKdTree->GetStatistics() << endl;
3086
[482]3087        // export leaf building blocks
3088        ExportLeaves(objects, rays);
[480]3089
[469]3090        // finally merge kd leaf building blocks to view cells
[485]3091        const int merged = mVspKdTree->MergeViewCells(rays);
3092
3093        // collapse siblings belonging to the same view cell
[486]3094        mVspKdTree->RefineViewCells(rays);
[485]3095
[542]3096        // collapse siblings belonging to the same view cell
[503]3097        mVspKdTree->CollapseTree();
3098
[482]3099        // evaluale view cell stats
3100        ResetViewCells();
[469]3101
[660]3102        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
[482]3103
[485]3104        long startTime = GetTime();
[660]3105
[469]3106        // recast rest of rays
[574]3107        ComputeSampleContributions(savedRays, true, false);
[503]3108
3109        Debug << "Computed remaining ray contribution in " << TimeDiff(startTime, GetTime()) * 1e-3
[485]3110                  << " secs" << endl;
[469]3111
3112        return merged;
[440]3113}
3114
3115bool VspKdViewCellsManager::ViewCellsConstructed() const
3116{
3117        return mVspKdTree->GetRoot() != NULL;
3118}
3119
[441]3120
[462]3121ViewCell *VspKdViewCellsManager::GenerateViewCell(Mesh *mesh) const
3122{
3123        return new VspKdViewCell(mesh);
3124}
3125
[503]3126int VspKdViewCellsManager::PostProcess(const ObjectContainer &objects,
[466]3127                                                                           const VssRayContainer &rays)
[440]3128{
[441]3129        if (!ViewCellsConstructed())
3130                return 0;
3131
[482]3132        // recalculate stats
3133        EvaluateViewCellsStats();
3134
[469]3135        return 0;
[440]3136}
3137
[482]3138
3139void VspKdViewCellsManager::ExportLeaves(const ObjectContainer &objects,
3140                                                                                 const VssRayContainer &sampleRays)
[440]3141{
[441]3142        if (!ViewCellsConstructed())
3143                return;
3144
[482]3145        //-- export leaf building blocks
[503]3146        Exporter *exporter = Exporter::GetExporter("vspkdtree.x3d");
[482]3147        if (!exporter)
3148                return;
3149
[598]3150        if (mExportGeometry)
3151                exporter->ExportGeometry(objects);
3152       
[482]3153        //exporter->SetWireframe();
3154        //exporter->ExportVspKdTree(*mVspKdTree, mVspKdTree->GetStatistics().maxPvsSize);
3155        exporter->ExportVspKdTree(*mVspKdTree);
3156
[503]3157        if (mExportRays)
[440]3158        {
[503]3159                const float prob = (float)mVisualizationSamples
[482]3160                        / ((float)sampleRays.size() + Limits::Small);
[440]3161
[482]3162                exporter->SetWireframe();
[440]3163
[482]3164                //-- collect uniformly distributed rays
3165                VssRayContainer rays;
[440]3166
[482]3167                for (int i = 0; i < sampleRays.size(); ++ i)
3168                {
3169                        if (RandomValue(0,1) < prob)
3170                                rays.push_back(sampleRays[i]);
[440]3171                }
[482]3172                exporter->ExportRays(rays, RgbColor(1, 0, 0));
[440]3173        }
3174
[482]3175        delete exporter;
3176}
3177
[726]3178
[482]3179void VspKdViewCellsManager::Visualize(const ObjectContainer &objects,
3180                                                                          const VssRayContainer &sampleRays)
3181{
3182        if (!ViewCellsConstructed())
3183                return;
[503]3184
[482]3185        //-- export single view cells
3186        for (int i = 0; i < 10; ++ i)
[440]3187        {
[482]3188                char s[64];
3189                sprintf(s, "vsp_viewcell%04d.x3d", i);
3190                Exporter *exporter = Exporter::GetExporter(s);
[503]3191                const int idx =
[482]3192                        (int)RandomValue(0.0, (Real)((int)mViewCells.size() - 1));
[440]3193
[503]3194                VspKdViewCell *vc = dynamic_cast<VspKdViewCell *>(mViewCells[idx]);
[482]3195
3196                //-- export geometry
3197                Material m;
3198                m.mDiffuseColor = RgbColor(0, 1, 1);
[503]3199
[482]3200                exporter->SetForcedMaterial(m);
3201                exporter->SetWireframe();
3202
[580]3203                ExportViewCellGeometry(exporter, vc);
[482]3204
3205                //-- export stored rays
[580]3206               
[485]3207                if (mExportRays)
[440]3208                {
[580]3209                        ViewCellContainer leaves;
3210                        mViewCellsTree->CollectLeaves(vc, leaves);
[440]3211
[580]3212                        ViewCellContainer::const_iterator it,
3213                                it_end = leaves.end();
3214
3215                        for (it = leaves.begin(); it != it_end; ++ it)
[482]3216                        {
[580]3217                                VspKdViewCell *vspKdVc = dynamic_cast<VspKdViewCell *>(*it);
3218                                VspKdLeaf *leaf = vspKdVc->mLeaf;
[482]3219                                AxisAlignedBox3 box = mVspKdTree->GetBBox(leaf);
[440]3220
[482]3221                                VssRayContainer vssRays;
[483]3222
3223                                VssRayContainer castRays;
3224                                VssRayContainer initRays;
3225
[482]3226                                leaf->GetRays(vssRays);
[440]3227
[482]3228                                VssRayContainer::const_iterator it, it_end = vssRays.end();
[483]3229                                const float prop = 200.0f / (float)vssRays.size();
[440]3230
[482]3231                                for (it = vssRays.begin(); it != it_end; ++ it)
[483]3232                                {
[485]3233                                        if (Random(1) < prop)
[483]3234                                                if ((*it)->mTerminationObject == NULL)
3235                                                        castRays.push_back(*it);
[503]3236                                                else
[483]3237                                                        initRays.push_back(*it);
3238                                }
3239
3240                                exporter->ExportRays(castRays, RgbColor(1, 0, 0));
3241                                exporter->ExportRays(initRays, RgbColor(0, 1, 0));
[482]3242                        }
3243                }
[580]3244       
[482]3245                //-- output PVS of view cell
3246                m.mDiffuseColor = RgbColor(1, 0, 0);
3247                exporter->SetForcedMaterial(m);
[440]3248
[483]3249                Intersectable::NewMail();
3250
[482]3251                ObjectPvsMap::const_iterator it,
3252                        it_end = vc->GetPvs().mEntries.end();
3253
3254                exporter->SetFilled();
3255
[503]3256                for (it = vc->GetPvs().mEntries.begin(); it != it_end; ++ it)
[482]3257                {
3258                        Intersectable *intersect = (*it).first;
3259
3260                        if (!intersect->Mailed())
3261                        {
3262                                Material m = RandomMaterial();
3263                                exporter->SetForcedMaterial(m);
3264
3265                                exporter->ExportIntersectable(intersect);
3266                                intersect->Mail();
[503]3267                        }
[482]3268                }
3269
3270                delete exporter;
[440]3271        }
[462]3272
3273        //-- export final view cells
[503]3274        Exporter *exporter = Exporter::GetExporter("vspkdtree_merged.x3d");
3275
[483]3276
[508]3277        ExportViewCellsForViz(exporter);
[462]3278
[503]3279        if (mExportGeometry)
[465]3280        {
3281                exporter->SetFilled();
[462]3282                exporter->ExportGeometry(objects);
[465]3283        }
[469]3284
[503]3285        if (mExportRays)
[462]3286        {
[503]3287                const float prob = (float)mVisualizationSamples
[482]3288                        / ((float)sampleRays.size() + Limits::Small);
[503]3289
[462]3290                exporter->SetWireframe();
[503]3291
[466]3292                VssRayContainer rays;
[503]3293
[462]3294                for (int i = 0; i < sampleRays.size(); ++ i)
3295                {
[466]3296                  if (RandomValue(0,1) < prob)
3297                        rays.push_back(sampleRays[i]);
[462]3298                }
[503]3299                exporter->ExportRays(rays, RgbColor(1, 0, 0));
[462]3300        }
3301
3302        delete exporter;
[440]3303}
3304
3305int VspKdViewCellsManager::GetType() const
3306{
3307        return VSP_KD;
3308}
[442]3309
[462]3310
[469]3311int VspKdViewCellsManager::CastLineSegment(const Vector3 &origin,
3312                                                                                   const Vector3 &termination,
3313                                                                                   ViewCellContainer &viewcells)
[466]3314{
[469]3315        return mVspKdTree->CastLineSegment(origin, termination, viewcells);
[466]3316}
3317
[477]3318
[482]3319void VspKdViewCellsManager::ExportColor(Exporter *exporter,
3320                                                                                ViewCell *vc) const
3321{
3322        if (mColorCode == 0) // Random color
3323                return;
[503]3324
[482]3325        float importance = 0;
[477]3326
[482]3327        switch (mColorCode)
3328        {
3329        case 1: // pvs
3330                {
[503]3331                        importance = (float)vc->GetPvs().GetSize() /
[660]3332                                (float)mCurrentViewCellsStats.maxPvs;
[482]3333                }
3334                break;
[580]3335        case 2: // merged leaves
[482]3336                {
[744]3337                const int lSize = mViewCellsTree->GetNumInitialViewCells(vc);
[580]3338                        importance = (float)lSize /
[660]3339                                (float)mCurrentViewCellsStats.maxLeaves;
[482]3340                }
3341                break;
[485]3342        case 3: // merged tree depth difference
[482]3343                {
[503]3344                        //importance = (float)GetMaxTreeDiff(vc) /
[482]3345                        //      (float)(mVspBspTree->GetStatistics().maxDepth * 2);
3346                }
3347                break;
3348        default:
3349                break;
3350        }
3351
3352        Material m;
3353        m.mDiffuseColor.b = 1.0f;
3354        m.mDiffuseColor.r = importance;
3355        m.mDiffuseColor.g = 1.0f - m.mDiffuseColor.r;
3356        //Debug << "importance: " << importance << endl;
3357        exporter->SetForcedMaterial(m);
3358}
3359
3360
[580]3361void VspKdViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
[591]3362                                                                                                   ViewCell *vc,
[660]3363                                                                                                   const Plane3 *clipPlane) const
[482]3364{
3365        VspKdViewCell *kdVc = dynamic_cast<VspKdViewCell *>(vc);
3366
[486]3367        Mesh m;
[580]3368
3369        ViewCellContainer leaves;
3370        mViewCellsTree->CollectLeaves(vc, leaves);
3371
3372        ViewCellContainer::const_iterator it, it_end = leaves.end();
3373
3374        for (it = leaves.begin(); it != it_end; ++ it)
[486]3375        {
[580]3376                VspKdLeaf *l = dynamic_cast<VspKdViewCell *>(*it)->mLeaf;
3377                mVspKdTree->GetBBox(l).AddBoxToMesh(&m);
[486]3378        }
3379
3380        exporter->ExportMesh(&m);
[482]3381}
3382
3383
[503]3384void VspKdViewCellsManager::CreateMesh(ViewCell *vc)
3385{
[551]3386        //TODO
[503]3387}
[442]3388
[574]3389
[584]3390void VspKdViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
3391                                                                                                   vector<MergeCandidate> &candidates)
[580]3392{
3393        // TODO
3394}
[574]3395
[580]3396
[503]3397/**************************************************************************/
3398/*                   VspBspViewCellsManager implementation                */
3399/**************************************************************************/
[482]3400
[503]3401
[574]3402VspBspViewCellsManager::VspBspViewCellsManager(VspBspTree *vspBspTree):
3403ViewCellsManager(), mVspBspTree(vspBspTree)
[442]3404{
[574]3405        environment->GetIntValue("VspBspTree.Construction.samples", mInitialSamples);
[478]3406        mVspBspTree->SetViewCellsManager(this);
[590]3407        mVspBspTree->mViewCellsTree = mViewCellsTree;
[442]3408}
3409
[477]3410
[475]3411VspBspViewCellsManager::~VspBspViewCellsManager()
3412{
3413}
3414
[477]3415
[471]3416float VspBspViewCellsManager::GetProbability(ViewCell *viewCell)
[468]3417{
[551]3418        if (0 && mVspBspTree->mUseAreaForPvs)
[547]3419                return GetArea(viewCell) / GetAccVcArea();
3420        else
3421                return GetVolume(viewCell) / mViewSpaceBox.GetVolume();
[468]3422}
3423
[477]3424
[480]3425void VspBspViewCellsManager::CollectViewCells()
3426{
[581]3427        // view cells tree constructed
3428        if (!ViewCellsTreeConstructed())
3429        {
[590]3430                mVspBspTree->CollectViewCells(mViewCells, false);
[581]3431        }
3432        else
[664]3433        {       // we can use the view cells tree hierarchy to get the right set
[600]3434                mViewCellsTree->CollectBestViewCellSet(mViewCells, mNumActiveViewCells);
[581]3435        }
[480]3436}
3437
3438
[442]3439bool VspBspViewCellsManager::ViewCellsConstructed() const
3440{
3441        return mVspBspTree->GetRoot() != NULL;
3442}
3443
[462]3444
[442]3445ViewCell *VspBspViewCellsManager::GenerateViewCell(Mesh *mesh) const
3446{
3447        return new BspViewCell(mesh);
3448}
3449
[569]3450
[574]3451int VspBspViewCellsManager::ConstructSubdivision(const ObjectContainer &objects,
[600]3452                                                                                                 const VssRayContainer &rays)
[442]3453{
[710]3454        mMaxPvsSize = (int)(mMaxPvsRatio * (float)objects.size());
3455
[503]3456        // if view cells were already constructed
3457        if (ViewCellsConstructed())
3458                return 0;
[442]3459
[503]3460        int sampleContributions = 0;
3461
3462        VssRayContainer sampleRays;
3463
[574]3464        int limit = min (mInitialSamples, (int)rays.size());
[503]3465
[469]3466        VssRayContainer constructionRays;
3467        VssRayContainer savedRays;
[442]3468
[660]3469        Debug << "samples used for vsp bsp subdivision: " << mInitialSamples
[664]3470                  << ", actual rays: " << (int)rays.size() << endl;
[587]3471
[574]3472        GetRaySets(rays, mInitialSamples, constructionRays, &savedRays);
[487]3473
[574]3474        Debug << "initial rays: " << (int)constructionRays.size() << endl;
[508]3475        Debug << "saved rays: " << (int)savedRays.size() << endl;
[485]3476
[564]3477
[666]3478        //TODO: remove
[667]3479        if (1)
3480                mVspBspTree->Construct(constructionRays, &mViewSpaceBox);
[666]3481        else
[667]3482                mVspBspTree->Construct(rays, &mViewSpaceBox);
3483
[490]3484        // collapse invalid regions
[491]3485        cout << "collapsing invalid tree regions ... ";
[495]3486        long startTime = GetTime();
[503]3487        int collapsedLeaves = mVspBspTree->CollapseTree();
[587]3488        Debug << "collapsed in " << TimeDiff(startTime, GetTime()) * 1e-3
3489                  << " seconds" << endl;
3490
[495]3491    cout << "finished" << endl;
[503]3492
[660]3493        // -- stats
3494        Debug << mVspBspTree->GetStatistics() << endl;
3495
[480]3496        ResetViewCells();
[660]3497        Debug << "\nView cells after construction:\n" << mCurrentViewCellsStats << endl;
[503]3498
[491]3499
[495]3500        startTime = GetTime();
[503]3501
[491]3502        cout << "Computing remaining ray contributions ... ";
[605]3503
[469]3504        // recast rest of rays
[605]3505        if (SAMPLE_AFTER_SUBDIVISION)
3506                ComputeSampleContributions(savedRays, true, false);
[752]3507
[491]3508        cout << "finished" << endl;
3509
[503]3510        Debug << "Computed remaining ray contribution in " << TimeDiff(startTime, GetTime()) * 1e-3
[485]3511                  << " secs" << endl;
[442]3512
[485]3513        cout << "construction finished" << endl;
[503]3514
[719]3515        // real meshes are contructed at this stage
3516        if (0)
3517        {
3518                cout << "finalizing view cells ... ";
3519                FinalizeViewCells(true);
3520                cout << "finished" << endl;
3521        }
3522
[442]3523        return sampleContributions;
3524}
3525
[489]3526
[503]3527void VspBspViewCellsManager::MergeViewCells(const VssRayContainer &rays,
3528                                                                                        const ObjectContainer &objects)
[475]3529{
[442]3530    int vcSize = 0;
3531        int pvsSize = 0;
3532
[650]3533        //-- merge view cells
3534        cout << "starting merge using " << mPostProcessSamples << " samples ... " << endl;
3535        long startTime = GetTime();
3536
3537
[597]3538        if (mMergeViewCells)
3539        {
3540                // TODO: should be done BEFORE the ray casting
[710]3541                // compute tree by merging the nodes based on cost heuristics
[650]3542                mViewCellsTree->ConstructMergeTree(rays, objects);
3543        }
3544        else
3545        {
[710]3546                // compute tree by merging the nodes of the spatial hierarchy
3547                ViewCell *root = ConstructSpatialMergeTree(mVspBspTree->GetRoot());
3548                mViewCellsTree->SetRoot(root);
[752]3549
3550                // compute pvs
3551                ObjectPvs pvs;
3552                UpdatePvsForEvaluation(root, pvs);
[650]3553        }
[442]3554
[666]3555        if (1)
3556        {
3557                char mstats[100];
[752]3558                ObjectPvs pvs;
3559
[666]3560                environment->GetStringValue("ViewCells.mergeStats", mstats);
3561                mViewCellsTree->ExportStats(mstats);
3562        }
[485]3563
[650]3564        //-- stats and visualizations
3565        cout << "finished merging" << endl;
3566        cout << "merged view cells in "
3567                 << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl;
[503]3568
[650]3569        Debug << "Postprocessing: Merged view cells in "
3570                  << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl << endl;
3571       
3572
[600]3573        int savedColorCode = mColorCode;
3574       
[660]3575        // get currently active view cell set
3576        ResetViewCells();
3577        Debug << "\nView cells after merge:\n" << mCurrentViewCellsStats << endl;
3578
[485]3579        //BspLeaf::NewMail();
[667]3580        if (1) // export merged view cells
[483]3581        {
[600]3582                mColorCode = 0;
[744]3583                Exporter *exporter = Exporter::GetExporter("merged_view_cells.wrl");
[660]3584               
[485]3585                cout << "exporting view cells after merge ... ";
3586
3587                if (exporter)
[483]3588                {
[600]3589                        if (0)
3590                                exporter->SetWireframe();
3591                        else
3592                                exporter->SetFilled();
3593
3594                        ExportViewCellsForViz(exporter);
3595
[485]3596                        if (mExportGeometry)
[483]3597                        {
[485]3598                                Material m;
3599                                m.mDiffuseColor = RgbColor(0, 1, 0);
3600                                exporter->SetForcedMaterial(m);
3601                                exporter->SetFilled();
[442]3602
[485]3603                                exporter->ExportGeometry(objects);
[442]3604                        }
[485]3605
[600]3606                        delete exporter;
3607                }
3608                cout << "finished" << endl;
3609        }
3610
[667]3611        if (1) // export merged view cells using pvs coding
[600]3612        {
3613                mColorCode = 1;
3614
[744]3615                Exporter *exporter = Exporter::GetExporter("merged_view_cells_pvs.wrl");
[600]3616       
3617                cout << "exporting view cells after merge (pvs size) ... ";     
3618
3619                if (exporter)
3620                {
[598]3621                        if (0)
3622                                exporter->SetWireframe();
3623                        else
3624                                exporter->SetFilled();
3625
3626                        ExportViewCellsForViz(exporter);
3627
[600]3628                        if (mExportGeometry)
3629                        {
3630                                Material m;
3631                                m.mDiffuseColor = RgbColor(0, 1, 0);
3632                                exporter->SetForcedMaterial(m);
3633                                exporter->SetFilled();
3634
3635                                exporter->ExportGeometry(objects);
3636                        }
3637
[485]3638                        delete exporter;
[442]3639                }
[485]3640                cout << "finished" << endl;
[442]3641        }
[600]3642
3643        mColorCode = savedColorCode;
3644
[503]3645}
[475]3646
[503]3647
[609]3648bool VspBspViewCellsManager::EqualToSpatialNode(ViewCell *viewCell) const
[607]3649{
[609]3650        return GetSpatialNode(viewCell) != NULL;
[607]3651}
3652
3653
[609]3654BspNode *VspBspViewCellsManager::GetSpatialNode(ViewCell *viewCell) const
[607]3655{
3656        if (!viewCell->IsLeaf())
3657        {
3658                BspViewCell *bspVc = dynamic_cast<BspViewCell *>(viewCell);
3659
[609]3660                return bspVc->mLeaf;
3661        }
[607]3662        else
3663        {
3664                ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(viewCell);
3665
3666                // cannot be node of binary tree
3667                if (interior->mChildren.size() != 2)
[609]3668                        return NULL;
[607]3669
3670                ViewCell *left = interior->mChildren[0];
3671                ViewCell *right = interior->mChildren[1];
3672
[609]3673                BspNode *leftNode = GetSpatialNode(left);
3674                BspNode *rightNode = GetSpatialNode(right);
[607]3675
[609]3676                if (leftNode && rightNode && leftNode->IsSibling(rightNode))
[607]3677                {
[609]3678                        return leftNode->GetParent();
[607]3679                }
[609]3680        }
[607]3681
[609]3682        return NULL;
[607]3683}
3684
3685
[564]3686void VspBspViewCellsManager::RefineViewCells(const VssRayContainer &rays,
3687                                                                                         const ObjectContainer &objects)
[503]3688{
[485]3689        Debug << "render time before refine:" << endl;
3690        mRenderer->RenderScene();
[503]3691        SimulationStatistics ss;
[485]3692        dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
3693    Debug << ss << endl;
3694
[489]3695        cout << "Refining the merged view cells ... ";
[503]3696        long startTime = GetTime();
[485]3697
3698        // refining the merged view cells
[580]3699        const int refined = mViewCellsTree->RefineViewCells(rays, objects);
[485]3700
[442]3701        //-- stats and visualizations
3702        cout << "finished" << endl;
[485]3703        cout << "refined " << refined << " view cells in "
[442]3704                 << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl;
3705
[485]3706        Debug << "Postprocessing: refined " << refined << " view cells in "
[475]3707                  << TimeDiff(startTime, GetTime()) *1e-3 << " secs" << endl << endl;
[503]3708}
[495]3709
[517]3710
[503]3711int VspBspViewCellsManager::PostProcess(const ObjectContainer &objects,
3712                                                                                const VssRayContainer &rays)
3713{
3714        if (!ViewCellsConstructed())
3715        {
[517]3716                Debug << "postprocess error: no view cells constructed" << endl;
[503]3717                return 0;
3718        }
[520]3719
[564]3720
[609]3721        // view cells already finished before post processing step
3722        // (i.e. because they were loaded)
[520]3723        if (mViewCellsFinished)
[542]3724        {
[551]3725                FinalizeViewCells(true);
[542]3726                EvaluateViewCellsStats();
[577]3727
[517]3728                return 0;
[542]3729        }
[448]3730
[710]3731        // check if new view cells turned invalid
3732        int minPvs, maxPvs;
[564]3733
[710]3734        if (0)
3735        {
3736                minPvs = mMinPvsSize;
3737                maxPvs = mMaxPvsSize;
3738        }
3739        else
3740        {
3741                minPvs = mPruneEmptyViewCells ? 1 : 0;
3742                maxPvs = mMaxPvsSize;
3743        }
[720]3744
[710]3745        Debug << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
3746        cout << "setting validity, min: " << minPvs << " max: " << maxPvs << endl;
3747       
3748        SetValidity(minPvs, maxPvs);
3749
[574]3750        // update valid view space according to valid view cells
[720]3751        if (0) mVspBspTree->ValidateTree();
[542]3752
[720]3753        // area has to be recomputed
[574]3754        mTotalAreaValid = false;
[517]3755        VssRayContainer postProcessRays;
[605]3756        GetRaySets(rays, mPostProcessSamples, postProcessRays);
3757
[517]3758        Debug << "post processing using " << (int)postProcessRays.size() << " samples" << endl;
[564]3759
[517]3760
[552]3761        // should maybe be done here to allow merge working with area or volume
3762        // and to correct the rendering statistics
[719]3763        if (0) FinalizeViewCells(false);
[720]3764               
[597]3765        //-- merge the individual view cells
3766        MergeViewCells(postProcessRays, objects);
[591]3767       
[720]3768
3769        // only for debugging purpose: test if the subdivision is valid
[693]3770        TestSubdivision();
3771
[597]3772        //-- refines the merged view cells
[720]3773        if (0) RefineViewCells(postProcessRays, objects);
[568]3774
[719]3775       
[660]3776        //-- render simulation after merge + refine
[605]3777        cout << "\nevaluating bsp view cells render time before compress ... ";
3778        dynamic_cast<RenderSimulator *>(mRenderer)->RenderScene();
3779        SimulationStatistics ss;
3780        dynamic_cast<RenderSimulator *>(mRenderer)->GetStatistics(ss);
[600]3781 
[580]3782
[605]3783        cout << " finished" << endl;
3784        cout << ss << endl;
3785        Debug << ss << endl;
[600]3786
3787
3788        //-- compression
3789        if (ViewCellsTreeConstructed() && mCompressViewCells)
3790        {
3791                int pvsEntries = mViewCellsTree->GetNumPvsEntries(mViewCellsTree->GetRoot());
3792                Debug << "number of entries before compress: " << pvsEntries << endl;
3793
[752]3794                mViewCellsTree->SetViewCellsStorage(ViewCellsTree::COMPRESSED);
[600]3795
3796                pvsEntries = mViewCellsTree->GetNumPvsEntries(mViewCellsTree->GetRoot());
3797                Debug << "number of entries after compress: " << pvsEntries << endl;
3798        }
3799
[660]3800
[517]3801        // collapse sibling leaves that share the same view cell
[586]3802        if (0)
3803                mVspBspTree->CollapseTree();
3804
[574]3805        // recompute view cell list and statistics
[520]3806        ResetViewCells();
3807
[719]3808        // compute final meshes and volume / area
3809        if (1) FinalizeViewCells(true);
[517]3810
[719]3811
[508]3812        // write view cells to disc
3813        if (mExportViewCells)
3814        {
[517]3815                char buff[100];
3816                environment->GetStringValue("ViewCells.filename", buff);
3817                string vcFilename(buff);
3818
3819                ExportViewCells(buff);
[508]3820        }
[503]3821
3822        return 0;
[442]3823}
3824
[490]3825
[442]3826int VspBspViewCellsManager::GetType() const
3827{
3828        return VSP_BSP;
3829}
3830
3831
[650]3832ViewCell *VspBspViewCellsManager::ConstructSpatialMergeTree(BspNode *root)
[609]3833{
[752]3834        // terminate recursion
[650]3835        if (root->IsLeaf())
3836        {
[752]3837                BspLeaf *leaf = dynamic_cast<BspLeaf *>(root);
3838                leaf->GetViewCell()->SetMergeCost(0.0f);
3839                return leaf->GetViewCell();
[650]3840        }
3841       
[752]3842       
[650]3843        BspInterior *interior = dynamic_cast<BspInterior *>(root);
3844        ViewCellInterior *viewCellInterior = new ViewCellInterior();
3845               
[752]3846        // evaluate merge cost for priority traversal
[650]3847        float mergeCost = 1.0f / (float)root->mTimeStamp;
3848        viewCellInterior->SetMergeCost(mergeCost);
[610]3849
[650]3850        float volume = 0;
3851       
3852        BspNode *front = interior->GetFront();
3853        BspNode *back = interior->GetBack();
[649]3854
[752]3855
3856        ObjectPvs frontPvs, backPvs;
3857
3858        //-- recursivly compute child hierarchies
[650]3859        ViewCell *backVc = ConstructSpatialMergeTree(back);
3860        ViewCell *frontVc = ConstructSpatialMergeTree(front);
[610]3861
[752]3862
3863        viewCellInterior->SetupChildLink(backVc);
[650]3864        viewCellInterior->SetupChildLink(frontVc);
3865
3866        volume += backVc->GetVolume();
3867        volume += frontVc->GetVolume();
3868
3869        viewCellInterior->SetVolume(volume);
3870
3871        return viewCellInterior;
[609]3872}
3873
3874
[752]3875
3876void VspBspViewCellsManager::UpdatePvsForEvaluation(ViewCell *root, ObjectPvs &pvs)
3877{
3878        // terminate traversal
3879        if (root->IsLeaf())
3880        {
3881                pvs = root->GetPvs();
3882
3883                root->mPvsSize = pvs.GetSize();
3884                root->mPvsSizeValid = true;
3885
3886                return;
3887        }
3888       
3889        ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(root);
3890        ViewCellContainer::const_iterator vit, vit_end = interior->mChildren.end();
3891
3892        vector<ObjectPvs> pvsList;
3893       
3894       
3895        for (vit = interior->mChildren.begin(); vit != vit_end; ++ vit)
3896        {
3897                ObjectPvs objPvs;
3898               
3899                //-- recursivly compute child pvss
3900                UpdatePvsForEvaluation(*vit, objPvs);
3901
3902                // store pvs in vector
3903                pvsList.push_back(objPvs);
3904        }
3905
3906#if 1
3907        Intersectable::NewMail();
3908
3909        //-- faster way of computing pvs:
3910        //   construct merged pvs by adding
3911        //   and only those of the next pvs which were not mailed.
3912        //   note: sumpdf is not correct!!
3913        vector<ObjectPvs>::iterator oit = pvsList.begin();
3914
3915        for (vit = interior->mChildren.begin(); vit != vit_end; ++ vit, ++ oit)
3916        {
3917            ObjectPvsMap::iterator pit, pit_end = (*oit).mEntries.end();
3918       
3919                for (pit = (*oit).mEntries.begin(); pit != pit_end; ++ pit)
3920                {
3921                        Intersectable *intersect = (*pit).first;
3922
3923                        if (!intersect->Mailed())
3924                        {
3925                                pvs.AddSample(intersect, (*pit).second.mSumPdf);
3926                                intersect->Mail();
3927                        }
3928                }
3929        }
3930
3931        // store pvs in this node
3932        if (mViewCellsTree->ViewCellsStorage() == ViewCellsTree::PVS_IN_INTERIORS)
3933        {
3934                interior->mPvs = pvs;
3935        }
3936       
3937        // set new pvs size
3938        interior->mPvsSize = pvs.GetSize();
3939        interior->mPvsSizeValid = true;
3940
3941#else
3942        // really merge cells: slow put sumpdf is correct
3943        ViewCellInterior *viewCellInterior = new ViewCellInterior();
3944
3945        viewCellInterior->GetPvs().Merge(backVc->GetPvs());
3946        viewCellInterior->GetPvs().Merge(frontVc->GetPvs());
3947#endif
3948
3949}
3950
3951
[490]3952bool VspBspViewCellsManager::GetViewPoint(Vector3 &viewPoint) const
3953{
3954        if (!ViewCellsConstructed())
3955                return ViewCellsManager::GetViewPoint(viewPoint);
3956
3957        // TODO: set reasonable limit
3958        const int limit = 20;
3959
3960        for (int i = 0; i < limit; ++ i)
3961        {
[542]3962                viewPoint = mViewSpaceBox.GetRandomPoint();
[490]3963                if (mVspBspTree->ViewPointValid(viewPoint))
3964                {
3965                        return true;
3966                }
3967        }
3968        Debug << "failed to find valid view point, taking " << viewPoint << endl;
3969        return false;
3970}
3971
3972
3973bool VspBspViewCellsManager::ViewPointValid(const Vector3 &viewPoint) const
3974{
[569]3975  // $$JB -> implemented in viewcellsmanager (slower, but allows dynamic
3976  // validy update in preprocessor for all managers)
3977  return ViewCellsManager::ViewPointValid(viewPoint);
[570]3978
[569]3979  //    return mViewSpaceBox.IsInside(viewPoint) &&
3980  //               mVspBspTree->ViewPointValid(viewPoint);
[490]3981}
3982
3983
[442]3984void VspBspViewCellsManager::Visualize(const ObjectContainer &objects,
[466]3985                                                                           const VssRayContainer &sampleRays)
[442]3986{
3987        if (!ViewCellsConstructed())
3988                return;
3989
[485]3990        VssRayContainer visRays;
3991        GetRaySets(sampleRays, mVisualizationSamples, visRays);
[483]3992
[600]3993       
[651]3994        if (1) // export view cells
[612]3995        {       // hack pvs
[600]3996                int savedColorCode = mColorCode;
[651]3997                mColorCode = 0;
[712]3998                Exporter *exporter = Exporter::GetExporter("final_view_cells.wrl");
[600]3999               
[442]4000                if (exporter)
4001                {
[580]4002                        cout << "exporting view cells after post process ... ";
4003
[600]4004                        if (0)
[542]4005                        {
4006                                exporter->SetWireframe();
4007                                exporter->ExportBox(mViewSpaceBox);
4008                                exporter->SetFilled();
4009                        }
4010
[485]4011                        if (mExportGeometry)
[542]4012                        {
[485]4013                                exporter->ExportGeometry(objects);
[542]4014                        }
[489]4015
4016                        // export rays
[490]4017                        if (mExportRays)
[489]4018                        {
[490]4019                                exporter->ExportRays(visRays, RgbColor(0, 1, 0));
4020                        }
[564]4021
[508]4022                        ExportViewCellsForViz(exporter);
[442]4023                        delete exporter;
[580]4024                        cout << "finished" << endl;
[442]4025                }
[600]4026
4027                mColorCode = savedColorCode;
[557]4028        }
[503]4029
[600]4030        if (0)
[577]4031        {
4032                cout << "exporting depth map ... ";
4033
4034                Exporter *exporter = Exporter::GetExporter("depth_map.x3d");
4035                if (exporter)
4036                {
4037                        if (1)
4038                        {
4039                                exporter->SetWireframe();
4040                                exporter->ExportBox(mViewSpaceBox);
4041                                exporter->SetFilled();
4042                        }
4043
4044                        if (mExportGeometry)
4045                        {
4046                                exporter->ExportGeometry(objects);
4047                        }
4048
4049                        const int maxDepth = mVspBspTree->mBspStats.maxDepth;
4050
4051                        ViewCellContainer::const_iterator vit, vit_end = mViewCells.end();
4052
4053                        for (vit = mViewCells.begin(); vit != mViewCells.end(); ++ vit)
4054                        {
[582]4055                                ViewCell *vc = *vit;
[577]4056
[580]4057                                ViewCellContainer leaves;
4058                                mViewCellsTree->CollectLeaves(vc, leaves);
[577]4059
[580]4060                                ViewCellContainer::const_iterator lit, lit_end = leaves.end();
4061
4062                                for (lit = leaves.begin(); lit != lit_end; ++ lit)
[577]4063                                {
[580]4064                                        BspLeaf *leaf = dynamic_cast<BspViewCell *>(*lit)->mLeaf;
[577]4065
4066                                        Material m;
4067
4068                                        float relDepth = (float)leaf->GetDepth() / (float)maxDepth;
4069                                        m.mDiffuseColor.r = relDepth;
4070                                        m.mDiffuseColor.g = 0.0f;
4071                                        m.mDiffuseColor.b = 1.0f - relDepth;
4072
4073                    exporter->SetForcedMaterial(m);
4074                               
4075
4076                                        BspNodeGeometry geom;
4077                                        mVspBspTree->ConstructGeometry(leaf, geom);
[678]4078                                        exporter->ExportPolygons(geom.GetPolys());
[577]4079                                }
4080                        }
4081
4082                        delete exporter;
4083                }
4084
4085
4086                cout << "finished" << endl;
4087        }
4088
[442]4089        //-- visualization of the BSP splits
4090        bool exportSplits = false;
[489]4091        environment->GetBoolValue("VspBspTree.Visualization.exportSplits", exportSplits);
[503]4092
[442]4093        if (exportSplits)
4094        {
4095                cout << "exporting splits ... ";
[485]4096                ExportSplits(objects, visRays);
[442]4097                cout << "finished" << endl;
4098        }
4099
[542]4100        //-- export single view cells
[485]4101        ExportBspPvs(objects, visRays);
[442]4102}
4103
[503]4104
[485]4105void VspBspViewCellsManager::ExportSplits(const ObjectContainer &objects,
4106                                                                                  const VssRayContainer &rays)
[442]4107{
4108        Exporter *exporter = Exporter::GetExporter("bsp_splits.x3d");
4109
[503]4110        if (exporter)
4111        {
4112                Material m;
[442]4113                m.mDiffuseColor = RgbColor(1, 0, 0);
4114                exporter->SetForcedMaterial(m);
4115                exporter->SetWireframe();
[503]4116
[448]4117                exporter->ExportBspSplits(*mVspBspTree, true);
[442]4118
4119                // take forced material, else big scenes cannot be viewed
4120                m.mDiffuseColor = RgbColor(0, 1, 0);
4121                exporter->SetForcedMaterial(m);
4122                exporter->SetFilled();
4123
4124                exporter->ResetForcedMaterial();
[503]4125
[442]4126                // export rays
[485]4127                if (mExportRays)
4128                        exporter->ExportRays(rays, RgbColor(1, 1, 0));
[503]4129
[485]4130                if (mExportGeometry)
[442]4131                        exporter->ExportGeometry(objects);
4132
4133                delete exporter;
4134        }
4135}
4136
[503]4137
[485]4138void VspBspViewCellsManager::ExportBspPvs(const ObjectContainer &objects,
4139                                                                                  const VssRayContainer &rays)
[442]4140{
[639]4141        const int leafOut = 20;
[503]4142
[442]4143        ViewCell::NewMail();
[503]4144
[639]4145        cout << "visualization using " << (int)rays.size() << " samples" << endl;
4146        Debug << "visualization using " << (int)rays.size() << " samples" << endl;
[475]4147        Debug << "\nOutput view cells: " << endl;
[503]4148
[694]4149        const bool sortViewCells = true;
4150
[485]4151        // sort view cells to visualize the largest view cells
[694]4152        if (sortViewCells)
[587]4153                stable_sort(mViewCells.begin(), mViewCells.end(), vc_gt);
[639]4154       
[503]4155        int limit = min(leafOut, (int)mViewCells.size());
[483]4156
[639]4157        int raysOut = 0;
[587]4158
[485]4159        //-- some rays for output
[478]4160        for (int i = 0; i < limit; ++ i)
[442]4161        {
[478]4162                cout << "creating output for view cell " << i << " ... ";
[503]4163
[582]4164                ViewCell *vc;
[574]4165       
[694]4166                if (sortViewCells) // largest view cell pvs first
[582]4167                        vc = mViewCells[i];
[574]4168                else
[639]4169                        vc = mViewCells[(int)RandomValue(0, (float)mViewCells.size() - 1)];
[442]4170
[639]4171                //bspLeaves[j]->Mail();
4172                char s[64]; sprintf(s, "bsp-pvs%04d.x3d", i);
4173                Exporter *exporter = Exporter::GetExporter(s);
4174               
4175                Debug << i << ": pvs size=" << (int)mViewCellsTree->GetPvsSize(vc) << endl;
[587]4176
[639]4177                if (1 || mExportRays)
[442]4178                {
[694]4179                        // output rays stored with the view cells during subdivision
[643]4180                        if (0)
[442]4181                        {
[639]4182                                VssRayContainer vcRays;
4183                VssRayContainer collectRays;
4184
4185                                raysOut = min((int)rays.size(), 100);
4186
4187                                // collect intial view cells
4188                                ViewCellContainer leaves;
4189                                mViewCellsTree->CollectLeaves(vc, leaves);
4190
4191                                ViewCellContainer::const_iterator vit, vit_end = leaves.end();
4192       
4193                                for (vit = leaves.begin(); vit != vit_end; ++ vit)
[574]4194                                {
[639]4195                                        BspLeaf *vcLeaf = dynamic_cast<BspViewCell *>(*vit)->mLeaf;
4196                               
4197                                        VssRayContainer::const_iterator rit, rit_end = vcLeaf->mVssRays.end();
[587]4198
[639]4199                                        for (rit = vcLeaf->mVssRays.begin(); rit != rit_end; ++ rit)
4200                                        {
4201                                                collectRays.push_back(*rit);
4202                                        }
[574]4203                                }
[639]4204
4205                                VssRayContainer::const_iterator rit, rit_end = collectRays.end();
4206
4207                                for (rit = collectRays.begin(); rit != rit_end; ++ rit)
4208                                {
4209                                        float p = RandomValue(0.0f, (float)collectRays.size());
4210                       
4211                                        if (p < raysOut)
4212                                                vcRays.push_back(*rit);
4213                                }
4214                                //-- export rays piercing this view cell
4215                                exporter->ExportRays(vcRays, RgbColor(1, 1, 1));
[442]4216                        }
[651]4217               
[694]4218                        // associate new rays with output view cell
[643]4219                        if (1)
[639]4220                        {
4221                                VssRayContainer vcRays;
4222                                raysOut = min((int)rays.size(), mVisualizationSamples);
4223                                // check whether we can add the current ray to the output rays
4224                                for (int k = 0; k < raysOut; ++ k)
4225                                {
4226                                        VssRay *ray = rays[k];
4227                                        for     (int j = 0; j < (int)ray->mViewCells.size(); ++ j)
4228                                        {
4229                                                ViewCell *rayvc = ray->mViewCells[j];
4230       
4231                                                if (rayvc == vc)
4232                                                        vcRays.push_back(ray);
4233                                        }
4234                                }       
4235                               
4236                                //-- export rays piercing this view cell
4237                                exporter->ExportRays(vcRays, RgbColor(1, 1, 0));
4238                        }
4239
[442]4240                }
[639]4241               
[574]4242
[478]4243                exporter->SetWireframe();
[442]4244
[478]4245                Material m;//= RandomMaterial();
4246                m.mDiffuseColor = RgbColor(0, 1, 0);
4247                exporter->SetForcedMaterial(m);
[442]4248
[580]4249                ExportViewCellGeometry(exporter, vc);
[639]4250       
4251                exporter->SetFilled();
[503]4252
[639]4253
[574]4254                if (1)
4255                {
[639]4256                        ObjectPvsMap::const_iterator oit,
4257                                oit_end = vc->GetPvs().mEntries.end();
[483]4258
[580]4259
[639]4260                        exporter->SetFilled();
[580]4261
[639]4262                        Intersectable::NewMail();
[574]4263       
[639]4264                        // output PVS of view cell
4265                        for (oit = vc->GetPvs().mEntries.begin(); oit != oit_end; ++ oit)
4266                        {               
4267                                Intersectable *intersect = (*oit).first;
[442]4268
[639]4269                                if (!intersect->Mailed())
4270                                {
[643]4271                                        m = RandomMaterial();
4272                                        exporter->SetForcedMaterial(m);
[442]4273
[639]4274                                        exporter->ExportIntersectable(intersect);
4275                                        intersect->Mail();
4276                                }
[503]4277                        }
[442]4278                }
[639]4279                else
4280                {
[643]4281                        m.mDiffuseColor = RgbColor(1, 0, 0);
4282                        exporter->SetForcedMaterial(m);
4283
[639]4284                        exporter->ExportGeometry(objects);
4285                }
[503]4286
[478]4287                DEL_PTR(exporter);
4288                cout << "finished" << endl;
[442]4289        }
[475]4290
4291        Debug << endl;
[442]4292}
4293
4294
[697]4295int VspBspViewCellsManager::ComputeBoxIntersections(const AxisAlignedBox3 &box, ViewCellContainer &viewCells) const
4296{
4297        return mVspBspTree->ComputeBoxIntersections(box, viewCells);
4298}
4299
4300
[469]4301int VspBspViewCellsManager::CastLineSegment(const Vector3 &origin,
4302                                                                                        const Vector3 &termination,
4303                                                                                        ViewCellContainer &viewcells)
[466]4304{
[469]4305        return mVspBspTree->CastLineSegment(origin, termination, viewcells);
[466]4306}
[482]4307
4308
[503]4309void VspBspViewCellsManager::ExportColor(Exporter *exporter,
[482]4310                                                                                 ViewCell *vc) const
4311{
[564]4312        const bool vcValid = CheckValidity(vc, mMinPvsSize, mMaxPvsSize);
[503]4313
[482]4314        float importance = 0;
[564]4315        static Material m;
4316
[482]4317        switch (mColorCode)
4318        {
[564]4319        case 0: // Random
4320                {
4321                        if (vcValid)
4322                        {
[598]4323                                m.mDiffuseColor.r = 0.5f + RandomValue(0.0f, 0.5f);
4324                                m.mDiffuseColor.g = 0.5f + RandomValue(0.0f, 0.5f);
4325                                m.mDiffuseColor.b = 0.5f + RandomValue(0.f, 0.5f);
[564]4326                        }
4327                        else
4328                        {
4329                                m.mDiffuseColor.r = 0.0f;
4330                                m.mDiffuseColor.g = 1.0f;
4331                                m.mDiffuseColor.b = 0.0f;
4332                        }
[591]4333
4334                        exporter->SetForcedMaterial(m);
4335                        return;
[564]4336                }
[591]4337               
[482]4338        case 1: // pvs
4339                {
[503]4340                        importance = (float)vc->GetPvs().GetSize() /
[744]4341#if 1 // hack for result                       
[660]4342                                (float)mCurrentViewCellsStats.maxPvs;
[744]4343#else
4344                                463.0f;
4345#endif
[482]4346                }
4347                break;
4348        case 2: // merges
4349                {
[736]4350            int lSize = mViewCellsTree->GetNumInitialViewCells(vc);
[660]4351                        importance = (float)lSize / (float)mCurrentViewCellsStats.maxLeaves;
[482]4352                }
4353                break;
4354        case 3: // merge tree differene
4355                {
[503]4356                        importance = (float)GetMaxTreeDiff(vc) /
[482]4357                                (float)(mVspBspTree->GetStatistics().maxDepth * 2);
[547]4358
[482]4359                }
4360                break;
4361        default:
4362                break;
4363        }
4364
[564]4365        // special color code for invalid view cells
[482]4366        m.mDiffuseColor.r = importance;
4367        m.mDiffuseColor.g = 1.0f - m.mDiffuseColor.r;
[564]4368        m.mDiffuseColor.b = vcValid ? 1.0f : 0.0f;
[547]4369
[482]4370        //Debug << "importance: " << importance << endl;
4371        exporter->SetForcedMaterial(m);
4372}
4373
4374
[580]4375void VspBspViewCellsManager::ExportViewCellGeometry(Exporter *exporter,
[591]4376                                                    ViewCell *vc,
[660]4377                                                                                                        const Plane3 *clipPlane) const
[482]4378{
[542]4379        if (vc->GetMesh())
[503]4380        {
4381                exporter->ExportMesh(vc->GetMesh());
[590]4382       
[503]4383                return;
4384        }
4385
[591]4386       
[660]4387        if (clipPlane)
[591]4388        {
4389                ViewCellContainer leaves;
4390                mViewCellsTree->CollectLeaves(vc, leaves);
4391                ViewCellContainer::const_iterator it, it_end = leaves.end();
4392
4393                for (it = leaves.begin(); it != it_end; ++ it)
4394                {
4395                        BspNodeGeometry geom;
4396
4397                        BspNodeGeometry front;
4398                        BspNodeGeometry back;
4399
4400                        BspLeaf *leaf = dynamic_cast<BspViewCell *>(*it)->mLeaf;
4401                        mVspBspTree->ConstructGeometry(leaf, geom);
4402
[710]4403                        const float eps = 0.00000001f;
4404                        const int cf = geom.Side(*clipPlane, eps);
[682]4405
[710]4406                        if (cf == -1)
[682]4407                        {
4408                                exporter->ExportPolygons(geom.GetPolys());
4409                        }
[710]4410                        else if (cf == 0)
[684]4411                        {
[682]4412                                geom.SplitGeometry(front,
4413                                                                   back,
4414                                                                   *clipPlane,
4415                                                                   mViewSpaceBox,
[710]4416                                                                   eps);
[682]4417       
[694]4418                                //Debug << "geo size: " << geom.Size() << endl;
4419                                //Debug << "size b: " << back.Size() << " f: " << front.Size() << endl;
[683]4420                                if (back.Valid())
4421                                {
[682]4422                                        exporter->ExportPolygons(back.GetPolys());
[708]4423                                }                       
[684]4424                        }
[591]4425                }
4426        }
4427        else
4428        {
4429                BspNodeGeometry geom;
4430                mVspBspTree->ConstructGeometry(vc, geom);
4431                       
[678]4432                exporter->ExportPolygons(geom.GetPolys());
[591]4433        }
[482]4434}
4435
4436
4437int VspBspViewCellsManager::GetMaxTreeDiff(ViewCell *vc) const
4438{
[580]4439        ViewCellContainer leaves;
4440        mViewCellsTree->CollectLeaves(vc, leaves);
[482]4441
4442        int maxDist = 0;
[580]4443       
[482]4444        // compute max height difference
[580]4445        for (int i = 0; i < (int)leaves.size(); ++ i)
4446                for (int j = 0; j < (int)leaves.size(); ++ j)
[482]4447        {
[580]4448                BspLeaf *leaf = dynamic_cast<BspViewCell *>(leaves[i])->mLeaf;
[482]4449
4450                if (i != j)
4451                {
[580]4452                        BspLeaf *leaf2 =dynamic_cast<BspViewCell *>(leaves[j])->mLeaf;
[482]4453                        int dist = mVspBspTree->TreeDistance(leaf, leaf2);
4454                        if (dist > maxDist)
4455                                maxDist = dist;
4456                }
4457        }
[580]4458
[492]4459        return maxDist;
4460}
[482]4461
[492]4462
[569]4463ViewCell *VspBspViewCellsManager::GetViewCell(const Vector3 &point) const
[492]4464{
[508]4465        if (!mVspBspTree)
4466                return NULL;
[572]4467
4468        if (!mViewSpaceBox.IsInside(point))
4469          return NULL;
4470
[508]4471        return mVspBspTree->GetViewCell(point);
[492]4472}
[503]4473
4474
4475void VspBspViewCellsManager::CreateMesh(ViewCell *vc)
4476{
[726]4477        //if (vc->GetMesh()) delete vc->GetMesh();
[503]4478        BspNodeGeometry geom;
[590]4479
4480        mVspBspTree->ConstructGeometry(vc, geom);
[582]4481       
[503]4482        Mesh *mesh = new Mesh();
4483        geom.AddToMesh(*mesh);
4484        vc->SetMesh(mesh);
[726]4485        // put mesh into mesh container so we can savely delete it
[503]4486        mMeshContainer.push_back(mesh);
4487}
[508]4488
4489
[577]4490ViewCellsManager *ViewCellsManager::LoadViewCells(const string filename,
4491                                                                                                  ObjectContainer *objects)
[508]4492{
4493        ViewCellsParser parser;
[564]4494
[577]4495        ViewCellsManager *vm = NULL;
[564]4496
[577]4497        if (parser.ParseFile(filename, &vm, objects))
4498        {
[590]4499                //vm->PrepareLoadedViewCells();
[577]4500                vm->ResetViewCells();
[564]4501
[577]4502                vm->mViewCellsFinished = true;
4503                vm->mMaxPvsSize = (int)objects->size();
[517]4504
[719]4505                // create the meshes and compute volumes
[577]4506                vm->FinalizeViewCells(true);
[564]4507
[685]4508                vm->mViewCellsTree->AssignRandomColors();
[577]4509                Debug << (int)vm->mViewCells.size() << " view cells loaded" << endl;
4510        }
4511        else
4512        {
4513                Debug << "failed loading view cells" << endl;
4514                DEL_PTR(vm);
4515        }
4516
4517        return vm;
[508]4518}
4519
4520
4521inline bool ilt(Intersectable *obj1, Intersectable *obj2)
4522{
4523        return obj1->mId < obj2->mId;
4524}
4525
4526
4527bool VspBspViewCellsManager::ExportViewCells(const string filename)
4528{
[564]4529        cout << "exporting view cells to xml ... ";
[508]4530        std::ofstream stream;
4531
[577]4532        // for output we need unique ids for each view cell
[590]4533        CreateUniqueViewCellIds();
[508]4534
4535        stream.open(filename.c_str());
4536        stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<endl;
4537        stream << "<Visibility_Solution>" << endl;
[564]4538
[577]4539        //-- the view space bounding box
4540        stream << "<ViewSpaceBox"
4541                   << " min=\"" << mViewSpaceBox.Min().x << " " << mViewSpaceBox.Min().y << " " << mViewSpaceBox.Min().z << "\""
4542                   << " max=\"" << mViewSpaceBox.Max().x << " " << mViewSpaceBox.Max().y << " " << mViewSpaceBox.Max().z << "\" />" << endl;
4543
4544        //-- the type of the view cells hierarchy
4545        stream << "<Hierarchy name=\"vspBspTree\" />" << endl;
4546
[508]4547        //-- load the view cells itself, i.e., the ids and the pvs
4548        stream << "<ViewCells>" << endl;
[610]4549       
4550#if 0
4551       
[508]4552        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
[610]4553               
[508]4554        for (it = mViewCells.begin(); it != it_end; ++ it)
4555                ExportViewCell(*it, stream);
[610]4556#else
4557        mViewCellsTree->Export(stream);
4558#endif
[564]4559
[508]4560        stream << "</ViewCells>" << endl;
[564]4561
[508]4562        //-- load the hierarchy
[590]4563        stream << "<Hierarchy>" << endl;
[508]4564        mVspBspTree->Export(stream);
[590]4565        stream << endl << "</Hierarchy>" << endl;
[564]4566
[508]4567        stream << "</Visibility_Solution>" << endl;
4568        stream.close();
4569
4570        cout << "finished" << endl;
4571
4572        return true;
[532]4573}
4574
4575
4576int VspBspViewCellsManager::CastBeam(Beam &beam)
4577{
[535]4578        return mVspBspTree->CastBeam(beam);
[532]4579}
[551]4580
4581
[587]4582void VspBspViewCellsManager::Finalize(ViewCell *viewCell,
4583                                                                          const bool createMesh)
[551]4584{
4585        float area = 0;
4586        float volume = 0;
4587
[580]4588        ViewCellContainer leaves;
[582]4589        mViewCellsTree->CollectLeaves(viewCell, leaves);
[580]4590
4591        ViewCellContainer::const_iterator it, it_end = leaves.end();
4592
[693]4593    for (it = leaves.begin(); it != it_end; ++ it)
[551]4594        {
4595                BspNodeGeometry geom;
[580]4596                BspLeaf *leaf = dynamic_cast<BspViewCell *>(*it)->mLeaf;
[551]4597                mVspBspTree->ConstructGeometry(leaf, geom);
4598
[719]4599                const float lVol = geom.GetVolume();
4600                const float lArea = geom.GetArea();
[693]4601
4602                //(*it)->SetVolume(vol);
4603                //(*it)->SetArea(area);
4604
4605                area += lArea;
4606                volume += lVol;
4607
4608        CreateMesh(*it);
[551]4609        }
4610
4611        viewCell->SetVolume(volume);
4612        viewCell->SetArea(area);
[563]4613}
[575]4614
4615
[693]4616void VspBspViewCellsManager::TestSubdivision()
4617{
4618        ViewCellContainer leaves;
4619        mViewCellsTree->CollectLeaves(mViewCellsTree->GetRoot(), leaves);
4620
4621        ViewCellContainer::const_iterator it, it_end = leaves.end();
4622
4623        const float vol = mViewSpaceBox.GetVolume();
4624        float subdivVol = 0;
4625        float newVol = 0;
4626
4627        for (it = leaves.begin(); it != it_end; ++ it)
4628        {
4629                BspNodeGeometry geom;
4630                BspLeaf *leaf = dynamic_cast<BspViewCell *>(*it)->mLeaf;
4631                mVspBspTree->ConstructGeometry(leaf, geom);
4632
4633                const float lVol = geom.GetVolume();
4634               
4635                newVol += lVol;
4636                subdivVol += (*it)->GetVolume();
[697]4637               
[704]4638                float thres = 0.9f;
[697]4639                if ((lVol < ((*it)->GetVolume() * thres)) || (lVol * thres > ((*it)->GetVolume())))
4640                        Debug << "warning: " << lVol << " " << (*it)->GetVolume() << endl;
[693]4641        }
4642       
4643        Debug << "exact volume: " << vol << endl;
4644        Debug << "subdivision volume: " << subdivVol << endl;
4645        Debug << "new volume: " << newVol << endl;
4646}
4647
4648
[577]4649void VspBspViewCellsManager::PrepareLoadedViewCells()
4650{
4651        // TODO: do I still need this here?
[590]4652        if (0)
[693]4653                mVspBspTree->RepairViewCellsLeafLists();
[577]4654}
[575]4655
[577]4656
[697]4657void VspBspViewCellsManager::TestFilter(const ObjectContainer &objects)
4658{
4659        Exporter *exporter = Exporter::GetExporter("filter.x3d");
[580]4660
[704]4661        Vector3 bsize = mViewSpaceBox.Size();
4662        const Vector3 viewPoint(mViewSpaceBox.Center());
[746]4663        float w = Magnitude(mViewSpaceBox.Size())*mFilterWidth;
4664        const Vector3 width = Vector3(w);
[704]4665       
4666        PrVs testPrVs;
4667       
[697]4668        if (exporter)
4669        {
4670                ViewCellContainer viewCells;
[704]4671       
4672        const AxisAlignedBox3 tbox = GetFilterBBox(viewPoint, mFilterWidth);
4673
4674                GetPrVS(viewPoint, testPrVs);
4675
[697]4676                exporter->SetWireframe();
4677
4678                exporter->SetForcedMaterial(RgbColor(1,1,1));
[704]4679                exporter->ExportBox(tbox);
[697]4680               
4681                exporter->SetFilled();
4682
[705]4683                exporter->SetForcedMaterial(RgbColor(0,1,0));
4684                ExportViewCellGeometry(exporter,  GetViewCell(viewPoint));
4685
4686                //exporter->ResetForcedMaterial();
4687                exporter->SetForcedMaterial(RgbColor(0,0,1));
[704]4688                ExportViewCellGeometry(exporter, testPrVs.mViewCell);
4689
4690        exporter->SetForcedMaterial(RgbColor(1,0,0));
[697]4691                exporter->ExportGeometry(objects);
4692
4693                delete exporter;
4694        }
4695}
4696
4697
[580]4698void VspBspViewCellsManager::CollectMergeCandidates(const VssRayContainer &rays,
4699                                                                                                        vector<MergeCandidate> &candidates)
4700{       
4701        cout << "collecting merge candidates ... " << endl;
4702
4703        if (mUseRaysForMerge)
4704        {
4705                mVspBspTree->CollectMergeCandidates(rays, candidates);
4706        }
4707        else
4708        {
4709                vector<BspLeaf *> leaves;
4710                mVspBspTree->CollectLeaves(leaves);
[708]4711       
[580]4712                mVspBspTree->CollectMergeCandidates(leaves, candidates);
4713        }
4714
4715        cout << "fininshed collecting candidates" << endl;
4716}
4717
4718
[590]4719void VspBspViewCellsManager::AddCurrentViewCellsToHierarchy()
4720{
4721        ViewCellContainer::const_iterator it, it_end = mViewCells.end();
4722        for (it = mViewCells.begin(); it != it_end; ++ it)
4723        {
4724        }
4725}
[580]4726
4727//////////////////////////////////
[575]4728ViewCellsManager *ViewCellsManagerFactory::Create(const string mName)
4729{
4730        //TODO
4731        return NULL;// new VspBspViewCellsManager();
4732}
[580]4733
Note: See TracBrowser for help on using the repository browser.