source: GTP/trunk/Lib/Vis/Preprocessing/src/VspBspTree.cpp @ 697

Revision 697, 89.1 KB checked in by mattausch, 18 years ago (diff)
RevLine 
[478]1#include <stack>
2#include <time.h>
3#include <iomanip>
4
[463]5#include "Plane3.h"
6#include "VspBspTree.h"
7#include "Mesh.h"
8#include "common.h"
9#include "ViewCell.h"
10#include "Environment.h"
11#include "Polygon3.h"
12#include "Ray.h"
13#include "AxisAlignedBox3.h"
14#include "Exporter.h"
15#include "Plane3.h"
16#include "ViewCellBsp.h"
[478]17#include "ViewCellsManager.h"
[532]18#include "Beam.h"
[463]19
[639]20#define USE_FIXEDPOINT_T 0
[590]21
[639]22
[463]23//-- static members
[508]24
[463]25
[482]26int VspBspTree::sFrontId = 0;
[463]27int VspBspTree::sBackId = 0;
28int VspBspTree::sFrontAndBackId = 0;
29
[697]30typedef pair<BspNode *, BspNodeGeometry *> bspNodePair;
[463]31
[557]32
[579]33// pvs penalty can be different from pvs size
34inline float EvalPvsPenalty(const int pvs,
35                                                        const int lower,
36                                                        const int upper)
37{
38        // clamp to minmax values
39        if (pvs < lower)
40                return (float)lower;
41        if (pvs > upper)
42                return (float)upper;
[578]43
[579]44        return (float)pvs;
45}
[463]46
[557]47
[579]48
49
[601]50/******************************************************************************/
51/*                       class VspBspTree implementation                      */
52/******************************************************************************/
[579]53
54
[482]55VspBspTree::VspBspTree():
[463]56mRoot(NULL),
[547]57mUseAreaForPvs(false),
[478]58mCostNormalizer(Limits::Small),
59mViewCellsManager(NULL),
[497]60mOutOfBoundsCell(NULL),
[643]61mStoreRays(false),
[605]62mRenderCostWeight(0.5),
[610]63mUseRandomAxis(false),
[650]64mTimeStamp(1)
[463]65{
[486]66        bool randomize = false;
67        environment->GetBoolValue("VspBspTree.Construction.randomize", randomize);
68        if (randomize)
69                Randomize(); // initialise random generator for heuristics
[463]70
71        //-- termination criteria for autopartition
72        environment->GetIntValue("VspBspTree.Termination.maxDepth", mTermMaxDepth);
73        environment->GetIntValue("VspBspTree.Termination.minPvs", mTermMinPvs);
74        environment->GetIntValue("VspBspTree.Termination.minRays", mTermMinRays);
[547]75        environment->GetFloatValue("VspBspTree.Termination.minProbability", mTermMinProbability);
[463]76        environment->GetFloatValue("VspBspTree.Termination.maxRayContribution", mTermMaxRayContribution);
77        environment->GetFloatValue("VspBspTree.Termination.minAccRayLenght", mTermMinAccRayLength);
[472]78        environment->GetFloatValue("VspBspTree.Termination.maxCostRatio", mTermMaxCostRatio);
79        environment->GetIntValue("VspBspTree.Termination.missTolerance", mTermMissTolerance);
[564]80        environment->GetIntValue("VspBspTree.Termination.maxViewCells", mMaxViewCells);
[666]81
[564]82        //-- max cost ratio for early tree termination
83        environment->GetFloatValue("VspBspTree.Termination.maxCostRatio", mTermMaxCostRatio);
[610]84
[654]85        environment->GetFloatValue("VspBspTree.Termination.minGlobalCostRatio", mTermMinGlobalCostRatio);
86        environment->GetIntValue("VspBspTree.Termination.globalCostMissTolerance", mTermGlobalCostMissTolerance);
[610]87
[654]88        // HACK//mTermMinPolygons = 25;
89
[463]90        //-- factors for bsp tree split plane heuristics
91        environment->GetFloatValue("VspBspTree.Factor.pvs", mPvsFactor);
92        environment->GetFloatValue("VspBspTree.Termination.ct_div_ci", mCtDivCi);
93
[482]94
[463]95        //-- partition criteria
96        environment->GetIntValue("VspBspTree.maxPolyCandidates", mMaxPolyCandidates);
97        environment->GetIntValue("VspBspTree.maxRayCandidates", mMaxRayCandidates);
98        environment->GetIntValue("VspBspTree.splitPlaneStrategy", mSplitPlaneStrategy);
99
100        environment->GetFloatValue("VspBspTree.Construction.epsilon", mEpsilon);
101        environment->GetIntValue("VspBspTree.maxTests", mMaxTests);
102
[564]103        // if only the driving axis is used for axis aligned split
[551]104        environment->GetBoolValue("VspBspTree.splitUseOnlyDrivingAxis", mOnlyDrivingAxis);
[580]105       
[508]106        //-- termination criteria for axis aligned split
107        environment->GetFloatValue("VspBspTree.Termination.AxisAligned.maxRayContribution",
[665]108                                                                mTermMaxRayContriForAxisAligned);
[508]109        environment->GetIntValue("VspBspTree.Termination.AxisAligned.minRays",
[665]110                                                         mTermMinRaysForAxisAligned);
[487]111
[508]112        //environment->GetFloatValue("VspBspTree.maxTotalMemory", mMaxTotalMemory);
113        environment->GetFloatValue("VspBspTree.maxStaticMemory", mMaxMemory);
114
[580]115        environment->GetFloatValue("VspBspTree.Construction.renderCostWeight", mRenderCostWeight);
[607]116        environment->GetBoolValue("VspBspTree.usePolygonSplitIfAvailable", mUsePolygonSplitIfAvailable);
[547]117
[612]118        environment->GetBoolValue("VspBspTree.useCostHeuristics", mUseCostHeuristics);
[655]119        environment->GetBoolValue("VspBspTree.useSplitCostQueue", mUseSplitCostQueue);
[663]120        environment->GetBoolValue("VspBspTree.simulateOctree", mSimulateOctree);
[664]121        environment->GetBoolValue("VspBspTree.useRandomAxis", mUseRandomAxis);
[666]122        environment->GetBoolValue("VspBspTree.useBreathFirstSplits", mBreathFirstSplits);
[580]123
[679]124        environment->GetBoolValue("ViewCells.PostProcess.emptyViewCellsMerge", mEmptyViewCellsMergeAllowed);
[676]125       
[660]126        char subdivisionStatsLog[100];
[666]127        environment->GetStringValue("VspBspTree.subdivisionStats", subdivisionStatsLog);
[660]128        mSubdivisionStats.open(subdivisionStatsLog);
[612]129
[478]130        //-- debug output
[580]131
[473]132        Debug << "******* VSP BSP options ******** " << endl;
133    Debug << "max depth: " << mTermMaxDepth << endl;
134        Debug << "min PVS: " << mTermMinPvs << endl;
[547]135        Debug << "min probabiliy: " << mTermMinProbability << endl;
[473]136        Debug << "min rays: " << mTermMinRays << endl;
137        Debug << "max ray contri: " << mTermMaxRayContribution << endl;
138        Debug << "max cost ratio: " << mTermMaxCostRatio << endl;
139        Debug << "miss tolerance: " << mTermMissTolerance << endl;
140        Debug << "max view cells: " << mMaxViewCells << endl;
141        Debug << "max polygon candidates: " << mMaxPolyCandidates << endl;
[663]142        //Debug << "max plane candidates: " << mMaxRayCandidates << endl;
[486]143        Debug << "randomize: " << randomize << endl;
[582]144
[551]145        Debug << "using area for pvs: " << mUseAreaForPvs << endl;
[580]146        Debug << "render cost weight: " << mRenderCostWeight << endl;
[663]147        Debug << "min global cost ratio: " << mTermMinGlobalCostRatio << endl;
148        Debug << "global cost miss tolerance: " << mTermGlobalCostMissTolerance << endl;
149        Debug << "only driving axis: " << mOnlyDrivingAxis << endl;
150        Debug << "max memory: " << mMaxMemory << endl;
151        Debug << "use poly split if available: " << mUsePolygonSplitIfAvailable << endl;
152        Debug << "use cost heuristics: " << mUseCostHeuristics << endl;
153        Debug << "use split cost queue: " << mUseSplitCostQueue << endl;
154        Debug << "subdivision stats log: " << subdivisionStatsLog << endl;
[664]155        Debug << "use random axis: " << mUseRandomAxis << endl;
156        Debug << "breath first splits: " << mBreathFirstSplits << endl;
[682]157        Debug << "empty view cells merge: " << mEmptyViewCellsMergeAllowed << endl;
158
[665]159        Debug << "octree: " << mSimulateOctree << endl;
[663]160
[463]161        Debug << "Split plane strategy: ";
[564]162
[463]163        if (mSplitPlaneStrategy & RANDOM_POLYGON)
[474]164        {
[463]165                Debug << "random polygon ";
[474]166        }
[463]167        if (mSplitPlaneStrategy & AXIS_ALIGNED)
[472]168        {
[463]169                Debug << "axis aligned ";
[472]170        }
[665]171        if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)
[472]172        {
[474]173                mCostNormalizer += mLeastRaySplitsFactor;
[463]174                Debug << "least ray splits ";
[472]175        }
[463]176        if (mSplitPlaneStrategy & BALANCED_RAYS)
[472]177        {
[474]178                mCostNormalizer += mBalancedRaysFactor;
[463]179                Debug << "balanced rays ";
[472]180        }
[463]181        if (mSplitPlaneStrategy & PVS)
[472]182        {
[474]183                mCostNormalizer += mPvsFactor;
[463]184                Debug << "pvs";
[665]185        }
[482]186
[489]187
[480]188        mSplitCandidates = new vector<SortableEntry>;
[463]189
190        Debug << endl;
191}
192
[580]193
[508]194BspViewCell *VspBspTree::GetOutOfBoundsCell()
195{
196        return mOutOfBoundsCell;
197}
[463]198
[508]199
[489]200BspViewCell *VspBspTree::GetOrCreateOutOfBoundsCell()
201{
202        if (!mOutOfBoundsCell)
[508]203        {
[489]204                mOutOfBoundsCell = new BspViewCell();
[508]205                mOutOfBoundsCell->SetId(-1);
[547]206                mOutOfBoundsCell->SetValid(false);
[508]207        }
[547]208
[489]209        return mOutOfBoundsCell;
210}
211
212
[482]213const BspTreeStatistics &VspBspTree::GetStatistics() const
[463]214{
[574]215        return mBspStats;
[463]216}
217
218
219VspBspTree::~VspBspTree()
220{
221        DEL_PTR(mRoot);
[480]222        DEL_PTR(mSplitCandidates);
[463]223}
224
[579]225
[482]226int VspBspTree::AddMeshToPolygons(Mesh *mesh,
227                                                                  PolygonContainer &polys,
[463]228                                                                  MeshInstance *parent)
229{
230        FaceContainer::const_iterator fi;
[482]231
[463]232        // copy the face data to polygons
233        for (fi = mesh->mFaces.begin(); fi != mesh->mFaces.end(); ++ fi)
234        {
235                Polygon3 *poly = new Polygon3((*fi), mesh);
[482]236
[463]237                if (poly->Valid(mEpsilon))
238                {
239                        poly->mParent = parent; // set parent intersectable
240                        polys.push_back(poly);
241                }
242                else
243                        DEL_PTR(poly);
244        }
245        return (int)mesh->mFaces.size();
246}
247
[580]248
[482]249int VspBspTree::AddToPolygonSoup(const ViewCellContainer &viewCells,
250                                                          PolygonContainer &polys,
[463]251                                                          int maxObjects)
252{
[482]253        int limit = (maxObjects > 0) ?
[463]254                Min((int)viewCells.size(), maxObjects) : (int)viewCells.size();
[482]255
[463]256        int polysSize = 0;
257
258        for (int i = 0; i < limit; ++ i)
259        {
260                if (viewCells[i]->GetMesh()) // copy the mesh data to polygons
261                {
262                        mBox.Include(viewCells[i]->GetBox()); // add to BSP tree aabb
[482]263                        polysSize +=
264                                AddMeshToPolygons(viewCells[i]->GetMesh(),
265                                                                  polys,
[463]266                                                                  viewCells[i]);
267                }
268        }
269
270        return polysSize;
271}
272
[580]273
[482]274int VspBspTree::AddToPolygonSoup(const ObjectContainer &objects,
275                                                                 PolygonContainer &polys,
[463]276                                                                 int maxObjects)
277{
[482]278        int limit = (maxObjects > 0) ?
[463]279                Min((int)objects.size(), maxObjects) : (int)objects.size();
[482]280
[463]281        for (int i = 0; i < limit; ++i)
282        {
283                Intersectable *object = objects[i];//*it;
284                Mesh *mesh = NULL;
285
286                switch (object->Type()) // extract the meshes
287                {
288                case Intersectable::MESH_INSTANCE:
289                        mesh = dynamic_cast<MeshInstance *>(object)->GetMesh();
290                        break;
291                case Intersectable::VIEW_CELL:
292                        mesh = dynamic_cast<ViewCell *>(object)->GetMesh();
293                        break;
294                        // TODO: handle transformed mesh instances
295                default:
296                        Debug << "intersectable type not supported" << endl;
297                        break;
298                }
[482]299
[463]300        if (mesh) // copy the mesh data to polygons
301                {
302                        mBox.Include(object->GetBox()); // add to BSP tree aabb
[485]303                        AddMeshToPolygons(mesh, polys, NULL);
[463]304                }
305        }
306
307        return (int)polys.size();
308}
309
[580]310
[483]311void VspBspTree::Construct(const VssRayContainer &sampleRays,
312                                                   AxisAlignedBox3 *forcedBoundingBox)
[463]313{
[574]314        mBspStats.nodes = 1;
[463]315        mBox.Initialize();      // initialise BSP tree bounding box
[482]316
[484]317        if (forcedBoundingBox)
318                mBox = *forcedBoundingBox;
319       
[463]320        PolygonContainer polys;
321        RayInfoContainer *rays = new RayInfoContainer();
322
323        VssRayContainer::const_iterator rit, rit_end = sampleRays.end();
324
325        long startTime = GetTime();
326
[480]327        cout << "Extracting polygons from rays ... ";
[463]328
329        Intersectable::NewMail();
330
[511]331        int numObj = 0;
[542]332
[463]333        //-- extract polygons intersected by the rays
334        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
335        {
336                VssRay *ray = *rit;
[482]337
[484]338                if ((mBox.IsInside(ray->mTermination) || !forcedBoundingBox) &&
339                        ray->mTerminationObject &&
340                        !ray->mTerminationObject->Mailed())
[463]341                {
342                        ray->mTerminationObject->Mail();
343                        MeshInstance *obj = dynamic_cast<MeshInstance *>(ray->mTerminationObject);
344                        AddMeshToPolygons(obj->GetMesh(), polys, obj);
[511]345                        ++ numObj;
[648]346
[484]347                        //-- compute bounding box
348                        if (!forcedBoundingBox)
349                                mBox.Include(ray->mTermination);
[463]350                }
351
[484]352                if ((mBox.IsInside(ray->mOrigin) || !forcedBoundingBox) &&
353                        ray->mOriginObject &&
354                        !ray->mOriginObject->Mailed())
[463]355                {
356                        ray->mOriginObject->Mail();
357                        MeshInstance *obj = dynamic_cast<MeshInstance *>(ray->mOriginObject);
358                        AddMeshToPolygons(obj->GetMesh(), polys, obj);
[511]359                        ++ numObj;
360
[484]361                        //-- compute bounding box
362                        if (!forcedBoundingBox)
363                                mBox.Include(ray->mOrigin);
[463]364                }
365        }
[535]366       
[653]367        Debug << "maximal pvs (i.e., pvs still considered as valid) : "
368                  << mViewCellsManager->GetMaxPvsSize() << endl;
[580]369
[463]370        //-- store rays
371        for (rit = sampleRays.begin(); rit != rit_end; ++ rit)
372        {
373                VssRay *ray = *rit;
[482]374
[463]375                float minT, maxT;
376
[564]377                static Ray hray;
378                hray.Init(*ray);
[562]379
[483]380                // TODO: not very efficient to implictly cast between rays types
[564]381                if (mBox.GetRaySegment(hray, minT, maxT))
[463]382                {
383                        float len = ray->Length();
[482]384
385                        if (!len)
[463]386                                len = Limits::Small;
[482]387
[463]388                        rays->push_back(RayInfo(ray, minT / len, maxT / len));
389                }
390        }
391
[587]392        // normalize
[547]393        if (mUseAreaForPvs)
[587]394                mTermMinProbability *= mBox.SurfaceArea();
[547]395        else
396                mTermMinProbability *= mBox.GetVolume();
397
[648]398        // throw out unnecessary polygons
399        PreprocessPolygons(polys);
400
[574]401        mBspStats.polys = (int)polys.size();
[654]402        mGlobalCostMisses = 0;
403
[475]404        cout << "finished" << endl;
[463]405
[482]406        Debug << "\nPolygon extraction: " << (int)polys.size() << " polys extracted from "
[475]407                  << (int)sampleRays.size() << " rays in "
408                  << TimeDiff(startTime, GetTime())*1e-3 << " secs" << endl << endl;
409
[655]410        // use split cost priority queue
411        if (mUseSplitCostQueue)
412        {
[654]413                ConstructWithSplitQueue(polys, rays);
[655]414        }
[654]415        else
[655]416        {
[654]417                Construct(polys, rays);
[655]418        }
[463]419
420        // clean up polygons
421        CLEAR_CONTAINER(polys);
422}
423
[508]424
[612]425// TODO: return memory usage in MB
[656]426float VspBspTree::GetMemUsage() const
[508]427{
[656]428        return (float)
429                 (sizeof(VspBspTree) +
430                  mBspStats.Leaves() * sizeof(BspLeaf) +
431                  mCreatedViewCells * sizeof(BspViewCell) +
432                  mBspStats.pvs * sizeof(ObjectPvsData) +
433                  mBspStats.Interior() * sizeof(BspInterior) +
434                  mBspStats.accumRays * sizeof(RayInfo)) / (1024.0f * 1024.0f);
[508]435}
436
437
438
[463]439void VspBspTree::Construct(const PolygonContainer &polys, RayInfoContainer *rays)
440{
[600]441        VspBspTraversalQueue tQueue;
[463]442
443        mRoot = new BspLeaf();
444
445        // constrruct root node geometry
446        BspNodeGeometry *geom = new BspNodeGeometry();
447        ConstructGeometry(mRoot, *geom);
448
[547]449        const float prop = mUseAreaForPvs ? geom->GetArea() : geom->GetVolume();
450
[482]451        VspBspTraversalData tData(mRoot,
452                                                          new PolygonContainer(polys),
[463]453                                                          0,
[482]454                                                          rays,
455                              ComputePvsSize(*rays),
[547]456                                                          prop,
[463]457                                                          geom);
[663]458
[664]459        EvalPriority(tData);
460       
[663]461
462        if (mSimulateOctree)
463        tData.mAxis = 0;
464
[578]465        // first node is kd node, i.e. an axis aligned box
[678]466        if (0)
[578]467        tData.mIsKdNode = true;
468        else
469                tData.mIsKdNode = false;
[562]470
[600]471        tQueue.push(tData);
[463]472
[609]473
[605]474        mTotalCost = tData.mPvs * tData.mProbability / mBox.GetVolume();
[607]475        mTotalPvsSize = tData.mPvs;
476       
[601]477        mSubdivisionStats
[605]478                        << "#ViewCells\n1\n" <<  endl
[601]479                        << "#RenderCostDecrease\n0\n" << endl
[607]480                        << "#TotalRenderCost\n" << mTotalCost << endl
481                        << "#AvgRenderCost\n" << mTotalPvsSize << endl;
[601]482
[600]483        Debug << "total cost: " << mTotalCost << endl;
484       
[601]485       
[574]486        mBspStats.Start();
[667]487        cout << "Constructing vsp bsp tree ... \n";
[463]488
[542]489        long startTime = GetTime();     
[664]490        int nLeaves = 500;
491        int nViewCells = 500;
[587]492
493        // used for intermediate time measurements and progress
[542]494        long interTime = GetTime();     
[547]495
[542]496        mOutOfMemory = false;
[482]497
[612]498        mCreatedViewCells = 0;
499       
[600]500        while (!tQueue.empty())
[463]501        {
[600]502                tData = tQueue.top();
503            tQueue.pop();               
[463]504
[508]505                if (0 && !mOutOfMemory)
506                {
507                        float mem = GetMemUsage();
[478]508
[508]509                        if (mem > mMaxMemory)
510                        {
511                                mOutOfMemory = true;
512                                Debug << "memory limit reached: " << mem << endl;
513                        }
514                }
515
[587]516                // subdivide leaf node
[600]517                BspNode *r = Subdivide(tQueue, tData);
[463]518
519                if (r == mRoot)
[482]520                        Debug << "VSP BSP tree construction time spent at root: "
[542]521                                  << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
522
[654]523                if (mBspStats.Leaves() >= nLeaves)
[542]524                {
[612]525                        nLeaves += 500;
526
[574]527                        cout << "leaves=" << mBspStats.Leaves() << endl;
[542]528                        Debug << "needed "
[587]529                                  << TimeDiff(interTime, GetTime())*1e-3
[612]530                                  << " secs to create 500 view cells" << endl;
[542]531                        interTime = GetTime();
532                }
[612]533
[664]534                if (mCreatedViewCells >= nViewCells)
[612]535                {
536                        nViewCells += 500;
537
538                        cout << "generated " << mCreatedViewCells << " viewcells" << endl;
539                }
[463]540        }
541
[542]542        Debug << "Used Memory: " << GetMemUsage() << " MB" << endl << endl;
[463]543        cout << "finished\n";
544
[574]545        mBspStats.Stop();
[463]546}
547
[508]548
[653]549
[654]550void VspBspTree::ConstructWithSplitQueue(const PolygonContainer &polys,
[653]551                                                                                          RayInfoContainer *rays)
552{
553        VspBspSplitQueue tQueue;
554
555        mRoot = new BspLeaf();
556
557        // constrruct root node geometry
558        BspNodeGeometry *geom = new BspNodeGeometry();
559        ConstructGeometry(mRoot, *geom);
560
561        const float prop = mUseAreaForPvs ? geom->GetArea() : geom->GetVolume();
562
563        VspBspTraversalData tData(mRoot,
564                                                          new PolygonContainer(polys),
565                                                          0,
566                                                          rays,
567                              ComputePvsSize(*rays),
568                                                          prop,
569                                                          geom);
570
[664]571       
[663]572
[660]573        // compute first split candidate
[653]574        VspBspSplitCandidate splitCandidate;
575        EvalSplitCandidate(tData, splitCandidate);
576
577        tQueue.push(splitCandidate);
578
579        mTotalCost = tData.mPvs * tData.mProbability / mBox.GetVolume();
580        mTotalPvsSize = tData.mPvs;
581       
582        mSubdivisionStats
583                        << "#ViewCells\n1\n" <<  endl
584                        << "#RenderCostDecrease\n0\n" << endl
[654]585                        << "#dummy\n0\n" << endl
[653]586                        << "#TotalRenderCost\n" << mTotalCost << endl
587                        << "#AvgRenderCost\n" << mTotalPvsSize << endl;
588
589        Debug << "total cost: " << mTotalCost << endl;
590       
591       
592        mBspStats.Start();
[667]593        cout << "Constructing vsp bsp tree ... \n";
[653]594
595        long startTime = GetTime();     
[666]596        int nLeaves = 500;
597        int nViewCells = 500;
[653]598
599        // used for intermediate time measurements and progress
600        long interTime = GetTime();     
601
602        mOutOfMemory = false;
603
604        mCreatedViewCells = 0;
605       
606        while (!tQueue.empty())
607        {
608                splitCandidate = tQueue.top();
609            tQueue.pop();               
610
[654]611                // cost ratio of cost decrease / totalCost
612                float costRatio = splitCandidate.GetCost() / mTotalCost;
613
[655]614                //Debug << "cost ratio: " << costRatio << endl;
[654]615
616                if (costRatio < mTermMinGlobalCostRatio)
617                        ++ mGlobalCostMisses;
[655]618               
[653]619                if (0 && !mOutOfMemory)
620                {
621                        float mem = GetMemUsage();
622
623                        if (mem > mMaxMemory)
624                        {
625                                mOutOfMemory = true;
626                                Debug << "memory limit reached: " << mem << endl;
627                        }
628                }
629
630                // subdivide leaf node
631                BspNode *r = Subdivide(tQueue, splitCandidate);
632
633                if (r == mRoot)
634                        Debug << "VSP BSP tree construction time spent at root: "
635                                  << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl;
636
[654]637                if (mBspStats.Leaves() >= nLeaves)
[653]638                {
639                        nLeaves += 500;
640
641                        cout << "leaves=" << mBspStats.Leaves() << endl;
642                        Debug << "needed "
643                                  << TimeDiff(interTime, GetTime())*1e-3
644                                  << " secs to create 500 view cells" << endl;
645                        interTime = GetTime();
646                }
647
648                if (mCreatedViewCells == nViewCells)
649                {
650                        nViewCells += 500;
651
652                        cout << "generated " << mCreatedViewCells << " viewcells" << endl;
653                }
654        }
655
656        Debug << "Used Memory: " << GetMemUsage() << " MB" << endl << endl;
657        cout << "finished\n";
658
659        mBspStats.Stop();
660}
661
662
[654]663bool VspBspTree::LocalTerminationCriteriaMet(const VspBspTraversalData &data) const
[463]664{
[482]665        return
[463]666                (((int)data.mRays->size() <= mTermMinRays) ||
[473]667                 (data.mPvs <= mTermMinPvs)   ||
[547]668                 (data.mProbability <= mTermMinProbability) ||
[535]669                 (data.GetAvgRayContribution() > mTermMaxRayContribution) ||
[463]670                 (data.mDepth >= mTermMaxDepth));
671}
672
[508]673
[654]674bool VspBspTree::GlobalTerminationCriteriaMet(const VspBspTraversalData &data) const
675{
676        return
677                (mOutOfMemory
678                || (mBspStats.Leaves() >= mMaxViewCells)
679                || (mGlobalCostMisses >= mTermGlobalCostMissTolerance)
680                 );
681}
682
683
684
[600]685BspNode *VspBspTree::Subdivide(VspBspTraversalQueue &tQueue,
[463]686                                                           VspBspTraversalData &tData)
687{
[473]688        BspNode *newNode = tData.mNode;
689
[654]690        if (!LocalTerminationCriteriaMet(tData) && !GlobalTerminationCriteriaMet(tData))
[473]691        {
692                PolygonContainer coincident;
[482]693
[473]694                VspBspTraversalData tFrontData;
695                VspBspTraversalData tBackData;
[612]696
[663]697                if (mSimulateOctree)
698                {       // choose axes in circular motion
699                        tFrontData.mAxis = (tData.mAxis + 1) % 3;
700                        tBackData.mAxis = (tData.mAxis + 1) % 3;
701                }
702
[473]703                // create new interior node and two leaf nodes
704                // or return leaf as it is (if maxCostRatio missed)
[653]705                int splitAxis;
706                bool splitFurther = true;
707                int maxCostMisses = tData.mMaxCostMisses;
708               
709                Plane3 splitPlane;
710                BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
711
712                if (!SelectPlane(splitPlane, leaf, tData, tFrontData, tBackData, splitAxis))
[473]713                {
[653]714                        ++ maxCostMisses;
715
716                        if (maxCostMisses > mTermMissTolerance)
717                        {
718                                // terminate branch because of max cost
719                                ++ mBspStats.maxCostNodes;
720                                splitFurther = false;
721                        }
722                }
723       
724                if (splitFurther) //-- continue subdivision
725                {
726                        newNode = SubdivideNode(splitPlane, tData, tFrontData, tBackData, coincident);
727
728                        if (splitAxis < 3)
729                                ++ mBspStats.splits[splitAxis];
730                        else
731                                ++ mBspStats.polySplits;
732
733                        tFrontData.mIsKdNode = tBackData.mIsKdNode = (tData.mIsKdNode && splitAxis < 3);
[663]734
[653]735                        // how often was max cost ratio missed in this branch?
736                        tFrontData.mMaxCostMisses = maxCostMisses;
737                        tBackData.mMaxCostMisses = maxCostMisses;
738
[664]739                        EvalPriority(tFrontData);
740                        EvalPriority(tBackData);
[663]741
[600]742                        if (1)
743                        {
[675]744
[611]745                                float cFront = (float)tFrontData.mPvs * tFrontData.mProbability;
746                                float cBack = (float)tBackData.mPvs * tBackData.mProbability;
747                                float cData = (float)tData.mPvs * tData.mProbability;;
[605]748
[670]749                float costDecr = (cFront + cBack - cData) / mBox.GetVolume();
[607]750
[600]751                                mTotalCost += costDecr;
[607]752                                mTotalPvsSize += tFrontData.mPvs + tBackData.mPvs - tData.mPvs;
[600]753
754                                mSubdivisionStats
[605]755                                                << "#ViewCells\n" << mBspStats.Leaves() << endl
[600]756                                                << "#RenderCostDecrease\n" << -costDecr << endl
[607]757                                                << "#TotalRenderCost\n" << mTotalCost << endl
[650]758                                                << "#AvgRenderCost\n" << (float)mTotalPvsSize / (float)mBspStats.Leaves() << endl;
[600]759                        }
760
[473]761                        // push the children on the stack
[600]762                        tQueue.push(tFrontData);
763                        tQueue.push(tBackData);
[473]764
765                        // delete old leaf node
[482]766                        DEL_PTR(tData.mNode);
[473]767                }
768        }
[482]769
[478]770        //-- terminate traversal and create new view cell
[473]771        if (newNode->IsLeaf())
[463]772        {
[473]773                BspLeaf *leaf = dynamic_cast<BspLeaf *>(newNode);
[547]774                BspViewCell *viewCell = new BspViewCell();
[489]775               
[463]776                leaf->SetViewCell(viewCell);
[487]777       
778                //-- update pvs
[556]779                int conSamp = 0;
780                float sampCon = 0.0f;
781                AddToPvs(leaf, *tData.mRays, sampCon, conSamp);
[487]782
[574]783                mBspStats.contributingSamples += conSamp;
784                mBspStats.sampleContributions +=(int) sampCon;
[487]785
786                //-- store additional info
[478]787                if (mStoreRays)
788                {
789                        RayInfoContainer::const_iterator it, it_end = tData.mRays->end();
790                        for (it = tData.mRays->begin(); it != it_end; ++ it)
[639]791                        {
792                                (*it).mRay->Ref();                     
[478]793                                leaf->mVssRays.push_back((*it).mRay);
[639]794                        }
[478]795                }
[612]796
[564]797                // should I check here?
[562]798                if (0 && !mViewCellsManager->CheckValidity(viewCell, 0, mViewCellsManager->GetMaxPvsSize()))
[547]799                {
800                        viewCell->SetValid(false);
801                        leaf->SetTreeValid(false);
802                        PropagateUpValidity(leaf);
[463]803
[574]804                        ++ mBspStats.invalidLeaves;
[547]805                }
806               
[580]807        viewCell->mLeaf = leaf;
[547]808
809                if (mUseAreaForPvs)
810                        viewCell->SetArea(tData.mProbability);
811                else
812                        viewCell->SetVolume(tData.mProbability);
813
814                leaf->mProbability = tData.mProbability;
815
[487]816                EvaluateLeafStats(tData);               
[463]817        }
[482]818
[473]819        //-- cleanup
[478]820        tData.Clear();
[463]821
[472]822        return newNode;
[463]823}
824
[487]825
[653]826BspNode *VspBspTree::Subdivide(VspBspSplitQueue &tQueue,
827                                                           VspBspSplitCandidate &splitCandidate)
828{
829        VspBspTraversalData &tData = splitCandidate.mParentData;
830
831        BspNode *newNode = tData.mNode;
832
[654]833        if (!LocalTerminationCriteriaMet(tData) && !GlobalTerminationCriteriaMet(tData))
[666]834        {       
[653]835                PolygonContainer coincident;
836
837                VspBspTraversalData tFrontData;
838                VspBspTraversalData tBackData;
839
840                //-- continue subdivision
841                // create new interior node and two leaf node
842                const Plane3 splitPlane = splitCandidate.mSplitPlane;
[654]843                               
[653]844                newNode = SubdivideNode(splitPlane, tData, tFrontData, tBackData, coincident);
[666]845       
[660]846                const int splitAxis = splitCandidate.mSplitAxis;
847                const int maxCostMisses = splitCandidate.mMaxCostMisses;
848
[654]849                if (splitAxis < 3)
850                        ++ mBspStats.splits[splitAxis];
851                else
852                        ++ mBspStats.polySplits;
[653]853
[654]854                tFrontData.mIsKdNode = tBackData.mIsKdNode = (tData.mIsKdNode && splitAxis < 3);
[660]855               
[654]856                // how often was max cost ratio missed in this branch?
857                tFrontData.mMaxCostMisses = maxCostMisses;
858                tBackData.mMaxCostMisses = maxCostMisses;
[664]859                       
[666]860               
[653]861                if (1)
862                {
863                        float cFront = (float)tFrontData.mPvs * tFrontData.mProbability;
864                        float cBack = (float)tBackData.mPvs * tBackData.mProbability;
[675]865                        float cData = (float)tData.mPvs * tData.mProbability;
[653]866
[675]867                       
[653]868                        float costDecr =
869                                (cFront + cBack - cData) / mBox.GetVolume();
870
871                        mTotalCost += costDecr;
872                        mTotalPvsSize += tFrontData.mPvs + tBackData.mPvs - tData.mPvs;
873
874                        mSubdivisionStats
875                                        << "#ViewCells\n" << mBspStats.Leaves() << endl
[654]876                                        << "#RenderCostDecrease\n" << -costDecr << endl
877                                        << "#dummy\n" << splitCandidate.GetCost() << endl
[653]878                                        << "#TotalRenderCost\n" << mTotalCost << endl
879                                        << "#AvgRenderCost\n" << (float)mTotalPvsSize / (float)mBspStats.Leaves() << endl;
880                }
881
[666]882       
[653]883                //-- push the new split candidates on the stack
884                VspBspSplitCandidate frontCandidate;
885                VspBspSplitCandidate backCandidate;
886
[654]887                EvalSplitCandidate(tFrontData, frontCandidate);
888                EvalSplitCandidate(tBackData, backCandidate);
889       
[653]890                tQueue.push(frontCandidate);
891                tQueue.push(backCandidate);
[666]892       
[653]893                // delete old leaf node
894                DEL_PTR(tData.mNode);
895        }
896
[654]897
[653]898        //-- terminate traversal and create new view cell
899        if (newNode->IsLeaf())
900        {
901                BspLeaf *leaf = dynamic_cast<BspLeaf *>(newNode);
902                BspViewCell *viewCell = new BspViewCell();
903               
904                leaf->SetViewCell(viewCell);
905       
906                //-- update pvs
907                int conSamp = 0;
908                float sampCon = 0.0f;
909                AddToPvs(leaf, *tData.mRays, sampCon, conSamp);
910
911                mBspStats.contributingSamples += conSamp;
912                mBspStats.sampleContributions +=(int) sampCon;
913
914                //-- store additional info
915                if (mStoreRays)
916                {
917                        RayInfoContainer::const_iterator it, it_end = tData.mRays->end();
918                        for (it = tData.mRays->begin(); it != it_end; ++ it)
919                        {
920                                (*it).mRay->Ref();                     
921                                leaf->mVssRays.push_back((*it).mRay);
922                        }
923                }
924
925                // should I check here?
926                viewCell->mLeaf = leaf;
927
928                if (mUseAreaForPvs)
929                        viewCell->SetArea(tData.mProbability);
930                else
931                        viewCell->SetVolume(tData.mProbability);
932
[675]933        leaf->mProbability = tData.mProbability;
[653]934
935                EvaluateLeafStats(tData);               
936        }
937
938        //-- cleanup
939        tData.Clear();
940
941        return newNode;
942}
943
944
[664]945void VspBspTree::EvalPriority(VspBspTraversalData &tData) const
946{
947    tData.mPriority = mBreathFirstSplits ?
948                (float)-tData.mDepth : tData.mPvs * tData.mProbability;
[670]949        //cout << "priority: " << tData.mPriority << endl;
[664]950}
951
952
[652]953void VspBspTree::EvalSplitCandidate(VspBspTraversalData &tData,
954                                                                        VspBspSplitCandidate &splitData)
955{
956        VspBspTraversalData frontData;
957        VspBspTraversalData backData;
958
959        BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
[654]960
961        // compute locally best split plane
[663]962        bool success = SelectPlane(splitData.mSplitPlane, leaf, tData,
[666]963                                                           frontData, backData, splitData.mSplitAxis);
[652]964
965        // TODO: reuse
966        DEL_PTR(frontData.mGeometry);
967        DEL_PTR(backData.mGeometry);
968       
[654]969        // compute global decrease in render cost
[652]970        splitData.mRenderCost = EvalRenderCostDecrease(splitData.mSplitPlane, tData);
971        splitData.mParentData = tData;
[660]972        splitData.mMaxCostMisses = success ? tData.mMaxCostMisses : tData.mMaxCostMisses + 1;
[652]973}
974
975
[653]976BspInterior *VspBspTree::SubdivideNode(const Plane3 &splitPlane,
977                                                                           VspBspTraversalData &tData,
978                                                                           VspBspTraversalData &frontData,
979                                                                           VspBspTraversalData &backData,
980                                                                           PolygonContainer &coincident)
[463]981{
982        BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);
[508]983       
[473]984        //-- the front and back traversal data is filled with the new values
985        frontData.mDepth = tData.mDepth + 1;
[508]986        frontData.mPolygons = new PolygonContainer();
[473]987        frontData.mRays = new RayInfoContainer();
[508]988       
[473]989        backData.mDepth = tData.mDepth + 1;
[508]990        backData.mPolygons = new PolygonContainer();
[473]991        backData.mRays = new RayInfoContainer();
[508]992       
[653]993
994        //-- subdivide rays
[652]995        SplitRays(splitPlane,
[482]996                          *tData.mRays,
997                          *frontData.mRays,
[463]998                          *backData.mRays);
[482]999
[463]1000
[472]1001        // compute pvs
[463]1002        frontData.mPvs = ComputePvsSize(*frontData.mRays);
1003        backData.mPvs = ComputePvsSize(*backData.mRays);
1004
[508]1005        // split front and back node geometry and compute area
[547]1006       
1007        // if geometry was not already computed
[602]1008        if (!frontData.mGeometry && !backData.mGeometry)
[463]1009        {
[547]1010                frontData.mGeometry = new BspNodeGeometry();
1011                backData.mGeometry = new BspNodeGeometry();
[482]1012
[547]1013                tData.mGeometry->SplitGeometry(*frontData.mGeometry,
1014                                                                           *backData.mGeometry,
[652]1015                                                                           splitPlane,
[547]1016                                                                           mBox,
[679]1017                                                                           //0.0f);
1018                                                                           mEpsilon);
[508]1019               
[547]1020                if (mUseAreaForPvs)
1021                {
1022                        frontData.mProbability = frontData.mGeometry->GetArea();
1023                        backData.mProbability = backData.mGeometry->GetArea();
[508]1024                }
[547]1025                else
1026                {
1027                        frontData.mProbability = frontData.mGeometry->GetVolume();
[654]1028                        backData.mProbability = tData.mProbability - frontData.mProbability;
[676]1029
1030                        if (frontData.mProbability < -0.00001)
[694]1031                                Debug << "fatal error f: " << frontData.mProbability << endl;
[676]1032                        if (backData.mProbability < -0.00001)
[694]1033                                Debug << "fatal error b: " << backData.mProbability << endl;
[676]1034
[675]1035                        // clamp because of precision issues
[676]1036                        if (0)
1037                        {
1038                                if (frontData.mProbability < 0) frontData.mProbability = 0;
1039                                if (backData.mProbability < 0) backData.mProbability = 0;
1040                        }
[547]1041                }
[463]1042        }
[663]1043
[547]1044       
[652]1045    // subdivide polygons
1046        SplitPolygons(splitPlane,
1047                                  *tData.mPolygons,
1048                      *frontData.mPolygons,
1049                                  *backData.mPolygons,
1050                                  coincident);
[463]1051
[652]1052
1053
[653]1054        ///////////////////////////////////////
1055        // subdivide further
[652]1056
1057        mBspStats.nodes += 2;
1058
1059       
1060        BspInterior *interior = new BspInterior(splitPlane);
1061
1062#ifdef _DEBUG
1063        Debug << interior << endl;
1064#endif
1065
[463]1066        //-- create front and back leaf
1067
1068        BspInterior *parent = leaf->GetParent();
1069
1070        // replace a link from node's parent
[487]1071        if (parent)
[463]1072        {
1073                parent->ReplaceChildLink(leaf, interior);
1074                interior->SetParent(parent);
1075        }
1076        else // new root
1077        {
1078                mRoot = interior;
1079        }
1080
1081        // and setup child links
1082        interior->SetupChildLinks(new BspLeaf(interior), new BspLeaf(interior));
[482]1083
[463]1084        frontData.mNode = interior->GetFront();
1085        backData.mNode = interior->GetBack();
[473]1086
[650]1087        interior->mTimeStamp = mTimeStamp ++;
[652]1088       
[463]1089        //DEL_PTR(leaf);
1090        return interior;
1091}
1092
[508]1093
[463]1094void VspBspTree::AddToPvs(BspLeaf *leaf,
[482]1095                                                  const RayInfoContainer &rays,
[556]1096                                                  float &sampleContributions,
[463]1097                                                  int &contributingSamples)
1098{
[556]1099  sampleContributions = 0;
1100  contributingSamples = 0;
1101 
1102  RayInfoContainer::const_iterator it, it_end = rays.end();
1103 
1104  ViewCell *vc = leaf->GetViewCell();
1105 
1106  // add contributions from samples to the PVS
1107  for (it = rays.begin(); it != it_end; ++ it)
[463]1108        {
[556]1109          float sc = 0.0f;
1110          VssRay *ray = (*it).mRay;
1111          bool madeContrib = false;
1112          float contribution;
1113          if (ray->mTerminationObject) {
1114                if (vc->GetPvs().AddSample(ray->mTerminationObject, ray->mPdf, contribution))
1115                  madeContrib = true;
1116                sc += contribution;
1117          }
1118         
1119          if (ray->mOriginObject) {
1120                if (vc->GetPvs().AddSample(ray->mOriginObject, ray->mPdf, contribution))
1121                  madeContrib = true;
1122                sc += contribution;
1123          }
1124         
1125          sampleContributions += sc;
1126          if (madeContrib)
1127                  ++ contributingSamples;
1128               
1129          //leaf->mVssRays.push_back(ray);
[463]1130        }
1131}
1132
[580]1133
[480]1134void VspBspTree::SortSplitCandidates(const RayInfoContainer &rays, const int axis)
[463]1135{
[480]1136        mSplitCandidates->clear();
[463]1137
[480]1138        int requestedSize = 2 * (int)(rays.size());
1139        // creates a sorted split candidates array
1140        if (mSplitCandidates->capacity() > 500000 &&
[612]1141                requestedSize < (int)(mSplitCandidates->capacity()  / 10) )
[480]1142        {
[482]1143        delete mSplitCandidates;
[480]1144                mSplitCandidates = new vector<SortableEntry>;
1145        }
[463]1146
[480]1147        mSplitCandidates->reserve(requestedSize);
1148
1149        // insert all queries
[612]1150        for (RayInfoContainer::const_iterator ri = rays.begin(); ri < rays.end(); ++ ri)
[473]1151        {
[612]1152                const bool positive = (*ri).mRay->HasPosDir(axis);
[480]1153                mSplitCandidates->push_back(SortableEntry(positive ? SortableEntry::ERayMin : SortableEntry::ERayMax,
[482]1154                                                                                                  (*ri).ExtrapOrigin(axis), (*ri).mRay));
[480]1155
1156                mSplitCandidates->push_back(SortableEntry(positive ? SortableEntry::ERayMax : SortableEntry::ERayMin,
[482]1157                                                                                                  (*ri).ExtrapTermination(axis), (*ri).mRay));
[473]1158        }
[480]1159
1160        stable_sort(mSplitCandidates->begin(), mSplitCandidates->end());
[463]1161}
1162
[580]1163
[480]1164float VspBspTree::BestCostRatioHeuristics(const RayInfoContainer &rays,
1165                                                                                  const AxisAlignedBox3 &box,
1166                                                                                  const int pvsSize,
[481]1167                                                                                  const int &axis,
[480]1168                                          float &position)
[463]1169{
[480]1170        SortSplitCandidates(rays, axis);
1171
[463]1172        // go through the lists, count the number of objects left and right
1173        // and evaluate the following cost funcion:
[480]1174        // C = ct_div_ci  + (ql*rl + qr*rr)/queries
1175
[612]1176        int pvsl = 0, pvsr = pvsSize;
[480]1177
[612]1178        int pvsBack = pvsl;
1179        int pvsFront = pvsr;
1180
[463]1181        float minBox = box.Min(axis);
1182        float maxBox = box.Max(axis);
[480]1183        float sizeBox = maxBox - minBox;
1184
[612]1185        float minBand = minBox + 0.1f * (maxBox - minBox);
1186        float maxBand = minBox + 0.9f * (maxBox - minBox);
[480]1187
[612]1188        float sum = (float)pvsSize * sizeBox;
[463]1189        float minSum = 1e20f;
1190
[480]1191        Intersectable::NewMail();
1192
[612]1193        RayInfoContainer::const_iterator ri, ri_end = rays.end();
1194
1195        // set all object as belonging to the front pvs
1196        for(ri = rays.begin(); ri != ri_end; ++ ri)
[463]1197        {
[612]1198                Intersectable *oObject = (*ri).mRay->mOriginObject;
1199                Intersectable *tObject = (*ri).mRay->mTerminationObject;
1200
1201                if (oObject)
[463]1202                {
[612]1203                        if (!oObject->Mailed())
[482]1204                        {
[612]1205                                oObject->Mail();
1206                                oObject->mCounter = 1;
[482]1207                        }
[612]1208                        else
1209                        {
1210                                ++ oObject->mCounter;
1211                        }
[463]1212                }
[612]1213                if (tObject)
1214                {
1215                        if (!tObject->Mailed())
1216                        {
1217                                tObject->Mail();
1218                                tObject->mCounter = 1;
1219                        }
1220                        else
1221                        {
1222                                ++ tObject->mCounter;
1223                        }
1224                }
[480]1225        }
1226
1227        Intersectable::NewMail();
1228
[612]1229        vector<SortableEntry>::const_iterator ci, ci_end = mSplitCandidates->end();
1230
1231        for (ci = mSplitCandidates->begin(); ci < ci_end; ++ ci)
[480]1232        {
1233                VssRay *ray;
[612]1234                ray = (*ci).ray;
1235               
1236                Intersectable *oObject = ray->mOriginObject;
1237                Intersectable *tObject = ray->mTerminationObject;
1238               
[480]1239
1240                switch ((*ci).type)
[463]1241                {
[480]1242                        case SortableEntry::ERayMin:
1243                                {
[612]1244                                        if (oObject && !oObject->Mailed())
[480]1245                                        {
[612]1246                                                oObject->Mail();
1247                                                ++ pvsl;
[480]1248                                        }
[612]1249                                        if (tObject && !tObject->Mailed())
1250                                        {
1251                                                tObject->Mail();
1252                                                ++ pvsl;
1253                                        }
[480]1254                                        break;
1255                                }
1256                        case SortableEntry::ERayMax:
1257                                {
[612]1258                                        if (oObject)
1259                                        {
1260                                                if (-- oObject->mCounter == 0)
1261                                                        -- pvsr;
1262                                        }
[463]1263
[612]1264                                        if (tObject)
[480]1265                                        {
[612]1266                                                if (-- tObject->mCounter == 0)
1267                                                        -- pvsr;
[480]1268                                        }
1269
1270                                        break;
1271                                }
1272                }
1273
1274                // Note: sufficient to compare size of bounding boxes of front and back side?
1275                if ((*ci).value > minBand && (*ci).value < maxBand)
1276                {
[612]1277                        sum = pvsl * ((*ci).value - minBox) + pvsr * (maxBox - (*ci).value);
[480]1278
1279                        //  cout<<"pos="<<(*ci).value<<"\t q=("<<ql<<","<<qr<<")\t r=("<<rl<<","<<rr<<")"<<endl;
1280                        // cout<<"cost= "<<sum<<endl;
1281
1282                        if (sum < minSum)
[463]1283                        {
1284                                minSum = sum;
1285                                position = (*ci).value;
1286
[612]1287                                pvsBack = pvsl;
1288                                pvsFront = pvsr;
[463]1289                        }
1290                }
1291        }
1292
[612]1293        // -- compute cost
[463]1294
[612]1295        const int lowerPvsLimit = mViewCellsManager->GetMinPvsSize();
1296        const int upperPvsLimit = mViewCellsManager->GetMaxPvsSize();
1297
1298        const float pOverall = sizeBox;
1299
1300        const float pBack = position - minBox;
1301        const float pFront = maxBox - position;
1302       
1303        const float penaltyOld = EvalPvsPenalty(pvsSize, lowerPvsLimit, upperPvsLimit);
1304    const float penaltyFront = EvalPvsPenalty(pvsFront, lowerPvsLimit, upperPvsLimit);
1305        const float penaltyBack = EvalPvsPenalty(pvsBack, lowerPvsLimit, upperPvsLimit);
1306       
1307        const float oldRenderCost = penaltyOld * pOverall;
1308        const float newRenderCost = penaltyFront * pFront + penaltyBack * pBack;
1309
1310        float ratio = mPvsFactor * newRenderCost / (oldRenderCost + Limits::Small);
1311
[480]1312        //Debug << "costRatio=" << ratio << " pos=" << position << " t=" << (position - minBox) / (maxBox - minBox)
1313        //     <<"\t q=(" << queriesBack << "," << queriesFront << ")\t r=(" << raysBack << "," << raysFront << ")" << endl;
1314
1315        return ratio;
[463]1316}
1317
[480]1318
[482]1319float VspBspTree::SelectAxisAlignedPlane(Plane3 &plane,
[491]1320                                                                                 const VspBspTraversalData &tData,
[495]1321                                                                                 int &axis,
[508]1322                                                                                 BspNodeGeometry **frontGeom,
1323                                                                                 BspNodeGeometry **backGeom,
[547]1324                                                                                 float &pFront,
1325                                                                                 float &pBack,
1326                                                                                 const bool useKdSplit)
[463]1327{
[508]1328        float nPosition[3];
1329        float nCostRatio[3];
[547]1330        float nProbFront[3];
1331        float nProbBack[3];
[508]1332
1333        BspNodeGeometry *nFrontGeom[3];
1334        BspNodeGeometry *nBackGeom[3];
1335
[612]1336        for (int i = 0; i < 3; ++ i)
1337        {
1338                nFrontGeom[i] = NULL;
1339                nBackGeom[i] = NULL;
1340        }
1341
[508]1342        int bestAxis = -1;
1343
[545]1344        // create bounding box of node geometry
[463]1345        AxisAlignedBox3 box;
1346        box.Initialize();
[547]1347       
[562]1348        //TODO: for kd split geometry already is box => only take minmax vertices
[551]1349        if (1)
[509]1350        {
[678]1351                PolygonContainer::const_iterator it, it_end = tData.mGeometry->GetPolys().end();
[480]1352
[678]1353                for(it = tData.mGeometry->GetPolys().begin(); it < it_end; ++ it)
[509]1354                        box.Include(*(*it));
1355        }
1356        else
1357        {
1358                RayInfoContainer::const_iterator ri, ri_end = tData.mRays->end();
[480]1359
[509]1360                for(ri = tData.mRays->begin(); ri < ri_end; ++ ri)
1361                        box.Include((*ri).ExtrapTermination());
1362        }
[663]1363
1364        int sAxis = 0;
1365
[664]1366        bool useSpecialAxis = mOnlyDrivingAxis || mUseRandomAxis || mSimulateOctree;
[663]1367
[664]1368        // use some kind of specialised fixed axis
1369        if (mOnlyDrivingAxis)
1370                sAxis = box.Size().DrivingAxis();
[663]1371        else if (mUseRandomAxis)
1372                sAxis = Random(3);
[664]1373        else if (mSimulateOctree)
1374                sAxis = tData.mAxis;
1375               
[670]1376        //Debug << "use special axis: " << useSpecialAxis << endl;
1377        //Debug << "axis: " << sAxis << " drivingaxis: " << box.Size().DrivingAxis();
[663]1378
[495]1379        for (axis = 0; axis < 3; ++ axis)
[480]1380        {
[663]1381                if (!useSpecialAxis || (axis == sAxis))
[463]1382                {
[612]1383                        if (!mUseCostHeuristics)
[480]1384                        {
[612]1385                                nFrontGeom[axis] = new BspNodeGeometry();
1386                                nBackGeom[axis] = new BspNodeGeometry();
1387
[480]1388                                nPosition[axis] = (box.Min()[axis] + box.Max()[axis]) * 0.5f;
[543]1389                                Vector3 normal(0,0,0); normal[axis] = 1.0f;
[547]1390
1391                                // allows faster split because we have axis aligned kd tree boxes
[679]1392                                if (0 && useKdSplit)
[542]1393                                {
1394                                        nCostRatio[axis] = EvalAxisAlignedSplitCost(tData,
1395                                                                                                                                box,
1396                                                                                                                                axis,
[547]1397                                                                                                                                nPosition[axis],
1398                                                                                                                                nProbFront[axis],
1399                                                                                                                                nProbBack[axis]);
[542]1400                                       
[543]1401                                        Vector3 pos;
[542]1402                                       
[543]1403                                        pos = box.Max(); pos[axis] = nPosition[axis];
[547]1404                                        AxisAlignedBox3 bBox(box.Min(), pos);
[678]1405                                        // TODO
1406#if 0
1407                                                bBox.ExtractPolys(nBackGeom[axis]->GetPolys());
1408#endif                                 
[542]1409                                        pos = box.Min(); pos[axis] = nPosition[axis];
[547]1410                                        AxisAlignedBox3 fBox(pos, box.Max());
[678]1411                                        // TODO
1412#if 0
1413                                                fBox.ExtractPolys(nFrontGeom[axis]->GetPolys());
1414#endif
[542]1415                                }
1416                                else
1417                                {
[573]1418                                        nCostRatio[axis] =
1419                                                EvalSplitPlaneCost(Plane3(normal, nPosition[axis]),
1420                                                                                   tData, *nFrontGeom[axis], *nBackGeom[axis],
1421                                                                                   nProbFront[axis], nProbBack[axis]);
[542]1422                                }
[480]1423                        }
[481]1424                        else
1425                        {
[482]1426                                nCostRatio[axis] =
[481]1427                                        BestCostRatioHeuristics(*tData.mRays,
1428                                                                                    box,
1429                                                                                        tData.mPvs,
1430                                                                                        axis,
1431                                                                                        nPosition[axis]);
1432                        }
1433
[480]1434                        if (bestAxis == -1)
1435                        {
1436                                bestAxis = axis;
1437                        }
1438                        else if (nCostRatio[axis] < nCostRatio[bestAxis])
1439                        {
1440                                bestAxis = axis;
1441                        }
1442
[463]1443                }
1444        }
1445
[495]1446        //-- assign values
1447        axis = bestAxis;
[547]1448        pFront = nProbFront[bestAxis];
1449        pBack = nProbBack[bestAxis];
[495]1450
[508]1451        // assign best split nodes geometry
1452        *frontGeom = nFrontGeom[bestAxis];
1453        *backGeom = nBackGeom[bestAxis];
[542]1454
[508]1455        // and delete other geometry
[612]1456        DEL_PTR(nFrontGeom[(bestAxis + 1) % 3]);
1457        DEL_PTR(nBackGeom[(bestAxis + 2) % 3]);
[495]1458
[508]1459        //-- split plane
1460    Vector3 normal(0,0,0); normal[bestAxis] = 1;
[480]1461        plane = Plane3(normal, nPosition[bestAxis]);
[508]1462
[480]1463        return nCostRatio[bestAxis];
[463]1464}
1465
[480]1466
[508]1467bool VspBspTree::SelectPlane(Plane3 &bestPlane,
1468                                                         BspLeaf *leaf,
[652]1469                                                         VspBspTraversalData &data,                                                     
[508]1470                                                         VspBspTraversalData &frontData,
[612]1471                                                         VspBspTraversalData &backData,
1472                                                         int &splitAxis)
[491]1473{
[508]1474        // simplest strategy: just take next polygon
1475        if (mSplitPlaneStrategy & RANDOM_POLYGON)
[491]1476        {
[508]1477        if (!data.mPolygons->empty())
1478                {
1479                        const int randIdx =
1480                                (int)RandomValue(0, (Real)((int)data.mPolygons->size() - 1));
1481                        Polygon3 *nextPoly = (*data.mPolygons)[randIdx];
[491]1482
[508]1483                        bestPlane = nextPoly->GetSupportingPlane();
1484                        return true;
1485                }
[491]1486        }
1487
[508]1488        //-- use heuristics to find appropriate plane
[491]1489
[508]1490        // intermediate plane
1491        Plane3 plane;
1492        float lowestCost = MAX_FLOAT;
[517]1493       
1494        // decides if the first few splits should be only axisAligned
[508]1495        const bool onlyAxisAligned  =
1496                (mSplitPlaneStrategy & AXIS_ALIGNED) &&
1497                ((int)data.mRays->size() > mTermMinRaysForAxisAligned) &&
1498                ((int)data.GetAvgRayContribution() < mTermMaxRayContriForAxisAligned);
1499       
1500        const int limit = onlyAxisAligned ? 0 :
1501                Min((int)data.mPolygons->size(), mMaxPolyCandidates);
[491]1502
[508]1503        float candidateCost;
[491]1504
[508]1505        int maxIdx = (int)data.mPolygons->size();
[491]1506
[508]1507        for (int i = 0; i < limit; ++ i)
[491]1508        {
[562]1509                // the already taken candidates are stored behind maxIdx
1510                // => assure that no index is taken twice
[508]1511                const int candidateIdx = (int)RandomValue(0, (Real)(-- maxIdx));
1512                Polygon3 *poly = (*data.mPolygons)[candidateIdx];
[491]1513
[508]1514                // swap candidate to the end to avoid testing same plane
1515                std::swap((*data.mPolygons)[maxIdx], (*data.mPolygons)[candidateIdx]);
1516                //Polygon3 *poly = (*data.mPolygons)[(int)RandomValue(0, (int)polys.size() - 1)];
[491]1517
[508]1518                // evaluate current candidate
1519                BspNodeGeometry fGeom, bGeom;
1520                float fArea, bArea;
1521                plane = poly->GetSupportingPlane();
[573]1522                candidateCost = EvalSplitPlaneCost(plane, data, fGeom, bGeom, fArea, bArea);
[491]1523               
[508]1524                if (candidateCost < lowestCost)
[491]1525                {
[508]1526                        bestPlane = plane;
1527                        lowestCost = candidateCost;
[491]1528                }
1529        }
1530
[508]1531        //-- evaluate axis aligned splits
1532        int axis;
1533        BspNodeGeometry *fGeom, *bGeom;
[547]1534        float pFront, pBack;
[491]1535
[653]1536        candidateCost = 99999999.0f;
[491]1537
[653]1538        // option: axis aligned split only if no polygon available
1539        if (!mUsePolygonSplitIfAvailable || data.mPolygons->empty())
1540        {
1541                candidateCost = SelectAxisAlignedPlane(plane,
1542                                                                                           data,
1543                                                                                           axis,
1544                                                                                           &fGeom,
1545                                                                                           &bGeom,
1546                                                                                           pFront,
1547                                                                                           pBack,
1548                                                                                           data.mIsKdNode);     
1549        }
1550
[612]1551        splitAxis = 3;
[562]1552
[508]1553        if (candidateCost < lowestCost)
1554        {       
1555                bestPlane = plane;
1556                lowestCost = candidateCost;
[612]1557                splitAxis = axis;
[653]1558       
[542]1559                // assign already computed values
1560                // we can do this because we always save the
[562]1561                // computed values from the axis aligned splits         
[653]1562
[612]1563                if (fGeom && bGeom)
1564                {
1565                        frontData.mGeometry = fGeom;
1566                        backData.mGeometry = bGeom;
[547]1567       
[612]1568                        frontData.mProbability = pFront;
1569                        backData.mProbability = pBack;
1570                }
[508]1571        }
1572        else
[463]1573        {
[508]1574                DEL_PTR(fGeom);
1575                DEL_PTR(bGeom);
[463]1576        }
[678]1577   
1578
[679]1579//      if (lowestCost > 10)
1580//              Debug << "warning!! lowest cost: " << lowestCost << endl;
[653]1581       
[679]1582#ifdef _DEBUG
[508]1583        Debug << "plane lowest cost: " << lowestCost << endl;
[679]1584#endif
[508]1585
1586        if (lowestCost > mTermMaxCostRatio)
[611]1587        {
[508]1588                return false;
[611]1589        }
[508]1590
1591        return true;
[463]1592}
1593
[480]1594
[473]1595Plane3 VspBspTree::ChooseCandidatePlane(const RayInfoContainer &rays) const
[482]1596{
[473]1597        const int candidateIdx = (int)RandomValue(0, (Real)((int)rays.size() - 1));
[482]1598
[473]1599        const Vector3 minPt = rays[candidateIdx].ExtrapOrigin();
1600        const Vector3 maxPt = rays[candidateIdx].ExtrapTermination();
1601
1602        const Vector3 pt = (maxPt + minPt) * 0.5;
1603        const Vector3 normal = Normalize(rays[candidateIdx].mRay->GetDir());
1604
1605        return Plane3(normal, pt);
1606}
1607
[480]1608
[473]1609Plane3 VspBspTree::ChooseCandidatePlane2(const RayInfoContainer &rays) const
[482]1610{
[473]1611        Vector3 pt[3];
[482]1612
[473]1613        int idx[3];
1614        int cmaxT = 0;
1615        int cminT = 0;
1616        bool chooseMin = false;
1617
1618        for (int j = 0; j < 3; ++ j)
1619        {
1620                idx[j] = (int)RandomValue(0, (Real)((int)rays.size() * 2 - 1));
[482]1621
[473]1622                if (idx[j] >= (int)rays.size())
1623                {
1624                        idx[j] -= (int)rays.size();
[482]1625
[473]1626                        chooseMin = (cminT < 2);
1627                }
1628                else
1629                        chooseMin = (cmaxT < 2);
1630
1631                RayInfo rayInf = rays[idx[j]];
1632                pt[j] = chooseMin ? rayInf.ExtrapOrigin() : rayInf.ExtrapTermination();
[482]1633        }
[473]1634
1635        return Plane3(pt[0], pt[1], pt[2]);
1636}
1637
[580]1638
[473]1639Plane3 VspBspTree::ChooseCandidatePlane3(const RayInfoContainer &rays) const
[482]1640{
[473]1641        Vector3 pt[3];
[482]1642
[473]1643        int idx1 = (int)RandomValue(0, (Real)((int)rays.size() - 1));
1644        int idx2 = (int)RandomValue(0, (Real)((int)rays.size() - 1));
1645
1646        // check if rays different
1647        if (idx1 == idx2)
1648                idx2 = (idx2 + 1) % (int)rays.size();
1649
1650        const RayInfo ray1 = rays[idx1];
1651        const RayInfo ray2 = rays[idx2];
1652
1653        // normal vector of the plane parallel to both lines
1654        const Vector3 norm = Normalize(CrossProd(ray1.mRay->GetDir(), ray2.mRay->GetDir()));
1655
1656        // vector from line 1 to line 2
[479]1657        const Vector3 vd = ray2.ExtrapOrigin() - ray1.ExtrapOrigin();
[482]1658
[473]1659        // project vector on normal to get distance
1660        const float dist = DotProd(vd, norm);
1661
1662        // point on plane lies halfway between the two planes
1663        const Vector3 planePt = ray1.ExtrapOrigin() + norm * dist * 0.5;
1664
1665        return Plane3(norm, planePt);
1666}
1667
[495]1668
[463]1669inline void VspBspTree::GenerateUniqueIdsForPvs()
1670{
[580]1671        Intersectable::NewMail(); sBackId = Intersectable::sMailId;
1672        Intersectable::NewMail(); sFrontId = Intersectable::sMailId;
1673        Intersectable::NewMail(); sFrontAndBackId = Intersectable::sMailId;
[463]1674}
1675
[495]1676
[652]1677float VspBspTree::EvalRenderCostDecrease(const Plane3 &candidatePlane,
1678                                                                                 const VspBspTraversalData &data) const
1679{
1680        int pvsFront = 0;
1681        int pvsBack = 0;
[654]1682        int totalPvs = 0;
[652]1683
1684        // probability that view point lies in back / front node
1685        float pOverall = data.mProbability;
1686        float pFront = 0;
1687        float pBack = 0;
1688
1689
1690        // create unique ids for pvs heuristics
1691        GenerateUniqueIdsForPvs();
1692       
1693        for (int i = 0; i < data.mRays->size(); ++ i)
1694        {
1695                RayInfo rayInf = (*data.mRays)[i];
1696
1697                float t;
1698                VssRay *ray = rayInf.mRay;
1699                const int cf = rayInf.ComputeRayIntersection(candidatePlane, t);
1700
1701                // find front and back pvs for origing and termination object
1702                AddObjToPvs(ray->mTerminationObject, cf, pvsFront, pvsBack, totalPvs);
1703                AddObjToPvs(ray->mOriginObject, cf, pvsFront, pvsBack, totalPvs);
1704        }
1705
1706
1707        BspNodeGeometry geomFront;
1708        BspNodeGeometry geomBack;
1709
1710        // construct child geometry with regard to the candidate split plane
1711        data.mGeometry->SplitGeometry(geomFront,
1712                                                                  geomBack,
1713                                                                  candidatePlane,
1714                                                                  mBox,
[679]1715                                                                  //0.0f);
1716                                                                  mEpsilon);
[652]1717
1718        if (!mUseAreaForPvs) // use front and back cell areas to approximate volume
1719        {
1720                pFront = geomFront.GetVolume();
1721                pBack = pOverall - pFront;
[675]1722
[679]1723                if ((pFront < 0.0) || (pBack < 0.0))
[676]1724                {
1725                        Debug << "vol f " << pFront << " b " << pBack << " p " << pOverall << endl;
1726                        Debug << "real vol f " << pFront << " b " << geomBack.GetVolume() << " p " << pOverall << endl;
[678]1727                        Debug << "polys f " << geomFront.Size() << " b " << geomBack.Size() << " data " << data.mGeometry->Size() << endl;
[676]1728                }
1729
[675]1730                // clamp because of possible precision issues
[676]1731                if (0)
1732                {
1733                        if (pFront < 0) pFront = 0;
1734                        if (pBack < 0) pBack = 0;
1735                }
[652]1736        }
1737        else
1738        {
1739                pFront = geomFront.GetArea();
1740                pBack = geomBack.GetArea();
1741        }
1742       
1743
1744        // -- pvs rendering heuristics
1745        const int lowerPvsLimit = mViewCellsManager->GetMinPvsSize();
1746        const int upperPvsLimit = mViewCellsManager->GetMaxPvsSize();
1747
1748        // only render cost heuristics or combined with standard deviation
1749        const float penaltyOld = EvalPvsPenalty(totalPvs, lowerPvsLimit, upperPvsLimit);
1750    const float penaltyFront = EvalPvsPenalty(pvsFront, lowerPvsLimit, upperPvsLimit);
1751        const float penaltyBack = EvalPvsPenalty(pvsBack, lowerPvsLimit, upperPvsLimit);
1752                       
1753        const float oldRenderCost = pOverall * penaltyOld;
1754        const float newRenderCost = penaltyFront * pFront + penaltyBack * pBack;
1755
[654]1756        //Debug << "decrease: " << oldRenderCost - newRenderCost << endl;
1757        return (oldRenderCost - newRenderCost) / mBox.GetVolume();
[652]1758}
1759
1760
[573]1761float VspBspTree::EvalSplitPlaneCost(const Plane3 &candidatePlane,
1762                                                                         const VspBspTraversalData &data,
1763                                                                         BspNodeGeometry &geomFront,
1764                                                                         BspNodeGeometry &geomBack,
1765                                                                         float &pFront,
1766                                                                         float &pBack) const
[463]1767{
[472]1768        float cost = 0;
[463]1769
[652]1770        int totalPvs = 0;
[508]1771        int pvsFront = 0;
1772        int pvsBack = 0;
[652]1773       
[508]1774        // probability that view point lies in back / front node
[463]1775        float pOverall = 0;
[547]1776        pFront = 0;
1777        pBack = 0;
[463]1778
[508]1779
[463]1780        int limit;
1781        bool useRand;
1782
[652]1783        // create unique ids for pvs heuristics
1784        GenerateUniqueIdsForPvs();
1785
[491]1786        // choose test rays randomly if too much
[463]1787        if ((int)data.mRays->size() > mMaxTests)
1788        {
1789                useRand = true;
1790                limit = mMaxTests;
1791        }
1792        else
1793        {
1794                useRand = false;
1795                limit = (int)data.mRays->size();
1796        }
[508]1797       
[463]1798        for (int i = 0; i < limit; ++ i)
1799        {
[508]1800                const int testIdx = useRand ?
1801                        (int)RandomValue(0, (Real)((int)data.mRays->size() - 1)) : i;
[463]1802                RayInfo rayInf = (*data.mRays)[testIdx];
1803
1804                float t;
[508]1805                VssRay *ray = rayInf.mRay;
[463]1806                const int cf = rayInf.ComputeRayIntersection(candidatePlane, t);
1807
[652]1808                // find front and back pvs for origing and termination object
1809                AddObjToPvs(ray->mTerminationObject, cf, pvsFront, pvsBack, totalPvs);
1810                AddObjToPvs(ray->mOriginObject, cf, pvsFront, pvsBack, totalPvs);
1811        }
[508]1812
[652]1813        // construct child geometry with regard to the candidate split plane
[679]1814        bool splitSuccessFull = data.mGeometry->SplitGeometry(geomFront,
1815                                                                                                                  geomBack,
1816                                                                                                                  candidatePlane,
1817                                                                                                                  mBox,
1818                                                                                                                  //0.0f);
1819                                                                                                                  mEpsilon);
[675]1820
[652]1821        pOverall = data.mProbability;
[463]1822
[652]1823        if (!mUseAreaForPvs) // use front and back cell areas to approximate volume
1824        {
1825                pFront = geomFront.GetVolume();
1826                pBack = pOverall - pFront;
[675]1827               
1828                // clamp because of possible precision issues
[685]1829                if (1 &&
[682]1830                        (!splitSuccessFull || (pFront <= 0) || (pBack <= 0) ||
1831                        !geomFront.Valid() || !geomBack.Valid()))
[676]1832                {
[682]1833                        Debug << "error f: " << pFront << " b: " << pBack << endl;
1834                        return 999;
[676]1835                }
[463]1836        }
[652]1837        else
[542]1838        {
[652]1839                pFront = geomFront.GetArea();
1840                pBack = geomBack.GetArea();
[542]1841        }
[652]1842       
[542]1843
[580]1844        // -- pvs rendering heuristics
[652]1845        const int lowerPvsLimit = mViewCellsManager->GetMinPvsSize();
1846        const int upperPvsLimit = mViewCellsManager->GetMaxPvsSize();
[580]1847
[652]1848        // only render cost heuristics or combined with standard deviation
1849        const float penaltyOld = EvalPvsPenalty(totalPvs, lowerPvsLimit, upperPvsLimit);
1850    const float penaltyFront = EvalPvsPenalty(pvsFront, lowerPvsLimit, upperPvsLimit);
1851        const float penaltyBack = EvalPvsPenalty(pvsBack, lowerPvsLimit, upperPvsLimit);
[579]1852                       
[652]1853        const float oldRenderCost = pOverall * penaltyOld;
1854        const float newRenderCost = penaltyFront * pFront + penaltyBack * pBack;
[579]1855
[652]1856        float oldCost, newCost;
[580]1857
[652]1858        // only render cost
1859        if (1)
1860        {
1861                oldCost = oldRenderCost;
1862                newCost = newRenderCost;
1863        }
1864        else // also considering standard deviation
1865        {
1866                // standard deviation is difference of back and front pvs
1867                const float expectedCost = 0.5f * (penaltyFront + penaltyBack);
[580]1868
[652]1869                const float newDeviation = 0.5f *
1870                        fabs(penaltyFront - expectedCost) + fabs(penaltyBack - expectedCost);
[580]1871
[652]1872                const float oldDeviation = penaltyOld;
[580]1873
[652]1874                newCost = mRenderCostWeight * newRenderCost + (1.0f - mRenderCostWeight) * newDeviation;
1875                oldCost = mRenderCostWeight * oldRenderCost + (1.0f - mRenderCostWeight) * oldDeviation;
1876        }
[580]1877
[652]1878        cost += mPvsFactor * newCost / (oldCost + Limits::Small);
[607]1879               
[463]1880
1881#ifdef _DEBUG
[474]1882        Debug << "totalpvs: " << data.mPvs << " ptotal: " << pOverall
[508]1883                  << " frontpvs: " << pvsFront << " pFront: " << pFront
1884                  << " backpvs: " << pvsBack << " pBack: " << pBack << endl << endl;
[600]1885        Debug << "cost: " << cost << endl;
[463]1886#endif
[482]1887
[652]1888        return cost;
[463]1889}
1890
[508]1891
[697]1892int VspBspTree::ComputeBoxIntersections(const AxisAlignedBox3 &box,
1893                                                                                ViewCellContainer &viewCells) const
1894{
1895        stack<bspNodePair> nodeStack;
1896        BspNodeGeometry *rgeom = new BspNodeGeometry();
1897
1898        ConstructGeometry(mRoot, *rgeom);
1899
1900        nodeStack.push(bspNodePair(mRoot, rgeom));
1901 
1902        ViewCell::NewMail();
1903
1904        while (!nodeStack.empty())
1905        {
1906                BspNode *node = nodeStack.top().first;
1907                BspNodeGeometry *geom = nodeStack.top().second;
1908                nodeStack.pop();
1909
1910                const int side = geom->ComputeIntersection(box);
1911               
1912                switch (side)
1913                {
1914                case -1:
1915                        // node geometry is contained in box
1916                        CollectViewCells(node, true, viewCells, true);
1917                        break;
1918
1919                case 0:
1920                        if (node->IsLeaf())
1921                        {
1922                                BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
1923                       
1924                                if (!leaf->GetViewCell()->Mailed() && leaf->TreeValid())
1925                                {
1926                                        leaf->GetViewCell()->Mail();
1927                                        viewCells.push_back(leaf->GetViewCell());
1928                                }
1929                        }
1930                        else
1931                        {
1932                                BspInterior *interior = dynamic_cast<BspInterior *>(node);
1933                       
1934                                BspNode *first = interior->GetFront();
1935                                BspNode *second = interior->GetBack();
1936           
1937                                BspNodeGeometry *firstGeom = new BspNodeGeometry();
1938                                BspNodeGeometry *secondGeom = new BspNodeGeometry();
1939
1940                                geom->SplitGeometry(*firstGeom,
1941                                                                        *secondGeom,
1942                                                                        interior->GetPlane(),
1943                                                                        mBox,
1944                                                                        //0.0000001f);
1945                                                                        mEpsilon);
1946
1947                                nodeStack.push(bspNodePair(first, firstGeom));
1948                                nodeStack.push(bspNodePair(second, secondGeom));
1949                        }
1950                       
1951                        break;
1952                default:
1953                        // default: cull
1954                        break;
1955                }
1956               
1957                DEL_PTR(geom);
1958               
1959        }
1960
1961        return (int)viewCells.size();
1962}
1963
1964
[580]1965float VspBspTree::EvalAxisAlignedSplitCost(const VspBspTraversalData &data,
1966                                                                                   const AxisAlignedBox3 &box,
1967                                                                                   const int axis,
1968                                                                                   const float &position,                                                                                 
1969                                                                                   float &pFront,
1970                                                                                   float &pBack) const
1971{
1972        int pvsTotal = 0;
1973        int pvsFront = 0;
1974        int pvsBack = 0;
1975       
1976        // create unique ids for pvs heuristics
1977        GenerateUniqueIdsForPvs();
1978
1979        const int pvsSize = data.mPvs;
1980
1981        RayInfoContainer::const_iterator rit, rit_end = data.mRays->end();
1982
1983        // this is the main ray classification loop!
1984        for(rit = data.mRays->begin(); rit != rit_end; ++ rit)
1985        {
1986                //if (!(*rit).mRay->IsActive()) continue;
1987
1988                // determine the side of this ray with respect to the plane
1989                float t;
1990                const int side = (*rit).ComputeRayIntersection(axis, position, t);
1991       
1992                AddObjToPvs((*rit).mRay->mTerminationObject, side, pvsFront, pvsBack, pvsTotal);
1993                AddObjToPvs((*rit).mRay->mOriginObject, side, pvsFront, pvsBack, pvsTotal);
1994        }
1995
1996        //-- pvs heuristics
1997        float pOverall;
1998
1999        //-- compute heurstics
2000        //   we take simplified computation for mid split
2001               
2002        pOverall = data.mProbability;
2003
2004        if (!mUseAreaForPvs)
2005        {   // volume
2006                pBack = pFront = pOverall * 0.5f;
2007               
2008#if 0
2009                // box length substitute for probability
2010                const float minBox = box.Min(axis);
2011                const float maxBox = box.Max(axis);
2012
2013                pBack = position - minBox;
2014                pFront = maxBox - position;
2015                pOverall = maxBox - minBox;
2016#endif
2017        }
2018        else //-- area substitute for probability
2019        {
2020                const int axis2 = (axis + 1) % 3;
2021                const int axis3 = (axis + 2) % 3;
2022
2023                const float faceArea =
2024                        (box.Max(axis2) - box.Min(axis2)) *
2025                        (box.Max(axis3) - box.Min(axis3));
2026
2027                pBack = pFront = pOverall * 0.5f + faceArea;
2028        }
2029
2030#ifdef _DEBUG
2031        Debug << axis << " " << pvsSize << " " << pvsBack << " " << pvsFront << endl;
2032        Debug << pFront << " " << pBack << " " << pOverall << endl;
2033#endif
2034
2035       
2036        const float newCost = pvsBack * pBack + pvsFront * pFront;
2037        const float oldCost = (float)pvsSize * pOverall + Limits::Small;
2038
2039        return  (mCtDivCi + newCost) / oldCost;
2040}
2041
2042
[463]2043void VspBspTree::AddObjToPvs(Intersectable *obj,
2044                                                         const int cf,
2045                                                         int &frontPvs,
[508]2046                                                         int &backPvs,
2047                                                         int &totalPvs) const
[463]2048{
2049        if (!obj)
2050                return;
[654]2051        // new object
[508]2052        if ((obj->mMailbox != sFrontId) &&
2053                (obj->mMailbox != sBackId) &&
2054                (obj->mMailbox != sFrontAndBackId))
2055        {
2056                ++ totalPvs;
2057        }
2058
[463]2059        // TODO: does this really belong to no pvs?
2060        //if (cf == Ray::COINCIDENT) return;
2061
2062        // object belongs to both PVS
2063        if (cf >= 0)
2064        {
[482]2065                if ((obj->mMailbox != sFrontId) &&
[463]2066                        (obj->mMailbox != sFrontAndBackId))
2067                {
2068                        ++ frontPvs;
[508]2069               
[463]2070                        if (obj->mMailbox == sBackId)
[482]2071                                obj->mMailbox = sFrontAndBackId;
[463]2072                        else
[482]2073                                obj->mMailbox = sFrontId;
[463]2074                }
2075        }
[482]2076
[463]2077        if (cf <= 0)
2078        {
2079                if ((obj->mMailbox != sBackId) &&
2080                        (obj->mMailbox != sFrontAndBackId))
2081                {
2082                        ++ backPvs;
[508]2083               
[463]2084                        if (obj->mMailbox == sFrontId)
[482]2085                                obj->mMailbox = sFrontAndBackId;
[463]2086                        else
[482]2087                                obj->mMailbox = sBackId;
[463]2088                }
2089        }
2090}
2091
[491]2092
[503]2093void VspBspTree::CollectLeaves(vector<BspLeaf *> &leaves,
2094                                                           const bool onlyUnmailed,
2095                                                           const int maxPvsSize) const
[463]2096{
2097        stack<BspNode *> nodeStack;
2098        nodeStack.push(mRoot);
[482]2099
2100        while (!nodeStack.empty())
[463]2101        {
2102                BspNode *node = nodeStack.top();
2103                nodeStack.pop();
[489]2104               
[482]2105                if (node->IsLeaf())
[463]2106                {
[490]2107                        // test if this leaf is in valid view space
[503]2108                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
2109                        if (leaf->TreeValid() &&
[508]2110                                (!onlyUnmailed || !leaf->Mailed()) &&
[503]2111                                ((maxPvsSize < 0) || (leaf->GetViewCell()->GetPvs().GetSize() <= maxPvsSize)))
[490]2112                        {
2113                                leaves.push_back(leaf);
2114                        }
[482]2115                }
2116                else
[463]2117                {
2118                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2119
2120                        nodeStack.push(interior->GetBack());
2121                        nodeStack.push(interior->GetFront());
2122                }
2123        }
2124}
2125
[489]2126
[463]2127AxisAlignedBox3 VspBspTree::GetBoundingBox() const
2128{
2129        return mBox;
2130}
2131
[489]2132
[463]2133BspNode *VspBspTree::GetRoot() const
2134{
2135        return mRoot;
2136}
2137
[489]2138
[463]2139void VspBspTree::EvaluateLeafStats(const VspBspTraversalData &data)
2140{
2141        // the node became a leaf -> evaluate stats for leafs
2142        BspLeaf *leaf = dynamic_cast<BspLeaf *>(data.mNode);
2143
2144        // store maximal and minimal depth
[574]2145        if (data.mDepth > mBspStats.maxDepth)
2146                mBspStats.maxDepth = data.mDepth;
[463]2147
[574]2148        if (data.mPvs > mBspStats.maxPvs)
2149                mBspStats.maxPvs = data.mPvs;
[508]2150       
[656]2151        mBspStats.pvs += data.mPvs;
2152
[574]2153        if (data.mDepth < mBspStats.minDepth)
2154                mBspStats.minDepth = data.mDepth;
[656]2155       
[463]2156        if (data.mDepth >= mTermMaxDepth)
[574]2157                ++ mBspStats.maxDepthNodes;
[611]2158
[508]2159        // accumulate rays to compute rays /  leaf
[574]2160        mBspStats.accumRays += (int)data.mRays->size();
[463]2161
[437]2162        if (data.mPvs < mTermMinPvs)
[574]2163                ++ mBspStats.minPvsNodes;
[437]2164
2165        if ((int)data.mRays->size() < mTermMinRays)
[574]2166                ++ mBspStats.minRaysNodes;
[437]2167
2168        if (data.GetAvgRayContribution() > mTermMaxRayContribution)
[574]2169                ++ mBspStats.maxRayContribNodes;
[482]2170
[547]2171        if (data.mProbability <= mTermMinProbability)
[574]2172                ++ mBspStats.minProbabilityNodes;
[508]2173       
[474]2174        // accumulate depth to compute average depth
[574]2175        mBspStats.accumDepth += data.mDepth;
[463]2176
[612]2177        ++ mCreatedViewCells;
[656]2178
[463]2179#ifdef _DEBUG
2180        Debug << "BSP stats: "
2181                  << "Depth: " << data.mDepth << " (max: " << mTermMaxDepth << "), "
2182                  << "PVS: " << data.mPvs << " (min: " << mTermMinPvs << "), "
[587]2183          //              << "Area: " << data.mProbability << " (min: " << mTermMinProbability << "), "
[482]2184                  << "#rays: " << (int)data.mRays->size() << " (max: " << mTermMinRays << "), "
[463]2185                  << "#pvs: " << leaf->GetViewCell()->GetPvs().GetSize() << "=, "
2186                  << "#avg ray contrib (pvs): " << (float)data.mPvs / (float)data.mRays->size() << endl;
2187#endif
2188}
2189
[612]2190
[463]2191int VspBspTree::CastRay(Ray &ray)
2192{
2193        int hits = 0;
[482]2194
[600]2195        stack<BspRayTraversalData> tQueue;
[482]2196
[463]2197        float maxt, mint;
2198
2199        if (!mBox.GetRaySegment(ray, mint, maxt))
2200                return 0;
2201
2202        Intersectable::NewMail();
[600]2203        ViewCell::NewMail();
[463]2204        Vector3 entp = ray.Extrap(mint);
2205        Vector3 extp = ray.Extrap(maxt);
[482]2206
[463]2207        BspNode *node = mRoot;
2208        BspNode *farChild = NULL;
[482]2209
[463]2210        while (1)
2211        {
[482]2212                if (!node->IsLeaf())
[463]2213                {
2214                        BspInterior *in = dynamic_cast<BspInterior *>(node);
2215
2216                        Plane3 splitPlane = in->GetPlane();
2217                        const int entSide = splitPlane.Side(entp);
2218                        const int extSide = splitPlane.Side(extp);
2219
2220                        if (entSide < 0)
2221                        {
2222                                node = in->GetBack();
2223
2224                                if(extSide <= 0) // plane does not split ray => no far child
2225                                        continue;
[482]2226
[463]2227                                farChild = in->GetFront(); // plane splits ray
2228
2229                        } else if (entSide > 0)
2230                        {
2231                                node = in->GetFront();
2232
2233                                if (extSide >= 0) // plane does not split ray => no far child
2234                                        continue;
2235
[482]2236                                farChild = in->GetBack(); // plane splits ray
[463]2237                        }
2238                        else // ray and plane are coincident
2239                        {
2240                                // WHAT TO DO IN THIS CASE ?
2241                                //break;
2242                                node = in->GetFront();
2243                                continue;
2244                        }
2245
2246                        // push data for far child
[600]2247                        tQueue.push(BspRayTraversalData(farChild, extp, maxt));
[463]2248
2249                        // find intersection of ray segment with plane
2250                        float t;
2251                        extp = splitPlane.FindIntersection(ray.GetLoc(), extp, &t);
2252                        maxt *= t;
[482]2253
[463]2254                } else // reached leaf => intersection with view cell
2255                {
2256                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
[482]2257
[463]2258                        if (!leaf->GetViewCell()->Mailed())
2259                        {
2260                                //ray.bspIntersections.push_back(Ray::VspBspIntersection(maxt, leaf));
2261                                leaf->GetViewCell()->Mail();
2262                                ++ hits;
2263                        }
[482]2264
[463]2265                        //-- fetch the next far child from the stack
[600]2266                        if (tQueue.empty())
[463]2267                                break;
[482]2268
[463]2269                        entp = extp;
2270                        mint = maxt; // NOTE: need this?
2271
2272                        if (ray.GetType() == Ray::LINE_SEGMENT && mint > 1.0f)
2273                                break;
2274
[600]2275                        BspRayTraversalData &s = tQueue.top();
[463]2276
2277                        node = s.mNode;
2278                        extp = s.mExitPoint;
2279                        maxt = s.mMaxT;
2280
[600]2281                        tQueue.pop();
[463]2282                }
2283        }
2284
2285        return hits;
2286}
2287
[532]2288
[547]2289void VspBspTree::CollectViewCells(ViewCellContainer &viewCells, bool onlyValid) const
[463]2290{
[532]2291        ViewCell::NewMail();
[551]2292       
2293        CollectViewCells(mRoot, onlyValid, viewCells, true);
[532]2294}
2295
2296
[574]2297void VspBspTree::CollapseViewCells()
[542]2298{
[590]2299// TODO
2300#if VC_HISTORY
[542]2301        stack<BspNode *> nodeStack;
2302
2303        if (!mRoot)
2304                return;
2305
2306        nodeStack.push(mRoot);
2307       
2308        while (!nodeStack.empty())
2309        {
2310                BspNode *node = nodeStack.top();
2311                nodeStack.pop();
2312               
2313                if (node->IsLeaf())
[574]2314        {
2315                        BspViewCell *viewCell = dynamic_cast<BspLeaf *>(node)->GetViewCell();
[542]2316
[574]2317                        if (!viewCell->GetValid())
[542]2318                        {
2319                                BspViewCell *viewCell = dynamic_cast<BspLeaf *>(node)->GetViewCell();
[580]2320       
2321                                ViewCellContainer leaves;
[590]2322                                mViewCellsTree->CollectLeaves(viewCell, leaves);
[580]2323
2324                                ViewCellContainer::const_iterator it, it_end = leaves.end();
2325
2326                                for (it = leaves.begin(); it != it_end; ++ it)
[542]2327                                {
[580]2328                                        BspLeaf *l = dynamic_cast<BspViewCell *>(*it)->mLeaf;
[574]2329                                        l->SetViewCell(GetOrCreateOutOfBoundsCell());
2330                                        ++ mBspStats.invalidLeaves;
2331                                }
[542]2332
[574]2333                                // add to unbounded view cell
2334                                GetOrCreateOutOfBoundsCell()->GetPvs().AddPvs(viewCell->GetPvs());
2335                                DEL_PTR(viewCell);
2336                        }
2337                }
2338                else
2339                {
2340                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2341               
2342                        nodeStack.push(interior->GetFront());
2343                        nodeStack.push(interior->GetBack());
2344                }
2345        }
[542]2346
[574]2347        Debug << "invalid leaves: " << mBspStats.invalidLeaves << endl;
[590]2348#endif
[574]2349}
2350
2351
[639]2352void VspBspTree::CollectRays(VssRayContainer &rays)
2353{
2354        vector<BspLeaf *> leaves;
2355
2356        vector<BspLeaf *>::const_iterator lit, lit_end = leaves.end();
2357
2358        for (lit = leaves.begin(); lit != lit_end; ++ lit)
2359        {
2360                BspLeaf *leaf = *lit;
2361                VssRayContainer::const_iterator rit, rit_end = leaf->mVssRays.end();
2362
2363                for (rit = leaf->mVssRays.begin(); rit != rit_end; ++ rit)
2364                        rays.push_back(*rit);
2365        }
2366}
2367
2368
[574]2369void VspBspTree::ValidateTree()
2370{
2371        stack<BspNode *> nodeStack;
2372
2373        if (!mRoot)
2374                return;
2375
2376        nodeStack.push(mRoot);
2377       
2378        mBspStats.invalidLeaves = 0;
2379        while (!nodeStack.empty())
2380        {
2381                BspNode *node = nodeStack.top();
2382                nodeStack.pop();
2383               
2384                if (node->IsLeaf())
2385                {
2386                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
2387
2388                        if (!leaf->GetViewCell()->GetValid())
2389                                ++ mBspStats.invalidLeaves;
2390
2391                        // validity flags don't match => repair
2392                        if (leaf->GetViewCell()->GetValid() != leaf->TreeValid())
2393                        {
2394                                leaf->SetTreeValid(leaf->GetViewCell()->GetValid());
2395                                PropagateUpValidity(leaf);
[542]2396                        }
2397                }
2398                else
2399                {
2400                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2401               
2402                        nodeStack.push(interior->GetFront());
2403                        nodeStack.push(interior->GetBack());
2404                }
2405        }
[562]2406
[574]2407        Debug << "invalid leaves: " << mBspStats.invalidLeaves << endl;
[542]2408}
2409
[547]2410
[574]2411
[547]2412void VspBspTree::CollectViewCells(BspNode *root,
2413                                                                  bool onlyValid,
[532]2414                                                                  ViewCellContainer &viewCells,
2415                                                                  bool onlyUnmailed) const
2416{
[498]2417        stack<BspNode *> nodeStack;
[463]2418
[538]2419        if (!root)
[508]2420                return;
[463]2421
[538]2422        nodeStack.push(root);
[498]2423       
2424        while (!nodeStack.empty())
2425        {
2426                BspNode *node = nodeStack.top();
2427                nodeStack.pop();
2428               
2429                if (node->IsLeaf())
2430                {
[564]2431                        if (!onlyValid || node->TreeValid())
[498]2432                        {
[590]2433                                ViewCell *viewCell =
2434                                        mViewCellsTree->GetActiveViewCell(dynamic_cast<BspLeaf *>(node)->GetViewCell());
2435                                               
[532]2436                                if (!onlyUnmailed || !viewCell->Mailed())
[498]2437                                {
2438                                        viewCell->Mail();
2439                                        viewCells.push_back(viewCell);
2440                                }
2441                        }
2442                }
2443                else
2444                {
2445                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
[508]2446               
[498]2447                        nodeStack.push(interior->GetFront());
2448                        nodeStack.push(interior->GetBack());
2449                }
2450        }
[590]2451
[463]2452}
2453
2454
[648]2455void VspBspTree::PreprocessPolygons(PolygonContainer &polys)
2456{
2457        // preprocess: throw out polygons coincident to the view space box (not needed)
2458        PolygonContainer boxPolys;
2459        mBox.ExtractPolys(boxPolys);
2460        vector<Plane3> boxPlanes;
2461
2462        PolygonContainer::iterator pit, pit_end = boxPolys.end();
2463
2464        // extract planes of box
2465        // TODO: can be done more elegantly than first extracting polygons
2466        // and take their planes
2467        for (pit = boxPolys.begin(); pit != pit_end; ++ pit)
2468        {
2469                boxPlanes.push_back((*pit)->GetSupportingPlane());
2470        }
2471
2472        pit_end = polys.end();
2473
2474        for (pit = polys.begin(); pit != pit_end; ++ pit)
2475        {
2476                vector<Plane3>::const_iterator bit, bit_end = boxPlanes.end();
2477               
2478                for (bit = boxPlanes.begin(); (bit != bit_end) && (*pit); ++ bit)
2479                {
2480                        const int cf = (*pit)->ClassifyPlane(*bit, mEpsilon);
2481
2482                        if (cf == Polygon3::COINCIDENT)
2483                        {
2484                                DEL_PTR(*pit);
2485                                //Debug << "coincident!!" << endl;
2486                        }
2487                }
2488        }
2489
2490        // remove deleted entries
2491        for (int i = 0; i < (int)polys.size(); ++ i)
2492        {
2493                while (!polys[i] && (i < (int)polys.size()))
2494                {
2495                        swap(polys[i], polys.back());
2496                        polys.pop_back();
2497                }
2498        }
2499}
2500
2501
[463]2502float VspBspTree::AccumulatedRayLength(const RayInfoContainer &rays) const
2503{
2504        float len = 0;
2505
2506        RayInfoContainer::const_iterator it, it_end = rays.end();
2507
2508        for (it = rays.begin(); it != it_end; ++ it)
2509                len += (*it).SegmentLength();
2510
2511        return len;
2512}
2513
[479]2514
[463]2515int VspBspTree::SplitRays(const Plane3 &plane,
[482]2516                                                  RayInfoContainer &rays,
2517                                                  RayInfoContainer &frontRays,
[639]2518                                                  RayInfoContainer &backRays) const
[463]2519{
2520        int splits = 0;
2521
[574]2522        RayInfoContainer::const_iterator it, it_end = rays.end();
2523
2524        for (it = rays.begin(); it != it_end; ++ it)
[463]2525        {
[574]2526                RayInfo bRay = *it;
2527               
[463]2528                VssRay *ray = bRay.mRay;
[473]2529                float t;
[463]2530
[485]2531                // get classification and receive new t
[463]2532                const int cf = bRay.ComputeRayIntersection(plane, t);
[482]2533
[463]2534                switch (cf)
2535                {
2536                case -1:
2537                        backRays.push_back(bRay);
2538                        break;
2539                case 1:
2540                        frontRays.push_back(bRay);
2541                        break;
[482]2542                case 0:
2543                        {
[485]2544                                //-- split ray
[639]2545                                //   test if start point behind or in front of plane
[485]2546                                const int side = plane.Side(bRay.ExtrapOrigin());
2547
2548                                if (side <= 0)
2549                                {
2550                                        backRays.push_back(RayInfo(ray, bRay.GetMinT(), t));
2551                                        frontRays.push_back(RayInfo(ray, t, bRay.GetMaxT()));
2552                                }
2553                                else
2554                                {
2555                                        frontRays.push_back(RayInfo(ray, bRay.GetMinT(), t));
2556                                        backRays.push_back(RayInfo(ray, t, bRay.GetMaxT()));
2557                                }
[463]2558                        }
2559                        break;
2560                default:
[485]2561                        Debug << "Should not come here" << endl;
[463]2562                        break;
2563                }
2564        }
2565
2566        return splits;
2567}
2568
[479]2569
[463]2570void VspBspTree::ExtractHalfSpaces(BspNode *n, vector<Plane3> &halfSpaces) const
2571{
2572        BspNode *lastNode;
2573
2574        do
2575        {
2576                lastNode = n;
2577
2578                // want to get planes defining geometry of this node => don't take
2579                // split plane of node itself
2580                n = n->GetParent();
[482]2581
[463]2582                if (n)
2583                {
2584                        BspInterior *interior = dynamic_cast<BspInterior *>(n);
2585                        Plane3 halfSpace = dynamic_cast<BspInterior *>(interior)->GetPlane();
2586
[683]2587            if (interior->GetBack() != lastNode)
[463]2588                                halfSpace.ReverseOrientation();
2589
2590                        halfSpaces.push_back(halfSpace);
2591                }
2592        }
2593        while (n);
2594}
2595
[485]2596
[482]2597void VspBspTree::ConstructGeometry(BspNode *n,
[503]2598                                                                   BspNodeGeometry &geom) const
[463]2599{
[437]2600        vector<Plane3> halfSpaces;
2601        ExtractHalfSpaces(n, halfSpaces);
2602
2603        PolygonContainer candidatePolys;
[678]2604        vector<Plane3> candidatePlanes;
[437]2605
[683]2606        // bounded planes are added to the polygons
[437]2607        for (int i = 0; i < (int)halfSpaces.size(); ++ i)
2608        {
2609                Polygon3 *p = GetBoundingBox().CrossSection(halfSpaces[i]);
[482]2610
[448]2611                if (p->Valid(mEpsilon))
[437]2612                {
[683]2613                        candidatePolys.push_back(p);
2614                        candidatePlanes.push_back(halfSpaces[i]);
[437]2615                }
2616        }
2617
2618        // add faces of bounding box (also could be faces of the cell)
2619        for (int i = 0; i < 6; ++ i)
2620        {
2621                VertexContainer vertices;
[482]2622
[437]2623                for (int j = 0; j < 4; ++ j)
2624                        vertices.push_back(mBox.GetFace(i).mVertices[j]);
2625
[678]2626                Polygon3 *poly = new Polygon3(vertices);
2627
2628                candidatePolys.push_back(poly);
2629                candidatePlanes.push_back(poly->GetSupportingPlane());
[437]2630        }
2631
2632        for (int i = 0; i < (int)candidatePolys.size(); ++ i)
2633        {
2634                // polygon is split by all other planes
2635                for (int j = 0; (j < (int)halfSpaces.size()) && candidatePolys[i]; ++ j)
2636                {
2637                        if (i == j) // polygon and plane are coincident
2638                                continue;
2639
2640                        VertexContainer splitPts;
2641                        Polygon3 *frontPoly, *backPoly;
2642
[482]2643                        const int cf =
[448]2644                                candidatePolys[i]->ClassifyPlane(halfSpaces[j],
2645                                                                                                 mEpsilon);
[482]2646
[437]2647                        switch (cf)
2648                        {
2649                                case Polygon3::SPLIT:
2650                                        frontPoly = new Polygon3();
2651                                        backPoly = new Polygon3();
2652
[482]2653                                        candidatePolys[i]->Split(halfSpaces[j],
2654                                                                                         *frontPoly,
[448]2655                                                                                         *backPoly,
2656                                                                                         mEpsilon);
[437]2657
2658                                        DEL_PTR(candidatePolys[i]);
2659
[683]2660                                        if (backPoly->Valid(mEpsilon))
2661                                                candidatePolys[i] = backPoly;
[437]2662                                        else
[683]2663                                                DEL_PTR(backPoly);
[437]2664
[683]2665                                        // outside, don't need this
2666                                        DEL_PTR(frontPoly);
[437]2667                                        break;
[683]2668                                // polygon outside of halfspace
2669                                case Polygon3::FRONT_SIDE:
[437]2670                                        DEL_PTR(candidatePolys[i]);
2671                                        break;
2672                                // just take polygon as it is
[683]2673                                case Polygon3::BACK_SIDE:
[437]2674                                case Polygon3::COINCIDENT:
2675                                default:
2676                                        break;
2677                        }
2678                }
[482]2679
[437]2680                if (candidatePolys[i])
[678]2681                {
2682                        geom.Add(candidatePolys[i], candidatePlanes[i]);
2683                        //      geom.mPolys.push_back(candidates[i]);
2684                }
[437]2685        }
[463]2686}
2687
[485]2688
[582]2689void VspBspTree::ConstructGeometry(ViewCell *vc,
[503]2690                                                                   BspNodeGeometry &vcGeom) const
[589]2691{
[580]2692        ViewCellContainer leaves;
[590]2693       
2694        mViewCellsTree->CollectLeaves(vc, leaves);
[463]2695
[580]2696        ViewCellContainer::const_iterator it, it_end = leaves.end();
2697
[463]2698        for (it = leaves.begin(); it != it_end; ++ it)
[580]2699        {
2700                BspLeaf *l = dynamic_cast<BspViewCell *>(*it)->mLeaf;
[590]2701               
[580]2702                ConstructGeometry(l, vcGeom);
2703        }
[463]2704}
2705
[485]2706
[482]2707int VspBspTree::FindNeighbors(BspNode *n, vector<BspLeaf *> &neighbors,
[562]2708                                                          const bool onlyUnmailed) const
[463]2709{
[551]2710        stack<bspNodePair> nodeStack;
2711       
2712        BspNodeGeometry nodeGeom;
2713        ConstructGeometry(n, nodeGeom);
2714       
[500]2715        // split planes from the root to this node
2716        // needed to verify that we found neighbor leaf
[557]2717        // TODO: really needed?
[463]2718        vector<Plane3> halfSpaces;
2719        ExtractHalfSpaces(n, halfSpaces);
2720
[551]2721
2722        BspNodeGeometry *rgeom = new BspNodeGeometry();
2723        ConstructGeometry(mRoot, *rgeom);
2724
2725        nodeStack.push(bspNodePair(mRoot, rgeom));
2726
[482]2727        while (!nodeStack.empty())
[463]2728        {
[551]2729                BspNode *node = nodeStack.top().first;
2730                BspNodeGeometry *geom = nodeStack.top().second;
[562]2731       
[463]2732                nodeStack.pop();
2733
[557]2734                if (node->IsLeaf())
[562]2735                {
[557]2736                        // test if this leaf is in valid view space
2737                        if (node->TreeValid() &&
2738                                (node != n) &&
2739                                (!onlyUnmailed || !node->Mailed()))
2740                        {
2741                                bool isAdjacent = true;
[551]2742
[570]2743                                if (1)
[557]2744                                {
[562]2745                                        // test all planes of current node if still adjacent
2746                                        for (int i = 0; (i < halfSpaces.size()) && isAdjacent; ++ i)
2747                                        {
2748                                                const int cf =
[678]2749                                                        Polygon3::ClassifyPlane(geom->GetPolys(),
[562]2750                                                                                                        halfSpaces[i],
2751                                                                                                        mEpsilon);
[482]2752
[683]2753                                                if (cf == Polygon3::FRONT_SIDE)
[562]2754                                                {
2755                                                        isAdjacent = false;
2756                                                }
[557]2757                                        }
2758                                }
[562]2759                                else
[557]2760                                {
[562]2761                                        // TODO: why is this wrong??
2762                                        // test all planes of current node if still adjacent
[678]2763                                        for (int i = 0; (i < nodeGeom.Size()) && isAdjacent; ++ i)
[562]2764                                        {
[678]2765                                                Polygon3 *poly = nodeGeom.GetPolys()[i];
[555]2766
[562]2767                                                const int cf =
[678]2768                                                        Polygon3::ClassifyPlane(geom->GetPolys(),
[562]2769                                                                                                        poly->GetSupportingPlane(),
2770                                                                                                        mEpsilon);
[557]2771
[683]2772                                                if (cf == Polygon3::FRONT_SIDE)
[562]2773                                                {
2774                                                        isAdjacent = false;
2775                                                }
[557]2776                                        }
[570]2777                                }
[557]2778                                // neighbor was found
2779                                if (isAdjacent)
[562]2780                                {       
[551]2781                                        neighbors.push_back(dynamic_cast<BspLeaf *>(node));
[562]2782                                }
[463]2783                        }
[562]2784                }
2785                else
2786                {
2787                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
[482]2788
[678]2789                        const int cf = Polygon3::ClassifyPlane(nodeGeom.GetPolys(),
[562]2790                                                                                                   interior->GetPlane(),
2791                                                                                                   mEpsilon);
[551]2792                       
[562]2793                        BspNode *front = interior->GetFront();
2794                        BspNode *back = interior->GetBack();
[551]2795           
[562]2796                        BspNodeGeometry *fGeom = new BspNodeGeometry();
2797                        BspNodeGeometry *bGeom = new BspNodeGeometry();
[463]2798
[562]2799                        geom->SplitGeometry(*fGeom,
2800                                                                *bGeom,
2801                                                                interior->GetPlane(),
2802                                                                mBox,
[675]2803                                                                //0.0000001f);
[562]2804                                                                mEpsilon);
[551]2805               
[683]2806                        if (cf == Polygon3::BACK_SIDE)
[562]2807                        {
[683]2808                                nodeStack.push(bspNodePair(interior->GetBack(), bGeom));
2809                                DEL_PTR(fGeom);
[562]2810                        }
2811                        else
2812                        {
[683]2813                                if (cf == Polygon3::FRONT_SIDE)
[551]2814                                {
[683]2815                                        nodeStack.push(bspNodePair(interior->GetFront(), fGeom));
2816                                        DEL_PTR(bGeom);
[551]2817                                }
[482]2818                                else
[562]2819                                {       // random decision
2820                                        nodeStack.push(bspNodePair(front, fGeom));
2821                                        nodeStack.push(bspNodePair(back, bGeom));
[463]2822                                }
[551]2823                        }
[463]2824                }
[562]2825       
[551]2826                DEL_PTR(geom);
[463]2827        }
[482]2828
[463]2829        return (int)neighbors.size();
2830}
2831
[489]2832
[600]2833
2834int VspBspTree::FindApproximateNeighbors(BspNode *n, vector<BspLeaf *> &neighbors,
2835                                                                                 const bool onlyUnmailed) const
2836{
2837        stack<bspNodePair> nodeStack;
2838       
2839        BspNodeGeometry nodeGeom;
2840        ConstructGeometry(n, nodeGeom);
2841       
2842        // split planes from the root to this node
2843        // needed to verify that we found neighbor leaf
2844        // TODO: really needed?
2845        vector<Plane3> halfSpaces;
2846        ExtractHalfSpaces(n, halfSpaces);
2847
2848
2849        BspNodeGeometry *rgeom = new BspNodeGeometry();
2850        ConstructGeometry(mRoot, *rgeom);
2851
2852        nodeStack.push(bspNodePair(mRoot, rgeom));
2853
2854        while (!nodeStack.empty())
2855        {
2856                BspNode *node = nodeStack.top().first;
2857                BspNodeGeometry *geom = nodeStack.top().second;
2858       
2859                nodeStack.pop();
2860
2861                if (node->IsLeaf())
2862                {
2863                        // test if this leaf is in valid view space
2864                        if (node->TreeValid() &&
2865                                (node != n) &&
2866                                (!onlyUnmailed || !node->Mailed()))
2867                        {
2868                                bool isAdjacent = true;
2869
2870                                // neighbor was found
2871                                if (isAdjacent)
2872                                {       
2873                                        neighbors.push_back(dynamic_cast<BspLeaf *>(node));
2874                                }
2875                        }
2876                }
2877                else
2878                {
2879                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2880
[678]2881                        const int cf = Polygon3::ClassifyPlane(nodeGeom.GetPolys(),
[600]2882                                                                                                   interior->GetPlane(),
2883                                                                                                   mEpsilon);
2884                       
2885                        BspNode *front = interior->GetFront();
2886                        BspNode *back = interior->GetBack();
2887           
2888                        BspNodeGeometry *fGeom = new BspNodeGeometry();
2889                        BspNodeGeometry *bGeom = new BspNodeGeometry();
2890
2891                        geom->SplitGeometry(*fGeom,
2892                                                                *bGeom,
2893                                                                interior->GetPlane(),
2894                                                                mBox,
[675]2895                                                                //0.0000001f);
[600]2896                                                                mEpsilon);
2897               
[683]2898                        if (cf == Polygon3::BACK_SIDE)
[600]2899                        {
[683]2900                                nodeStack.push(bspNodePair(interior->GetBack(), bGeom));
2901                                DEL_PTR(fGeom);
[600]2902                        }
2903                        else
2904                        {
[683]2905                                if (cf == Polygon3::FRONT_SIDE)
[600]2906                                {
[683]2907                                        nodeStack.push(bspNodePair(interior->GetFront(), fGeom));
2908                                        DEL_PTR(bGeom);
[600]2909                                }
2910                                else
2911                                {       // random decision
2912                                        nodeStack.push(bspNodePair(front, fGeom));
2913                                        nodeStack.push(bspNodePair(back, bGeom));
2914                                }
2915                        }
2916                }
2917       
2918                DEL_PTR(geom);
2919        }
2920
2921        return (int)neighbors.size();
2922}
2923
2924
2925
[463]2926BspLeaf *VspBspTree::GetRandomLeaf(const Plane3 &halfspace)
2927{
2928    stack<BspNode *> nodeStack;
2929        nodeStack.push(mRoot);
[482]2930
[463]2931        int mask = rand();
[482]2932
2933        while (!nodeStack.empty())
[463]2934        {
2935                BspNode *node = nodeStack.top();
2936                nodeStack.pop();
[482]2937
2938                if (node->IsLeaf())
[463]2939                {
2940                        return dynamic_cast<BspLeaf *>(node);
[482]2941                }
2942                else
[463]2943                {
2944                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2945                        BspNode *next;
[503]2946                        BspNodeGeometry geom;
[482]2947
[463]2948                        // todo: not very efficient: constructs full cell everytime
[498]2949                        ConstructGeometry(interior, geom);
[463]2950
[503]2951                        const int cf =
[678]2952                                Polygon3::ClassifyPlane(geom.GetPolys(), halfspace, mEpsilon);
[463]2953
2954                        if (cf == Polygon3::BACK_SIDE)
2955                                next = interior->GetFront();
2956                        else
2957                                if (cf == Polygon3::FRONT_SIDE)
2958                                        next = interior->GetFront();
[482]2959                        else
[463]2960                        {
2961                                // random decision
2962                                if (mask & 1)
2963                                        next = interior->GetBack();
2964                                else
2965                                        next = interior->GetFront();
2966                                mask = mask >> 1;
2967                        }
2968
2969                        nodeStack.push(next);
2970                }
2971        }
[482]2972
[463]2973        return NULL;
2974}
2975
[694]2976
[463]2977BspLeaf *VspBspTree::GetRandomLeaf(const bool onlyUnmailed)
2978{
2979        stack<BspNode *> nodeStack;
[482]2980
[463]2981        nodeStack.push(mRoot);
2982
2983        int mask = rand();
[482]2984
2985        while (!nodeStack.empty())
[463]2986        {
2987                BspNode *node = nodeStack.top();
2988                nodeStack.pop();
[482]2989
2990                if (node->IsLeaf())
[463]2991                {
2992                        if ( (!onlyUnmailed || !node->Mailed()) )
2993                                return dynamic_cast<BspLeaf *>(node);
2994                }
[482]2995                else
[463]2996                {
2997                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
2998
2999                        // random decision
3000                        if (mask & 1)
3001                                nodeStack.push(interior->GetBack());
3002                        else
3003                                nodeStack.push(interior->GetFront());
3004
3005                        mask = mask >> 1;
3006                }
3007        }
[482]3008
[463]3009        return NULL;
3010}
3011
[694]3012
[463]3013int VspBspTree::ComputePvsSize(const RayInfoContainer &rays) const
3014{
3015        int pvsSize = 0;
3016
3017        RayInfoContainer::const_iterator rit, rit_end = rays.end();
3018
3019        Intersectable::NewMail();
3020
3021        for (rit = rays.begin(); rit != rays.end(); ++ rit)
3022        {
3023                VssRay *ray = (*rit).mRay;
[482]3024
[463]3025                if (ray->mOriginObject)
3026                {
3027                        if (!ray->mOriginObject->Mailed())
3028                        {
3029                                ray->mOriginObject->Mail();
3030                                ++ pvsSize;
3031                        }
3032                }
3033                if (ray->mTerminationObject)
3034                {
3035                        if (!ray->mTerminationObject->Mailed())
3036                        {
3037                                ray->mTerminationObject->Mail();
3038                                ++ pvsSize;
3039                        }
3040                }
3041        }
3042
3043        return pvsSize;
3044}
3045
[694]3046
[463]3047float VspBspTree::GetEpsilon() const
3048{
3049        return mEpsilon;
3050}
3051
3052
3053int VspBspTree::SplitPolygons(const Plane3 &plane,
[482]3054                                                          PolygonContainer &polys,
3055                                                          PolygonContainer &frontPolys,
3056                                                          PolygonContainer &backPolys,
[463]3057                                                          PolygonContainer &coincident) const
3058{
3059        int splits = 0;
3060
[574]3061        PolygonContainer::const_iterator it, it_end = polys.end();
3062
3063        for (it = polys.begin(); it != polys.end(); ++ it)     
[463]3064        {
[574]3065                Polygon3 *poly = *it;
[463]3066
3067                // classify polygon
3068                const int cf = poly->ClassifyPlane(plane, mEpsilon);
3069
3070                switch (cf)
3071                {
3072                        case Polygon3::COINCIDENT:
3073                                coincident.push_back(poly);
[482]3074                                break;
3075                        case Polygon3::FRONT_SIDE:
[463]3076                                frontPolys.push_back(poly);
3077                                break;
3078                        case Polygon3::BACK_SIDE:
3079                                backPolys.push_back(poly);
3080                                break;
3081                        case Polygon3::SPLIT:
3082                                backPolys.push_back(poly);
3083                                frontPolys.push_back(poly);
3084                                ++ splits;
3085                                break;
3086                        default:
3087                Debug << "SHOULD NEVER COME HERE\n";
3088                                break;
3089                }
3090        }
3091
3092        return splits;
3093}
[466]3094
3095
[469]3096int VspBspTree::CastLineSegment(const Vector3 &origin,
3097                                                                const Vector3 &termination,
3098                                                                vector<ViewCell *> &viewcells)
[466]3099{
[469]3100        int hits = 0;
[600]3101        stack<BspRayTraversalData> tQueue;
[482]3102
[469]3103        float mint = 0.0f, maxt = 1.0f;
[482]3104
[469]3105        Intersectable::NewMail();
[600]3106        ViewCell::NewMail();
[482]3107
[469]3108        Vector3 entp = origin;
3109        Vector3 extp = termination;
[482]3110
[469]3111        BspNode *node = mRoot;
3112        BspNode *farChild = NULL;
[482]3113
[485]3114        float t;
[694]3115        const float thresh = 1e-6f; // matt: change this
3116       
[482]3117        while (1)
[469]3118        {
[482]3119                if (!node->IsLeaf())
[469]3120                {
3121                        BspInterior *in = dynamic_cast<BspInterior *>(node);
[482]3122
[469]3123                        Plane3 splitPlane = in->GetPlane();
[485]3124                       
[666]3125                        const int entSide = splitPlane.Side(entp, thresh);
3126                        const int extSide = splitPlane.Side(extp, thresh);
[482]3127
[485]3128                        if (entSide < 0)
[469]3129                        {
[666]3130                                node = in->GetBack();
3131                               
3132                                // plane does not split ray => no far child
3133                                if (extSide <= 0)
3134                                        continue;
3135 
3136                                farChild = in->GetFront(); // plane splits ray
[485]3137                        }
3138                        else if (entSide > 0)
[469]3139                        {
[666]3140                                node = in->GetFront();
[482]3141
[666]3142                                if (extSide >= 0) // plane does not split ray => no far child
3143                                        continue;
[482]3144
3145                                farChild = in->GetBack(); // plane splits ray
[469]3146                        }
[694]3147                        else // one of the ray end points is on the plane
[485]3148                        {       // NOTE: what to do if ray is coincident with plane?
3149                                if (extSide < 0)
3150                                        node = in->GetBack();
[694]3151                                else //if (extSide > 0)
[485]3152                                        node = in->GetFront();
[694]3153                                //else break; // coincident => count no intersections
3154
[485]3155                                continue; // no far child
[469]3156                        }
[482]3157
[469]3158                        // push data for far child
[600]3159                        tQueue.push(BspRayTraversalData(farChild, extp));
[482]3160
[469]3161                        // find intersection of ray segment with plane
3162                        extp = splitPlane.FindIntersection(origin, extp, &t);
[485]3163                }
3164                else
[469]3165                {
3166                        // reached leaf => intersection with view cell
3167                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
[666]3168                        ViewCell *viewCell;
3169                       
3170                        viewCell = mViewCellsTree->GetActiveViewCell(leaf->GetViewCell());
3171                        //viewCell = leaf->GetViewCell();
[482]3172
[590]3173                        if (!viewCell->Mailed())
[469]3174                        {
[590]3175                                viewcells.push_back(viewCell);
3176                                viewCell->Mail();
[469]3177                                ++ hits;
3178                        }
[482]3179
[469]3180                        //-- fetch the next far child from the stack
[600]3181                        if (tQueue.empty())
[469]3182                                break;
[482]3183
[469]3184                        entp = extp;
[485]3185                       
[600]3186                        BspRayTraversalData &s = tQueue.top();
[482]3187
[469]3188                        node = s.mNode;
3189                        extp = s.mExitPoint;
[482]3190
[600]3191                        tQueue.pop();
[469]3192                }
[466]3193        }
[487]3194
[469]3195        return hits;
[466]3196}
[478]3197
[576]3198
3199
3200
[485]3201int VspBspTree::TreeDistance(BspNode *n1, BspNode *n2) const
[482]3202{
3203        std::deque<BspNode *> path1;
3204        BspNode *p1 = n1;
[479]3205
[482]3206        // create path from node 1 to root
3207        while (p1)
3208        {
3209                if (p1 == n2) // second node on path
3210                        return (int)path1.size();
3211
3212                path1.push_front(p1);
3213                p1 = p1->GetParent();
3214        }
3215
3216        int depth = n2->GetDepth();
3217        int d = depth;
3218
3219        BspNode *p2 = n2;
3220
3221        // compare with same depth
3222        while (1)
3223        {
3224                if ((d < (int)path1.size()) && (p2 == path1[d]))
3225                        return (depth - d) + ((int)path1.size() - 1 - d);
3226
3227                -- d;
3228                p2 = p2->GetParent();
3229        }
3230
3231        return 0; // never come here
3232}
3233
[580]3234
[501]3235BspNode *VspBspTree::CollapseTree(BspNode *node, int &collapsed)
[479]3236{
[590]3237// TODO
3238#if VC_HISTORY
[495]3239        if (node->IsLeaf())
[479]3240                return node;
3241
[492]3242        BspInterior *interior = dynamic_cast<BspInterior *>(node);
3243
[501]3244        BspNode *front = CollapseTree(interior->GetFront(), collapsed);
3245        BspNode *back = CollapseTree(interior->GetBack(), collapsed);
[492]3246
[479]3247        if (front->IsLeaf() && back->IsLeaf())
3248        {
3249                BspLeaf *frontLeaf = dynamic_cast<BspLeaf *>(front);
3250                BspLeaf *backLeaf = dynamic_cast<BspLeaf *>(back);
3251
3252                //-- collapse tree
3253                if (frontLeaf->GetViewCell() == backLeaf->GetViewCell())
3254                {
3255                        BspViewCell *vc = frontLeaf->GetViewCell();
3256
3257                        BspLeaf *leaf = new BspLeaf(interior->GetParent(), vc);
[489]3258                        leaf->SetTreeValid(frontLeaf->TreeValid());
[482]3259
[479]3260                        // replace a link from node's parent
3261                        if (leaf->GetParent())
3262                                leaf->GetParent()->ReplaceChildLink(node, leaf);
[517]3263                        else
3264                                mRoot = leaf;
3265
[501]3266                        ++ collapsed;
[479]3267                        delete interior;
3268
3269                        return leaf;
3270                }
3271        }
[590]3272#endif
[495]3273        return node;
3274}
3275
3276
[501]3277int VspBspTree::CollapseTree()
[495]3278{
[501]3279        int collapsed = 0;
[580]3280        //TODO
3281#if VC_HISTORY
[501]3282        (void)CollapseTree(mRoot, collapsed);
[517]3283
[485]3284        // revalidate leaves
[517]3285        RepairViewCellsLeafLists();
[580]3286#endif
[501]3287        return collapsed;
[479]3288}
3289
3290
[517]3291void VspBspTree::RepairViewCellsLeafLists()
[492]3292{
[590]3293// TODO
3294#if VC_HISTORY
[479]3295        // list not valid anymore => clear
[492]3296        stack<BspNode *> nodeStack;
3297        nodeStack.push(mRoot);
3298
3299        ViewCell::NewMail();
3300
3301        while (!nodeStack.empty())
3302        {
3303                BspNode *node = nodeStack.top();
3304                nodeStack.pop();
3305
3306                if (node->IsLeaf())
3307                {
3308                        BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
3309
3310                        BspViewCell *viewCell = leaf->GetViewCell();
[590]3311
[492]3312                        if (!viewCell->Mailed())
3313                        {
3314                                viewCell->mLeaves.clear();
3315                                viewCell->Mail();
3316                        }
[580]3317       
[492]3318                        viewCell->mLeaves.push_back(leaf);
[590]3319
[492]3320                }
3321                else
3322                {
3323                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
3324
3325                        nodeStack.push(interior->GetFront());
3326                        nodeStack.push(interior->GetBack());
3327                }
[479]3328        }
[590]3329// TODO
3330#endif
[479]3331}
3332
3333
[532]3334typedef pair<BspNode *, BspNodeGeometry *> bspNodePair;
3335
[535]3336
[532]3337int VspBspTree::CastBeam(Beam &beam)
3338{
3339    stack<bspNodePair> nodeStack;
3340        BspNodeGeometry *rgeom = new BspNodeGeometry();
3341        ConstructGeometry(mRoot, *rgeom);
3342
3343        nodeStack.push(bspNodePair(mRoot, rgeom));
3344 
3345        ViewCell::NewMail();
3346
3347        while (!nodeStack.empty())
3348        {
3349                BspNode *node = nodeStack.top().first;
3350                BspNodeGeometry *geom = nodeStack.top().second;
3351                nodeStack.pop();
3352               
3353                AxisAlignedBox3 box;
[697]3354                geom->GetBoundingBox(box);
[532]3355
[535]3356                const int side = beam.ComputeIntersection(box);
[532]3357               
3358                switch (side)
3359                {
3360                case -1:
[547]3361                        CollectViewCells(node, true, beam.mViewCells, true);
[532]3362                        break;
3363                case 0:
[535]3364                       
[532]3365                        if (node->IsLeaf())
3366                        {
[535]3367                                BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
3368                       
[532]3369                                if (!leaf->GetViewCell()->Mailed() && leaf->TreeValid())
[535]3370                                {
3371                                        leaf->GetViewCell()->Mail();
[532]3372                                        beam.mViewCells.push_back(leaf->GetViewCell());
[535]3373                                }
[532]3374                        }
3375                        else
3376                        {
3377                                BspInterior *interior = dynamic_cast<BspInterior *>(node);
[535]3378                       
[538]3379                                BspNode *first = interior->GetFront();
3380                                BspNode *second = interior->GetBack();
[535]3381           
3382                                BspNodeGeometry *firstGeom = new BspNodeGeometry();
3383                                BspNodeGeometry *secondGeom = new BspNodeGeometry();
3384
[538]3385                                geom->SplitGeometry(*firstGeom,
3386                                                                        *secondGeom,
3387                                                                        interior->GetPlane(),
3388                                                                        mBox,
[675]3389                                                                        //0.0000001f);
[538]3390                                                                        mEpsilon);
[535]3391
[532]3392                                // decide on the order of the nodes
3393                                if (DotProd(beam.mPlanes[0].mNormal,
3394                                        interior->GetPlane().mNormal) > 0)
3395                                {
3396                                        swap(first, second);
[535]3397                                        swap(firstGeom, secondGeom);
[532]3398                                }
3399
[535]3400                                nodeStack.push(bspNodePair(first, firstGeom));
3401                                nodeStack.push(bspNodePair(second, secondGeom));
[532]3402                        }
[535]3403                       
[532]3404                        break;
[538]3405                default:
[532]3406                        // default: cull
[538]3407                        break;
[532]3408                }
[538]3409               
[532]3410                DEL_PTR(geom);
[535]3411               
[532]3412        }
3413
[538]3414        return (int)beam.mViewCells.size();
[532]3415}
3416
3417
[485]3418void VspBspTree::SetViewCellsManager(ViewCellsManager *vcm)
[478]3419{
[485]3420        mViewCellsManager = vcm;
3421}
3422
3423
[580]3424int VspBspTree::CollectMergeCandidates(const vector<BspLeaf *> leaves,
3425                                                                           vector<MergeCandidate> &candidates)
[485]3426{
[478]3427        BspLeaf::NewMail();
[508]3428       
[478]3429        vector<BspLeaf *>::const_iterator it, it_end = leaves.end();
3430
[580]3431        int numCandidates = 0;
[509]3432
[478]3433        // find merge candidates and push them into queue
3434        for (it = leaves.begin(); it != it_end; ++ it)
3435        {
3436                BspLeaf *leaf = *it;
[485]3437               
3438                // the same leaves must not be part of two merge candidates
3439                leaf->Mail();
[650]3440               
[485]3441                vector<BspLeaf *> neighbors;
[694]3442                if (1)
[650]3443                        FindNeighbors(leaf, neighbors, true);
3444                else
3445                        FindApproximateNeighbors(leaf, neighbors, true);
[485]3446                vector<BspLeaf *>::const_iterator nit, nit_end = neighbors.end();
3447
3448                // TODO: test if at least one ray goes from one leaf to the other
3449                for (nit = neighbors.begin(); nit != nit_end; ++ nit)
[508]3450                {
3451                        if ((*nit)->GetViewCell() != leaf->GetViewCell())
[509]3452                        {
[580]3453                                MergeCandidate mc(leaf->GetViewCell(), (*nit)->GetViewCell());
[564]3454
[676]3455                                // dont't merge view cells if they are empty and not front and back leaf of the same parent
3456                                // in the tree?
3457                                if (mEmptyViewCellsMergeAllowed ||
[682]3458                                        !leaf->GetViewCell()->GetPvs().Empty() || !(*nit)->GetViewCell()->GetPvs().Empty() ||
[676]3459                    leaf->IsSibling(*nit))
3460                                {
3461                                        candidates.push_back(mc);
3462                                }
3463
[580]3464                                ++ numCandidates;
3465                                if ((numCandidates % 1000) == 0)
[566]3466                                {
[580]3467                                        cout << "collected " << numCandidates << " merge candidates" << endl;
[566]3468                                }
[509]3469                        }
[485]3470                }
3471        }
3472
[580]3473        Debug << "merge queue: " << (int)candidates.size() << endl;
3474        Debug << "leaves in queue: " << numCandidates << endl;
3475       
[508]3476
[485]3477        return (int)leaves.size();
3478}
3479
3480
[580]3481int VspBspTree::CollectMergeCandidates(const VssRayContainer &rays,
3482                                                                           vector<MergeCandidate> &candidates)
[485]3483{
[547]3484        ViewCell::NewMail();
[503]3485        long startTime = GetTime();
[574]3486       
[485]3487        map<BspLeaf *, vector<BspLeaf*> > neighborMap;
[574]3488        ViewCellContainer::const_iterator iit;
[485]3489
[503]3490        int numLeaves = 0;
[485]3491       
3492        BspLeaf::NewMail();
3493
[574]3494        for (int i = 0; i < (int)rays.size(); ++ i)
[485]3495        { 
[574]3496                VssRay *ray = rays[i];
[547]3497       
[485]3498                // traverse leaves stored in the rays and compare and
3499                // merge consecutive leaves (i.e., the neighbors in the tree)
[574]3500                if (ray->mViewCells.size() < 2)
[485]3501                        continue;
[580]3502//TODO viewcellhierarchy
[574]3503                iit = ray->mViewCells.begin();
3504                BspViewCell *bspVc = dynamic_cast<BspViewCell *>(*(iit ++));
[580]3505                BspLeaf *leaf = bspVc->mLeaf;
[485]3506               
3507                // traverse intersections
[489]3508                // consecutive leaves are neighbors => add them to queue
[574]3509                for (; iit != ray->mViewCells.end(); ++ iit)
[485]3510                {
[489]3511                        // next pair
3512                        BspLeaf *prevLeaf = leaf;
[574]3513                        bspVc = dynamic_cast<BspViewCell *>(*iit);
[580]3514            leaf = bspVc->mLeaf;
[489]3515
[508]3516                        // view space not valid or same view cell
3517                        if (!leaf->TreeValid() || !prevLeaf->TreeValid() ||
3518                                (leaf->GetViewCell() == prevLeaf->GetViewCell()))
[489]3519                                continue;
3520
[580]3521                vector<BspLeaf *> &neighbors = neighborMap[leaf];
[485]3522                       
3523                        bool found = false;
[478]3524
[485]3525                        // both leaves inserted in queue already =>
3526                        // look if double pair already exists
3527                        if (leaf->Mailed() && prevLeaf->Mailed())
[478]3528                        {
[485]3529                                vector<BspLeaf *>::const_iterator it, it_end = neighbors.end();
3530                               
3531                for (it = neighbors.begin(); !found && (it != it_end); ++ it)
3532                                        if (*it == prevLeaf)
3533                                                found = true; // already in queue
3534                        }
[547]3535               
[485]3536                        if (!found)
3537                        {
[564]3538                                // this pair is not in map yet
[485]3539                                // => insert into the neighbor map and the queue
3540                                neighbors.push_back(prevLeaf);
3541                                neighborMap[prevLeaf].push_back(leaf);
[478]3542
[485]3543                                leaf->Mail();
3544                                prevLeaf->Mail();
[547]3545               
[580]3546                                MergeCandidate mc(leaf->GetViewCell(), prevLeaf->GetViewCell());
3547                               
3548                                candidates.push_back(mc);
[564]3549
[580]3550                                if (((int)candidates.size() % 1000) == 0)
[564]3551                                {
[580]3552                                        cout << "collected " << (int)candidates.size() << " merge candidates" << endl;
[564]3553                                }
[478]3554                        }
[485]3555        }
3556        }
[564]3557
[485]3558        Debug << "neighbormap size: " << (int)neighborMap.size() << endl;
[580]3559        Debug << "merge queue: " << (int)candidates.size() << endl;
[503]3560        Debug << "leaves in queue: " << numLeaves << endl;
[485]3561
[580]3562
[503]3563        //-- collect the leaves which haven't been found by ray casting
[542]3564        if (0)
3565        {
[551]3566                cout << "finding additional merge candidates using geometry" << endl;
[542]3567                vector<BspLeaf *> leaves;
[547]3568                CollectLeaves(leaves, true);
[542]3569                Debug << "found " << (int)leaves.size() << " new leaves" << endl << endl;
[580]3570                CollectMergeCandidates(leaves, candidates);
[542]3571        }
[503]3572
3573        return numLeaves;
[485]3574}
3575
3576
3577
3578
[508]3579ViewCell *VspBspTree::GetViewCell(const Vector3 &point)
[492]3580{
3581  if (mRoot == NULL)
3582        return NULL;
3583 
3584  stack<BspNode *> nodeStack;
3585  nodeStack.push(mRoot);
3586 
3587  ViewCell *viewcell = NULL;
3588 
3589  while (!nodeStack.empty())  {
3590        BspNode *node = nodeStack.top();
3591        nodeStack.pop();
3592       
3593        if (node->IsLeaf()) {
3594          viewcell = dynamic_cast<BspLeaf *>(node)->GetViewCell();
3595          break;
3596        } else {
3597         
3598          BspInterior *interior = dynamic_cast<BspInterior *>(node);
3599               
3600          // random decision
3601          if (interior->GetPlane().Side(point) < 0)
3602                nodeStack.push(interior->GetBack());
3603          else
3604                nodeStack.push(interior->GetFront());
3605        }
3606  }
3607 
3608  return viewcell;
3609}
3610
3611
[487]3612bool VspBspTree::ViewPointValid(const Vector3 &viewPoint) const
3613{
3614        BspNode *node = mRoot;
[485]3615
[487]3616        while (1)
3617        {
3618                // early exit
3619                if (node->TreeValid())
3620                        return true;
3621
3622                if (node->IsLeaf())
3623                        return false;
3624                       
3625                BspInterior *in = dynamic_cast<BspInterior *>(node);
[490]3626                                       
3627                if (in->GetPlane().Side(viewPoint) <= 0)
[487]3628                {
3629                        node = in->GetBack();
3630                }
3631                else
3632                {
3633                        node = in->GetFront();
3634                }
3635        }
3636
3637        // should never come here
3638        return false;
3639}
3640
3641
3642void VspBspTree::PropagateUpValidity(BspNode *node)
3643{
[574]3644        const bool isValid = node->TreeValid();
3645
3646        // propagative up invalid flag until only invalid nodes exist over this node
3647        if (!isValid)
[487]3648        {
[574]3649                while (!node->IsRoot() && node->GetParent()->TreeValid())
3650                {
3651                        node = node->GetParent();
3652                        node->SetTreeValid(false);
3653                }
[487]3654        }
[574]3655        else
3656        {
3657                // propagative up valid flag until one of the subtrees is invalid
3658                while (!node->IsRoot() && !node->TreeValid())
3659                {
3660            node = node->GetParent();
3661                        BspInterior *interior = dynamic_cast<BspInterior *>(node);
3662                       
3663                        // the parent is valid iff both leaves are valid
3664                        node->SetTreeValid(interior->GetBack()->TreeValid() &&
3665                                                           interior->GetFront()->TreeValid());
3666                }
3667        }
[487]3668}
3669
[508]3670
3671bool VspBspTree::Export(ofstream &stream)
[503]3672{
[508]3673        ExportNode(mRoot, stream);
[487]3674
[503]3675        return true;
3676}
3677
3678
[508]3679void VspBspTree::ExportNode(BspNode *node, ofstream &stream)
3680{
3681        if (node->IsLeaf())
[503]3682        {
[508]3683                BspLeaf *leaf = dynamic_cast<BspLeaf *>(node);
[590]3684                ViewCell *viewCell = mViewCellsTree->GetActiveViewCell(leaf->GetViewCell());
3685
[508]3686                int id = -1;
[590]3687                if (viewCell != mOutOfBoundsCell)
3688                        id = viewCell->GetId();
[503]3689
[508]3690                stream << "<Leaf viewCellId=\"" << id << "\" />" << endl;
[503]3691        }
[508]3692        else
[503]3693        {
[508]3694                BspInterior *interior = dynamic_cast<BspInterior *>(node);
3695       
3696                Plane3 plane = interior->GetPlane();
3697                stream << "<Interior plane=\"" << plane.mNormal.x << " "
3698                           << plane.mNormal.y << " " << plane.mNormal.z << " "
3699                           << plane.mD << "\">" << endl;
[503]3700
[508]3701                ExportNode(interior->GetBack(), stream);
3702                ExportNode(interior->GetFront(), stream);
[503]3703
[508]3704                stream << "</Interior>" << endl;
[503]3705        }
3706}
Note: See TracBrowser for help on using the repository browser.