source: GTP/trunk/Lib/Vis/Preprocessing/src/HierarchyManager.cpp @ 1710

Revision 1710, 55.8 KB checked in by mattausch, 18 years ago (diff)
RevLine 
[1237]1#include <stack>
2#include <time.h>
3#include <iomanip>
4
5#include "ViewCell.h"
6#include "Plane3.h"
7#include "HierarchyManager.h"
8#include "Mesh.h"
9#include "common.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 "ViewCellsManager.h"
17#include "Beam.h"
18#include "KdTree.h"
[1315]19#include "IntersectableWrapper.h"
[1237]20#include "VspTree.h"
21#include "OspTree.h"
[1259]22#include "BvHierarchy.h"
[1707]23#include "ViewCell.h"
[1237]24
25
26namespace GtpVisibilityPreprocessor {
27
28
29#define USE_FIXEDPOINT_T 0
30
31
32/*******************************************************************/
33/*              class HierarchyManager implementation              */
34/*******************************************************************/
35
36
[1421]37HierarchyManager::HierarchyManager(const int objectSpaceSubdivisionType):
[1308]38mObjectSpaceSubdivisionType(objectSpaceSubdivisionType),
[1279]39mOspTree(NULL),
40mBvHierarchy(NULL)
[1237]41{
[1308]42        switch(mObjectSpaceSubdivisionType)
[1279]43        {
44        case KD_BASED_OBJ_SUBDIV:
45                mOspTree = new OspTree();
46                mOspTree->mVspTree = mVspTree;
[1379]47                mOspTree->mHierarchyManager = this;
[1279]48                break;
49        case BV_BASED_OBJ_SUBDIV:
50        mBvHierarchy = new BvHierarchy();
[1379]51                mBvHierarchy->mHierarchyManager = this;
[1279]52                break;
53        default:
54                break;
55        }
56
[1379]57        // hierarchy manager links view space partition and object space partition
[1421]58        mVspTree = new VspTree();
[1379]59        mVspTree->mHierarchyManager = this;
60       
[1580]61        mViewSpaceSubdivisionType = KD_BASED_VIEWSPACE_SUBDIV;
[1288]62        ParseEnvironment();
[1237]63}
64
65
[1421]66HierarchyManager::HierarchyManager(KdTree *kdTree):
[1308]67mObjectSpaceSubdivisionType(KD_BASED_OBJ_SUBDIV),
[1279]68mBvHierarchy(NULL)
69{
70        mOspTree = new OspTree(*kdTree);
71        mOspTree->mVspTree = mVspTree;
72
[1421]73        mVspTree = new VspTree();
[1379]74        mVspTree->mHierarchyManager = this;
[1279]75
[1580]76        mViewSpaceSubdivisionType = KD_BASED_VIEWSPACE_SUBDIV;
[1288]77        ParseEnvironment();
78}
79
80
81void HierarchyManager::ParseEnvironment()
82{
83        Environment::GetSingleton()->GetFloatValue(
84                "Hierarchy.Termination.minGlobalCostRatio", mTermMinGlobalCostRatio);
85        Environment::GetSingleton()->GetIntValue(
86                "Hierarchy.Termination.globalCostMissTolerance", mTermGlobalCostMissTolerance);
87
[1370]88        Environment::GetSingleton()->GetBoolValue(
89                "Hierarchy.Construction.startWithObjectSpace", mStartWithObjectSpace);
90
[1293]91        Environment::GetSingleton()->GetIntValue(
[1294]92                "Hierarchy.Termination.maxLeaves", mTermMaxLeaves);
93
94        Environment::GetSingleton()->GetIntValue(
[1293]95                "Hierarchy.Construction.type", mConstructionType);
96
[1311]97        Environment::GetSingleton()->GetIntValue(
98                "Hierarchy.Construction.minDepthForOsp", mMinDepthForObjectSpaceSubdivion);
[1370]99
100        Environment::GetSingleton()->GetIntValue(
101                "Hierarchy.Construction.minDepthForVsp", mMinDepthForViewSpaceSubdivion);
[1311]102       
[1314]103        Environment::GetSingleton()->GetBoolValue(
104                "Hierarchy.Construction.repairQueue", mRepairQueue);
105
[1449]106        Environment::GetSingleton()->GetBoolValue(
[1564]107                "Hierarchy.Construction.useMultiLevel", mUseMultiLevelConstruction);
[1449]108
[1580]109        Environment::GetSingleton()->GetIntValue(
110                "Hierarchy.Construction.levels", mNumMultiLevels);
111
[1640]112        Environment::GetSingleton()->GetIntValue(
113                "Hierarchy.Construction.minStepsOfSameType", mMinStepsOfSameType);
114       
[1684]115        Environment::GetSingleton()->GetIntValue(
116                "Hierarchy.Construction.maxStepsOfSameType", mMaxStepsOfSameType);
117
[1624]118        char subdivisionStatsLog[100];
119        Environment::GetSingleton()->GetStringValue("Hierarchy.subdivisionStats", subdivisionStatsLog);
120        mSubdivisionStats.open(subdivisionStatsLog);
121
[1633]122        Environment::GetSingleton()->GetBoolValue(
123                "Hierarchy.Construction.recomputeSplitPlaneOnRepair", mRecomputeSplitPlaneOnRepair);
[1624]124
[1662]125        Environment::GetSingleton()->GetBoolValue(
126                "Hierarchy.Construction.considerMemory", mConsiderMemory);
127
[1673]128        Environment::GetSingleton()->GetBoolValue(
129                "Hierarchy.Construction.considerMemory2", mConsiderMemory2);
130
[1649]131        Environment::GetSingleton()->GetFloatValue(
132                "Hierarchy.Termination.maxMemory", mTermMaxMemory);
133
[1684]134        if (1 && mConsiderMemory2)
135        {
136                mMemoryConst = (float)(sizeof(VspLeaf *) + sizeof (VspViewCell *));
137        }
138        else
139        {
140                Environment::GetSingleton()->GetFloatValue(
141                        "Hierarchy.Termination.memoryConst", mMemoryConst);
142        }
[1666]143
[1662]144        // compare to bytes
[1653]145        mTermMaxMemory *= (1024.0f * 1024.0f);
146
[1705]147        Debug << "******** Hierarchy Manager Options ***********" << endl;
[1294]148        Debug << "max leaves: " << mTermMaxLeaves << endl;
[1288]149        Debug << "min global cost ratio: " << mTermMinGlobalCostRatio << endl;
150        Debug << "global cost miss tolerance: " << mTermGlobalCostMissTolerance << endl;
[1314]151        Debug << "min depth for object space subdivision: " << mMinDepthForObjectSpaceSubdivion << endl;
152        Debug << "repair queue: " << mRepairQueue << endl;
[1580]153        Debug << "number of multilevels: " << mNumMultiLevels << endl;
[1633]154        Debug << "recompute split plane on repair: " << mRecomputeSplitPlaneOnRepair << endl;
[1640]155        Debug << "minimal number of steps from same type: " << mMinStepsOfSameType << endl;
[1649]156        Debug << "maximal allowed memory: " << mTermMaxMemory << endl;
[1673]157        Debug << "consider memory: " << mConsiderMemory << endl;
158        Debug << "consider memory2: " << mConsiderMemory << endl;
[1666]159        Debug << "mem const: " << mMemoryConst << endl;
[1684]160        Debug << "min steps of same kind: " << mMinStepsOfSameType << endl;
161        Debug << "max steps of same kind: " << mMaxStepsOfSameType << endl;
[1632]162
163        switch (mConstructionType)
164        {
165        case 0:
166                Debug << "construction type: sequential" << endl;
167                break;
168        case 1:
169                Debug << "construction type: interleaved" << endl;
170                break;
171        case 2:
172                Debug << "construction type: gradient" << endl;
173                break;
174        case 3:
175                Debug << "construction type: multilevel" << endl;
176                break;
177        default:
178                Debug << "construction type " << mConstructionType << " unknown" << endl;
179                break;
180        }
181
[1625]182        //Debug << "min render cost " << mMinRenderCostDecrease << endl;
[1449]183        Debug << endl;
[1279]184}
185
186
187HierarchyManager::~HierarchyManager()
188{
189        DEL_PTR(mOspTree);
[1421]190        DEL_PTR(mVspTree);
[1279]191        DEL_PTR(mBvHierarchy);
192}
193
194
[1370]195int HierarchyManager::GetObjectSpaceSubdivisionType() const
196{
197        return mObjectSpaceSubdivisionType;
198}
199
200
201int HierarchyManager::GetViewSpaceSubdivisionType() const
202{
203        return mViewSpaceSubdivisionType;
204}
205
206
[1279]207void HierarchyManager::SetViewCellsManager(ViewCellsManager *vcm)
208{
209        mVspTree->SetViewCellsManager(vcm);
210
211        if (mOspTree)
[1576]212        {
[1279]213                mOspTree->SetViewCellsManager(vcm);
[1576]214        }
[1416]215        else if (mBvHierarchy)
[1576]216        {
[1279]217                mBvHierarchy->SetViewCellsManager(vcm);
[1576]218        }
[1279]219}
220
221
222void HierarchyManager::SetViewCellsTree(ViewCellsTree *vcTree)
223{
224        mVspTree->SetViewCellsTree(vcTree);
225}
226
227
[1379]228VspTree *HierarchyManager::GetVspTree()
229{
230        return mVspTree;
231}
232
[1563]233/*
[1379]234AxisAlignedBox3 HierarchyManager::GetViewSpaceBox() const
235{
236        return mVspTree->mBoundingBox;
[1563]237}*/
[1379]238
239
[1416]240AxisAlignedBox3 HierarchyManager::GetObjectSpaceBox() const
241{
242        switch (mObjectSpaceSubdivisionType)
243        {
244        case KD_BASED_OBJ_SUBDIV:
245                return mOspTree->mBoundingBox;
246        case BV_BASED_OBJ_SUBDIV:
247                return mBvHierarchy->mBoundingBox;
248        default:
[1576]249                // hack: empty box
[1416]250                return AxisAlignedBox3();
251        }
252}
253
254
[1625]255SubdivisionCandidate *HierarchyManager::NextSubdivisionCandidate(SplitQueue &splitQueue)
[1237]256{
[1625]257        SubdivisionCandidate *splitCandidate = splitQueue.Top();
258        splitQueue.Pop();
[1237]259
260        return splitCandidate;
261}
262
263
[1624]264void HierarchyManager::EvalSubdivisionStats()
[1237]265{
[1649]266        // question: should I also add the mem usage of the hierarchies?
267        const float objectSpaceMem = 0;//GetObjectSpaceMemUsage();
268        const float viewSpaceMem = 0;//mVspTree->GetMemUsage();
[1640]269       
270        // calculate cost in MB
[1676]271        const float memoryCost = mHierarchyStats.mMemory  / float(1024 * 1024)
[1640]272                                                         + objectSpaceMem + viewSpaceMem;
273
[1580]274        //cout << "pvs entries " << mHierarchyStats.pvsEntries << endl;
[1576]275        AddSubdivisionStats(mHierarchyStats.Leaves(),
[1624]276                                                mHierarchyStats.mRenderCostDecrease,
277                                                mHierarchyStats.mTotalCost,
[1625]278                                                mHierarchyStats.mPvsEntries,
[1640]279                                                memoryCost,
[1654]280                                                1.0f / (mHierarchyStats.mTotalCost * memoryCost),
281                                                (float)mVspTree->mVspStats.Leaves() / (float)GetObjectSpaceSubdivisionLeaves()
[1576]282                                                );
[1237]283}
284
285
286void HierarchyManager::AddSubdivisionStats(const int splits,
287                                                                                   const float renderCostDecr,
[1576]288                                                                                   const float totalRenderCost,
[1625]289                                                                                   const int pvsEntries,
[1640]290                                                                                   const float memory,
[1654]291                                                                                   const float renderCostPerStorage,
292                                                                                   const float vspOspRatio)
[1237]293{
[1308]294        mSubdivisionStats
[1237]295                        << "#Splits\n" << splits << endl
296                        << "#RenderCostDecrease\n" << renderCostDecr << endl
[1577]297                        << "#TotalEntriesInPvs\n" << pvsEntries << endl
[1625]298                        << "#TotalRenderCost\n" << totalRenderCost << endl
299                        << "#Memory\n" << memory << endl
[1660]300                        << "#FpsPerMb\n" << renderCostPerStorage << endl
[1654]301                        << "#VspOspRatio\n" << vspOspRatio << endl;
[1237]302}
303
304
305bool HierarchyManager::GlobalTerminationCriteriaMet(SubdivisionCandidate *candidate) const
306{
[1421]307        const bool terminationCriteriaMet =
308                (0
[1294]309                || (mHierarchyStats.Leaves() >= mTermMaxLeaves)
[1649]310                || (mHierarchyStats.mMemory >= mTermMaxMemory)
311                || candidate->GlobalTerminationCriteriaMet()
312                //|| (mHierarchyStats.mRenderCostDecrease < mMinRenderCostDecrease)
[1633]313                //|| (mHierarchyStats.mGlobalCostMisses >= mTermGlobalCostMissTolerance)
[1288]314                );
[1421]315
[1653]316#if _DEBUG
[1610]317        if (terminationCriteriaMet)
[1421]318        {
319                Debug << "hierarchy global termination criteria met:" << endl;
320                Debug << "leaves: " << mHierarchyStats.Leaves() << " " << mTermMaxLeaves << endl;
[1449]321                Debug << "cost misses: " << mHierarchyStats.mGlobalCostMisses << " " << mTermGlobalCostMissTolerance << endl;
[1649]322                Debug << "memory: " << mHierarchyStats.mMemory << " " << mTermMaxMemory << endl;
[1421]323        }
[1653]324#endif
[1610]325
[1421]326        return terminationCriteriaMet;
[1237]327}
328
329
330void HierarchyManager::Construct(const VssRayContainer &sampleRays,
[1311]331                                                                 const ObjectContainer &objects,
332                                                                 AxisAlignedBox3 *forcedViewSpace)
[1237]333{
[1679]334        mTimeStamp = 1;
335
[1627]336        switch (mConstructionType)
[1449]337        {
[1627]338        case MULTILEVEL:
[1449]339                ConstructMultiLevel(sampleRays, objects, forcedViewSpace);
[1627]340                break;
341        case INTERLEAVED:
342        case SEQUENTIAL:
[1624]343                ConstructInterleaved(sampleRays, objects, forcedViewSpace);
[1627]344                break;
345        case GRADIENT:
346                ConstructInterleavedWithGradient(sampleRays, objects, forcedViewSpace);
347                break;
348        default:
349                break;
[1624]350        }
[1642]351
352        // hack: should be different parameter name
353        if (mUseMultiLevelConstruction)
354        {
355                cout << "starting optimizing multilevel ... " << endl;
356                // try to optimize on the above hierarchy
357                OptimizeMultiLevel(sampleRays, objects, forcedViewSpace);
358               
359                cout << "finished" << endl;
360        }
[1624]361}
362
363
[1686]364void HierarchyManager::ConstructInterleavedWithGradient(const VssRayContainer &sampleRays,
[1626]365                                                                                                                const ObjectContainer &objects,
366                                                                                                                AxisAlignedBox3 *forcedViewSpace)
[1624]367{
368        mHierarchyStats.Reset();
369        mHierarchyStats.Start();
[1625]370       
[1624]371        mHierarchyStats.mNodes = 2;
[1640]372
373        // create first nodes
374        mVspTree->Initialise(sampleRays, forcedViewSpace);
375        InitialiseObjectSpaceSubdivision(objects);
376
377        // hack: assume that object space can be seen from view space
[1677]378        mHierarchyStats.mTotalCost = mInitialRenderCost = (float)objects.size();
[1667]379        // only one entry for start
[1640]380        mHierarchyStats.mPvsEntries = 1;
[1667]381        mHierarchyStats.mMemory = (float)ObjectPvs::GetEntrySizeByte();
[1640]382
383        EvalSubdivisionStats();
[1624]384        Debug << "setting total cost to " << mHierarchyStats.mTotalCost << endl;
385
386        const long startTime = GetTime();
387        cout << "Constructing view space / object space tree ... \n";
388       
[1633]389        SplitQueue objectSpaceQueue;
390        SplitQueue viewSpaceQueue;
391
[1696]392        int vspSteps = 0, ospSteps = 0;
[1684]393
[1624]394        // use sah for evaluating osp tree construction
395        // in the first iteration of the subdivision
396        mSavedViewSpaceSubdivisionType = mViewSpaceSubdivisionType;
397        mViewSpaceSubdivisionType = NO_VIEWSPACE_SUBDIV;
[1662]398        mSavedObjectSpaceSubdivisionType = mObjectSpaceSubdivisionType;
[1624]399
[1632]400        // number of initial splits
[1640]401        const int minSteps = mMinStepsOfSameType;
[1684]402        const int maxSteps = mMaxStepsOfSameType;
[1625]403
[1676]404        SubdivisionCandidate *osc = PrepareObjectSpaceSubdivision(sampleRays, objects);
[1633]405        objectSpaceQueue.Push(osc);
406
[1640]407
[1633]408        /////////////////////////
409        // calulcate initial object space splits
410       
[1684]411        SubdivisionCandidateContainer dirtyList;
[1633]412
413        // subdivide object space first
414        // for first round, use sah splits. Once view space partition
415        // has started, use render cost heuristics instead
[1684]416        ospSteps = RunConstruction(objectSpaceQueue, dirtyList, NULL, minSteps, maxSteps);
[1640]417        cout << "\n" << ospSteps << " object space partition steps taken" << endl;
[1633]418
[1640]419        // create view space
[1667]420        SubdivisionCandidate *vsc = PrepareViewSpaceSubdivision(sampleRays, objects);
[1684]421        viewSpaceQueue.Push(vsc);
[1633]422
[1684]423        dirtyList.clear();
424
[1642]425        // view space subdivision started
[1633]426        mViewSpaceSubdivisionType = mSavedViewSpaceSubdivisionType;
427
[1684]428        if (1)
429        {
430                // rather also start with 100 view space splits to avoid initial bias.
431                vspSteps = RunConstruction(viewSpaceQueue, dirtyList, NULL, minSteps, maxSteps);
432                cout << "\n" << vspSteps << " view space partition steps taken" << endl;
433               
434                /// Repair split queue
435                cout << "repairing queue ... " << endl;
436                RepairQueue(dirtyList, objectSpaceQueue, true);
437                cout << "repaired " << (int)dirtyList.size() << " candidates" << endl;
[1633]438
[1684]439                dirtyList.clear();
440        }
441        else
442        {
443                // the priorities were calculated for driving sah.
444                // => recalculate "real" priorities taking visibility into
445                // account so we can compare to view space splits
446                ResetQueue(objectSpaceQueue, false);
447        }
448
[1624]449        // This method subdivides view space / object space
450        // in order to converge to some optimal cost for this partition
451        // start with object space partiton
452        // then optimizate view space partition for the current osp
453        // and vice versa until iteration depth is reached.
[1696]454
[1684]455        bool lastSplitWasOsp = true;
456
[1633]457        while (!(viewSpaceQueue.Empty() && objectSpaceQueue.Empty()))
[1624]458        {
[1662]459                // decide upon next split type
[1701]460                const float vspPriority = viewSpaceQueue.Top() ? viewSpaceQueue.Top()->GetPriority() : -1e20f;
461                const float ospPriority = objectSpaceQueue.Top() ? objectSpaceQueue.Top()->GetPriority() : -1e20f;
[1662]462               
[1640]463                cout << "new decicion, vsp: " << vspPriority << ", osp: " << ospPriority << endl;
464
[1633]465                // should view or object space be subdivided further?
[1684]466                if (ospPriority >= vspPriority)
467                //if (!lastSplitWasOsp)
[1633]468                {
[1679]469                        lastSplitWasOsp = true;
[1673]470                        cout << "osp" << endl;
[1684]471                       
[1633]472                        // dirtied view space candidates
473                        SubdivisionCandidateContainer dirtyVspList;
[1624]474
[1633]475                        // subdivide object space first
476                        // for first round, use sah splits. Once view space partition
477                        // has started, use render cost heuristics instead
[1684]478                        const int ospSteps =
479                                RunConstruction(objectSpaceQueue, dirtyVspList, viewSpaceQueue.Top(), minSteps, maxSteps);
[1624]480
[1640]481                        cout << "\n" << ospSteps << " object space partition steps taken" << endl;
[1684]482                        Debug << "\n" << ospSteps << " object space partition steps taken" << endl;
483
[1640]484                        /// Repair split queue, i.e., affected view space candidates
[1633]485                        cout << "repairing queue ... " << endl;
486                        RepairQueue(dirtyVspList, viewSpaceQueue, true);
[1640]487                        cout << "\nrepaired " << (int)dirtyVspList.size() << " candidates" << endl;
[1633]488                }
489                else
490                {
[1679]491                        lastSplitWasOsp = false;
[1673]492                        cout << "vsp" << endl;
493                       
[1633]494                        /////////////////
495                        // subdivide view space with respect to the objects
[1625]496
[1684]497                        // dirtied object space candidates
[1633]498                        SubdivisionCandidateContainer dirtyOspList;
[1624]499
[1633]500                        // process view space candidates
501                        const int vspSteps =
[1676]502                                RunConstruction(viewSpaceQueue, dirtyOspList, objectSpaceQueue.Top(), minSteps, maxSteps);
[1624]503
[1640]504                        cout << "\n" << vspSteps << " view space partition steps taken" << endl;
[1684]505                        Debug << "\n" << vspSteps << " view space partition steps taken" << endl;
[1625]506
[1633]507                        // view space subdivision constructed
508                        mViewSpaceSubdivisionType = mSavedViewSpaceSubdivisionType;
[1624]509
[1633]510                        /// Repair split queue
511                        cout << "repairing queue ... " << endl;
512                        RepairQueue(dirtyOspList, objectSpaceQueue, true);
[1640]513                        cout << "repaired " << (int)dirtyOspList.size() << " candidates" << endl;
[1633]514                }
[1449]515        }
[1633]516
[1624]517        cout << "\nfinished in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
518
519        mHierarchyStats.Stop();
520        mVspTree->mVspStats.Stop();
[1625]521
[1649]522        FinishObjectSpaceSubdivision(objects, !mUseMultiLevelConstruction);
[1449]523}
524
525
526void HierarchyManager::ConstructInterleaved(const VssRayContainer &sampleRays,
527                                                                                        const ObjectContainer &objects,
528                                                                                        AxisAlignedBox3 *forcedViewSpace)
529{
[1308]530        mHierarchyStats.Reset();
531        mHierarchyStats.Start();
[1664]532
533        // two nodes for view space and object space
534        mHierarchyStats.mNodes = 2;
[1640]535        mHierarchyStats.mPvsEntries = 1;
[1667]536        mHierarchyStats.mMemory = (float)ObjectPvs::GetEntrySizeByte();
[1640]537        mHierarchyStats.mTotalCost = (float)objects.size();
[1449]538
[1624]539        mHierarchyStats.mRenderCostDecrease = 0;
[1237]540
[1624]541        EvalSubdivisionStats();
542        Debug << "setting total cost to " << mHierarchyStats.mTotalCost << endl;
543
[1311]544        const long startTime = GetTime();
[1308]545        cout << "Constructing view space / object space tree ... \n";
[1237]546       
[1640]547        // create only roots
548        mVspTree->Initialise(sampleRays, forcedViewSpace);
549        InitialiseObjectSpaceSubdivision(objects);
[1379]550
[1633]551        // use objects for evaluating vsp tree construction in the
552        // first levels of the subdivision
[1323]553        mSavedObjectSpaceSubdivisionType = mObjectSpaceSubdivisionType;
554        mObjectSpaceSubdivisionType = NO_OBJ_SUBDIV;
555
[1370]556        mSavedViewSpaceSubdivisionType = mViewSpaceSubdivisionType;
557        mViewSpaceSubdivisionType = NO_VIEWSPACE_SUBDIV;
558
[1632]559        // start view space subdivison immediately?
[1329]560        if (StartViewSpaceSubdivision())
561        {
[1624]562                // prepare vsp tree for traversal
[1640]563        mViewSpaceSubdivisionType = mSavedViewSpaceSubdivisionType;
564                SubdivisionCandidate *vspSc =
565                        PrepareViewSpaceSubdivision(sampleRays, objects);
566
[1632]567                mTQueue.Push(vspSc);
[1329]568        }
569       
[1323]570        // start object space subdivision immediately?
571        if (StartObjectSpaceSubdivision())
572        {
573                mObjectSpaceSubdivisionType = mSavedObjectSpaceSubdivisionType;
[1632]574                SubdivisionCandidate *ospSc =
575                        PrepareObjectSpaceSubdivision(sampleRays, objects);
576                mTQueue.Push(ospSc);
[1323]577        }
[1632]578
[1624]579        // begin subdivision
[1667]580        RunConstruction(mRepairQueue, sampleRays, objects, forcedViewSpace);
[1308]581       
[1418]582        cout << "\nfinished in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
[1370]583
[1548]584        mObjectSpaceSubdivisionType = mSavedObjectSpaceSubdivisionType;
585        mViewSpaceSubdivisionType = mSavedViewSpaceSubdivisionType;
586
[1313]587        mHierarchyStats.Stop();
[1259]588        mVspTree->mVspStats.Stop();
[1649]589       
590        FinishObjectSpaceSubdivision(objects, !mUseMultiLevelConstruction);
[1237]591}
592
593
[1625]594SubdivisionCandidate *HierarchyManager::PrepareViewSpaceSubdivision(const VssRayContainer &sampleRays,
595                                                                                                                                        const ObjectContainer &objects)
[1311]596{
[1632]597        cout << "\npreparing view space hierarchy construction ... " << endl;
[1625]598
[1580]599        // hack: reset global cost misses
[1548]600        mHierarchyStats.mGlobalCostMisses = 0;
[1625]601
[1311]602        RayInfoContainer *viewSpaceRays = new RayInfoContainer();
603        SubdivisionCandidate *vsc =
[1379]604                mVspTree->PrepareConstruction(sampleRays, *viewSpaceRays);
[1311]605
[1661]606        /////////
607        //-- new stats
608
[1624]609        mHierarchyStats.mTotalCost = mVspTree->mTotalCost;
[1662]610       
[1624]611        cout << "\nreseting cost for vsp, new total cost: " << mHierarchyStats.mTotalCost << endl;
[1421]612
[1625]613        return vsc;
[1311]614}
615
616
[1640]617float HierarchyManager::GetObjectSpaceMemUsage() const
618{
619        if (mObjectSpaceSubdivisionType == KD_BASED_OBJ_SUBDIV)
620        {
621                // TODO;
622        }
623        else if (mObjectSpaceSubdivisionType == BV_BASED_OBJ_SUBDIV)
624        {
625                return mBvHierarchy->GetMemUsage();
626        }
627
628        return -1;
629}
630
631void HierarchyManager::InitialiseObjectSpaceSubdivision(const ObjectContainer &objects)
632{
633        if (mObjectSpaceSubdivisionType == KD_BASED_OBJ_SUBDIV)
634        {
635                // TODO;
636        }
637        else if (mObjectSpaceSubdivisionType == BV_BASED_OBJ_SUBDIV)
638        {
639                mBvHierarchy->Initialise(objects);
640        }
641}
642
643
[1625]644SubdivisionCandidate *HierarchyManager::PrepareObjectSpaceSubdivision(const VssRayContainer &sampleRays,
645                                                                                                                                          const ObjectContainer &objects)
[1308]646{
[1625]647        // hack: reset global cost misses
648        mHierarchyStats.mGlobalCostMisses = 0;
[1522]649
[1308]650        if (mObjectSpaceSubdivisionType == KD_BASED_OBJ_SUBDIV)
651        {
[1625]652                return PrepareOspTree(sampleRays, objects);
[1308]653        }
654        else if (mObjectSpaceSubdivisionType == BV_BASED_OBJ_SUBDIV)
655        {
[1625]656                return PrepareBvHierarchy(sampleRays, objects);
[1308]657        }
[1625]658       
659        return NULL;
[1308]660}
[1294]661
[1308]662
[1625]663SubdivisionCandidate *HierarchyManager::PrepareBvHierarchy(const VssRayContainer &sampleRays,
664                                                                                                                   const ObjectContainer &objects)
[1294]665{
[1421]666        const long startTime = GetTime();
667
668        cout << "preparing bv hierarchy construction ... " << endl;
[1548]669       
[1294]670        // compute first candidate
671        SubdivisionCandidate *sc =
672                mBvHierarchy->PrepareConstruction(sampleRays, objects);
673
[1624]674        mHierarchyStats.mTotalCost = mBvHierarchy->mTotalCost;
675        Debug << "\nreseting cost, new total cost: " << mHierarchyStats.mTotalCost << endl;
[1294]676
[1548]677        cout << "finished bv hierarchy preparation in "
678                 << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
[1625]679         
680        return sc;
[1294]681}
682
683
[1625]684SubdivisionCandidate *HierarchyManager::PrepareOspTree(const VssRayContainer &sampleRays,
685                                                                                                           const ObjectContainer &objects)
[1294]686{
[1370]687        cout << "starting osp tree construction ... " << endl;
688
[1294]689        RayInfoContainer *objectSpaceRays = new RayInfoContainer();
690
691        // start with one big kd cell - all objects can be seen from everywhere
692        // note: only true for view space = object space
693
694        // compute first candidate
695        SubdivisionCandidate *osc =
696                mOspTree->PrepareConstruction(sampleRays, objects, *objectSpaceRays);
697
[1624]698        mHierarchyStats.mTotalCost = mOspTree->mTotalCost;
[1625]699        Debug << "\nreseting cost for osp, new total cost: " << mHierarchyStats.mTotalCost << endl;
[1294]700       
[1625]701    return osc;
[1294]702}
703
704
[1624]705bool HierarchyManager::ApplySubdivisionCandidate(SubdivisionCandidate *sc,
[1625]706                                                                                                 SplitQueue &splitQueue,
[1624]707                                                                                                 const bool repairQueue)
[1237]708{
[1624]709        const bool terminationCriteriaMet = GlobalTerminationCriteriaMet(sc);
[1633]710        const bool success = sc->Apply(splitQueue, terminationCriteriaMet);
[1444]711
[1610]712        if (!success) // split was not taken
713        {
714                return false;
715        }
716
717        ///////////////
[1624]718        //-- split was successful => update stats and queue
[1610]719
720    // cost ratio of cost decrease / totalCost
[1624]721        const float costRatio = sc->GetRenderCostDecrease() / mHierarchyStats.mTotalCost;
[1610]722        //Debug << "ratio: " << costRatio << " min ratio: " << mTermMinGlobalCostRatio << endl;
723       
724        if (costRatio < mTermMinGlobalCostRatio)
725        {
726                ++ mHierarchyStats.mGlobalCostMisses;
727        }
728       
[1580]729        cout << sc->Type() << " ";
730               
[1640]731        /////////////
[1580]732        // update stats
[1640]733
[1624]734        mHierarchyStats.mNodes += 2;
[1640]735        mHierarchyStats.mTotalCost -= sc->GetRenderCostDecrease();
736
737        const int pvsEntriesIncr = sc->GetPvsEntriesIncr();
738        mHierarchyStats.mPvsEntries += pvsEntriesIncr;
739        //cout << "pvs entries: " << pvsEntriesIncr << " " << mHierarchyStats.pvsEntries << endl;
740
741        // memory size in byte
[1676]742        mHierarchyStats.mMemory += (float)ObjectPvs::GetEntrySizeByte() * pvsEntriesIncr;
[1624]743        mHierarchyStats.mRenderCostDecrease = sc->GetRenderCostDecrease();
744
[1654]745        static float memoryCount = 0;
746
747        if (mHierarchyStats.mMemory > memoryCount)
748        {
749                memoryCount += 100000;
[1684]750                cout << "\nstorage cost: " << mHierarchyStats.mMemory / float(1024 * 1024)
751                         << " MB, steps: " << mHierarchyStats.Leaves() << endl;
[1654]752        }
753
[1640]754        // output stats
[1624]755        EvalSubdivisionStats();
[1580]756               
757        if (repairQueue)
[1624]758        {
759                // reevaluate candidates affected by the split for view space splits,
760                // this would be object space splits and other way round
[1625]761                vector<SubdivisionCandidate *> dirtyList;
[1633]762                sc->CollectDirtyCandidates(dirtyList, false);
[1624]763
[1633]764                RepairQueue(dirtyList, splitQueue, mRecomputeSplitPlaneOnRepair);
[1580]765        }
766
[1416]767        return true;
[1237]768}
769
770
[1370]771int HierarchyManager::GetObjectSpaceSubdivisionDepth() const
772{
773        int maxDepth = 0;
774
775        if (mObjectSpaceSubdivisionType == KD_BASED_OBJ_SUBDIV)
776        {
777                maxDepth = mOspTree->mOspStats.maxDepth;
778        }
779        else if (mObjectSpaceSubdivisionType == BV_BASED_OBJ_SUBDIV)
780        {
781                maxDepth = mBvHierarchy->mBvhStats.maxDepth;
782        }
783
784        return maxDepth;
785}
786
787
[1640]788int HierarchyManager::GetObjectSpaceSubdivisionLeaves() const
789{
790        int maxLeaves= 0;
791
792        if (mObjectSpaceSubdivisionType == KD_BASED_OBJ_SUBDIV)
793        {
794                maxLeaves = mOspTree->mOspStats.Leaves();
795        }
796        else if (mObjectSpaceSubdivisionType == BV_BASED_OBJ_SUBDIV)
797        {
798                maxLeaves = mBvHierarchy->mBvhStats.Leaves();
799        }
800
801        return maxLeaves;
802}
803
804
[1663]805int HierarchyManager::GetObjectSpaceSubdivisionNodes() const
806{
807        int maxLeaves = 0;
808
809        if (mObjectSpaceSubdivisionType == KD_BASED_OBJ_SUBDIV)
810        {
811                maxLeaves = mOspTree->mOspStats.nodes;
812        }
813        else if (mObjectSpaceSubdivisionType == BV_BASED_OBJ_SUBDIV)
814        {
815                maxLeaves = mBvHierarchy->mBvhStats.nodes;
816        }
817
818        return maxLeaves;
819}
820
[1308]821bool HierarchyManager::StartObjectSpaceSubdivision() const
[1237]822{
[1370]823        // view space construction already started
824        if (ObjectSpaceSubdivisionConstructed())
825                return false;
826
827        // start immediately with object space subdivision?
828        if (mStartWithObjectSpace)
829                return true;
830
831        // is the queue empty again?
832        if (ViewSpaceSubdivisionConstructed() && mTQueue.Empty())
833                return true;
834
835        // has the depth for subdivision been reached?
836        return
837                ((mConstructionType == INTERLEAVED) &&
[1640]838                 (mMinStepsOfSameType <= mVspTree->mVspStats.nodes));
[1308]839}
840
841
[1329]842bool HierarchyManager::StartViewSpaceSubdivision() const
843{
[1370]844        // view space construction already started
845        if (ViewSpaceSubdivisionConstructed())
846                return false;
847
848        // start immediately with view space subdivision?
849        if (!mStartWithObjectSpace)
850                return true;
851
852        // is the queue empty again?
853        if (ObjectSpaceSubdivisionConstructed() && mTQueue.Empty())
854                return true;
855
856        // has the depth for subdivision been reached?
857        return
858                ((mConstructionType == INTERLEAVED) &&
[1640]859                 (mMinStepsOfSameType <= GetObjectSpaceSubdivisionLeaves()));
[1329]860}
861
862
[1449]863void HierarchyManager::RunConstruction(const bool repairQueue,
864                                                                           const VssRayContainer &sampleRays,
[1311]865                                                                           const ObjectContainer &objects,
[1640]866                                                                           AxisAlignedBox3 *forcedViewSpace)
[1308]867{
[1313]868        while (!FinishedConstruction())
869        {
[1625]870                SubdivisionCandidate *sc = NextSubdivisionCandidate(mTQueue);   
[1632]871       
[1415]872                ///////////////////
[1237]873                //-- subdivide leaf node
[1415]874
[1625]875                ApplySubdivisionCandidate(sc, mTQueue, repairQueue);
[1580]876                               
[1313]877                // we use objects for evaluating vsp tree construction until
[1415]878                // a certain depth once a certain depth existiert ...
[1313]879                if (StartObjectSpaceSubdivision())
880                {
[1323]881                        mObjectSpaceSubdivisionType = mSavedObjectSpaceSubdivisionType;
[1314]882
[1640]883                        cout << "\nstarting object space subdivision after "
[1676]884                                 << mVspTree->mVspStats.nodes << " (" << mMinStepsOfSameType << ") " << endl;
[1329]885
[1632]886                        SubdivisionCandidate *ospSc = PrepareObjectSpaceSubdivision(sampleRays, objects);
[1640]887                       
[1313]888                        cout << "reseting queue ... ";
[1640]889                        ResetQueue(mTQueue, mRecomputeSplitPlaneOnRepair);
[1313]890                        cout << "finished" << endl;
[1640]891
892                        mTQueue.Push(ospSc);
[1313]893                }
894
[1329]895                if (StartViewSpaceSubdivision())
896                {
897                        mViewSpaceSubdivisionType = mSavedViewSpaceSubdivisionType;
898
[1415]899                        cout << "\nstarting view space subdivision at depth "
[1640]900                                 << GetObjectSpaceSubdivisionLeaves() << " ("
901                                 << mMinStepsOfSameType << ") " << endl;
[1329]902
[1640]903                        SubdivisionCandidate *vspSc = PrepareViewSpaceSubdivision(sampleRays, objects);
[1329]904
905                        cout << "reseting queue ... ";
[1640]906                        ResetQueue(mTQueue, mRecomputeSplitPlaneOnRepair);
[1329]907                        cout << "finished" << endl;
[1640]908
909                        // push view space candidate                   
910                        mTQueue.Push(vspSc);
[1329]911                }
912
[1624]913                DEL_PTR(sc);
[1237]914        }
915}
916
917
[1449]918void HierarchyManager::RunConstruction(const bool repairQueue)
919{
[1580]920        // main loop
[1449]921        while (!FinishedConstruction())
922        {
[1625]923                SubdivisionCandidate *sc = NextSubdivisionCandidate(mTQueue);   
[1649]924               
[1624]925                ////////
926                //-- subdivide leaf node of either type
[1642]927        ApplySubdivisionCandidate(sc, mTQueue, repairQueue);
928               
[1624]929                DEL_PTR(sc);
[1449]930        }
931}
932
933
[1625]934int HierarchyManager::RunConstruction(SplitQueue &splitQueue,
[1633]935                                                                          SubdivisionCandidateContainer &dirtyCandidates,
[1667]936                                                                          SubdivisionCandidate *oldCandidate,
[1676]937                                                                          const int minSteps,
938                                                                          const int maxSteps)
[1624]939{
[1676]940        if (minSteps >= maxSteps)
941                cout << "error!! " << minSteps << " equal or larger maxSteps" << endl;
942
[1625]943        int steps = 0;
[1633]944        SubdivisionCandidate::NewMail();
[1625]945
[1624]946        // main loop
[1634]947        while (!splitQueue.Empty())
[1624]948        {
[1701]949                const float priority = splitQueue.Top()->GetPriority();
[1686]950                const float threshold = oldCandidate ? oldCandidate->GetPriority() : 1e20f;
[1679]951
[1701]952                // minimum slope reached
953                if ((steps >= maxSteps) || ((priority < threshold) && !(steps < minSteps)))
954                {
955                        cout << "\n**************** breaking on " << priority << " smaller than " << threshold << endl;
956                        break;
957                }
958               
959                SubdivisionCandidate *sc = NextSubdivisionCandidate(splitQueue);
960                               
[1624]961                ////////
962                //-- subdivide leaf node of either type
963
[1625]964                const bool repairQueue = false;
[1633]965                const bool success = ApplySubdivisionCandidate(sc, splitQueue, repairQueue);
[1625]966
[1632]967                if (success)
968                {
[1697]969                        sc->CollectDirtyCandidates(dirtyCandidates, true);
[1633]970                        ++ steps;
[1632]971                }
[1696]972
973                DEL_PTR(sc);
[1624]974        }
[1625]975
976        return steps;
[1624]977}
978
979
[1625]980SubdivisionCandidate *HierarchyManager::ResetObjectSpaceSubdivision(const VssRayContainer &sampleRays,
981                                                                                                                                        const ObjectContainer &objects)
[1580]982{       
[1632]983        SubdivisionCandidate *firstCandidate;
[1625]984
[1580]985        // object space partition constructed => reconstruct
[1557]986        switch (mObjectSpaceSubdivisionType)
987        {
988        case BV_BASED_OBJ_SUBDIV:
[1580]989                {
990                        cout << "\nreseting bv hierarchy" << endl;
991                        Debug << "old bv hierarchy:\n " << mBvHierarchy->mBvhStats << endl;
[1663]992                               
993                        // rather use this: remove previous nodes and add the two new ones
994                        //mHierarchyStats.mNodes -= mBvHierarchy->mBvhStats.nodes + 1;
995                        mHierarchyStats.mNodes = mVspTree->mVspStats.nodes;
[1649]996                       
[1663]997                        // create root
[1642]998                        mBvHierarchy->Initialise(objects);
[1649]999       
[1632]1000                        firstCandidate = mBvHierarchy->Reset(sampleRays, objects);
[1649]1001
[1625]1002                        mHierarchyStats.mTotalCost = mBvHierarchy->mTotalCost;
[1663]1003                       
[1662]1004                        //mHierarchyStats.mPvsEntries -= mBvHierarchy->mPvsEntries + 1;
[1649]1005                        mHierarchyStats.mPvsEntries = mBvHierarchy->CountViewCells(objects);
[1663]1006
[1667]1007                        mHierarchyStats.mMemory =
1008                                (float)mHierarchyStats.mPvsEntries * ObjectPvs::GetEntrySizeByte();
[1642]1009
[1662]1010                        mHierarchyStats.mRenderCostDecrease = 0;
1011
[1625]1012                        // evaluate stats before first subdivision
1013                        EvalSubdivisionStats();
[1649]1014                        cout << "finished bv hierarchy preparation" << endl;
[1580]1015                }
[1548]1016                break;
[1557]1017
[1548]1018        case KD_BASED_OBJ_SUBDIV:
1019                // TODO
1020        default:
[1632]1021                firstCandidate = NULL;
[1548]1022                break;
1023        }
[1633]1024
[1625]1025        return firstCandidate;
[1449]1026}
1027
1028
[1625]1029SubdivisionCandidate *HierarchyManager::ResetViewSpaceSubdivision(const VssRayContainer &sampleRays,
[1642]1030                                                                                                                                  const ObjectContainer &objects,
1031                                                                                                                                  AxisAlignedBox3 *forcedViewSpace)
[1557]1032{
[1649]1033        ViewCellsManager *vm = mVspTree->mViewCellsManager;
[1557]1034
[1624]1035        // HACK: rather not destroy vsp tree
[1580]1036        DEL_PTR(mVspTree);
1037        mVspTree = new VspTree();
[1649]1038
[1580]1039        mVspTree->mHierarchyManager = this;
[1649]1040        mVspTree->mViewCellsManager = vm;
[1580]1041
[1642]1042        mVspTree->Initialise(sampleRays, forcedViewSpace);
[1580]1043       
[1662]1044        //-- reset stats
[1663]1045    mHierarchyStats.mNodes = GetObjectSpaceSubdivisionNodes();//-mVspTree->mVspStats.nodes + 1;
[1662]1046       
1047        SubdivisionCandidate *vsc = PrepareViewSpaceSubdivision(sampleRays, objects);
1048       
1049        mHierarchyStats.mPvsEntries = mVspTree->mPvsEntries;
[1661]1050        mHierarchyStats.mRenderCostDecrease = 0;
1051
[1667]1052        mHierarchyStats.mMemory = (float)mHierarchyStats.mPvsEntries * ObjectPvs::GetEntrySizeByte();
[1662]1053
[1640]1054        // evaluate new stats before first subdivsiion
[1624]1055        EvalSubdivisionStats();
[1625]1056
1057        return vsc;
[1557]1058}
1059
1060
[1449]1061void HierarchyManager::ConstructMultiLevel(const VssRayContainer &sampleRays,                                                                                   
1062                                                                                   const ObjectContainer &objects,
1063                                                                                   AxisAlignedBox3 *forcedViewSpace)
1064{
1065        mHierarchyStats.Reset();
1066        mHierarchyStats.Start();
[1624]1067        mHierarchyStats.mNodes = 2;
[1449]1068       
[1624]1069        mHierarchyStats.mTotalCost = (float)objects.size();
1070        Debug << "setting total cost to " << mHierarchyStats.mTotalCost << endl;
[1449]1071
1072        const long startTime = GetTime();
1073        cout << "Constructing view space / object space tree ... \n";
1074       
[1640]1075        // initialise view / object space
1076        mVspTree->Initialise(sampleRays, forcedViewSpace);
1077        InitialiseObjectSpaceSubdivision(objects);
[1449]1078
[1580]1079        // use sah for evaluating osp tree construction
1080        // in the first iteration of the subdivision
[1642]1081
[1449]1082        mSavedViewSpaceSubdivisionType = mViewSpaceSubdivisionType;
1083        mViewSpaceSubdivisionType = NO_VIEWSPACE_SUBDIV;
[1640]1084
[1642]1085        SubdivisionCandidate *osc =
1086                PrepareObjectSpaceSubdivision(sampleRays, objects);
1087        mTQueue.Push(osc);
[1640]1088
[1649]1089        //////////////////////////
[1642]1090
1091
[1640]1092        const int limit = mNumMultiLevels;
1093        int i = 0;
1094
1095        // This method subdivides view space / object space
1096        // in order to converge to some optimal cost for this partition
1097        // start with object space partiton
1098        // then optimizate view space partition for the current osp
1099        // and vice versa until iteration depth is reached.
1100        while (1)
1101        {
1102                char subdivisionStatsLog[100];
1103                sprintf(subdivisionStatsLog, "tests/i3d/subdivision-%04d.log", i);
1104                mSubdivisionStats.open(subdivisionStatsLog);
1105
1106                // subdivide object space first
[1642]1107                osc = ResetObjectSpaceSubdivision(sampleRays, objects);
1108                mTQueue.Push(osc);
[1640]1109
1110                // process object space candidates
1111                RunConstruction(false);
1112
1113                // object space subdivision constructed
1114                mObjectSpaceSubdivisionType = mSavedObjectSpaceSubdivisionType;
1115
1116                cout << "iteration " << i << " of " << limit << " finished" << endl;
1117                mSubdivisionStats.close();
1118
1119                if ((i ++) >= limit)
1120                        break;
1121
1122                sprintf(subdivisionStatsLog, "tests/i3d/subdivision-%04d.log", i);
1123                mSubdivisionStats.open(subdivisionStatsLog);
1124
[1649]1125
[1640]1126                /////////////////
1127                // subdivide view space with respect to the objects
1128
[1649]1129                SubdivisionCandidate *vspVc =
1130                        ResetViewSpaceSubdivision(sampleRays, objects, forcedViewSpace);
[1640]1131                mTQueue.Push(vspVc);
1132
1133                // view space subdivision constructed
1134                mViewSpaceSubdivisionType = mSavedViewSpaceSubdivisionType;
1135               
1136                // process view space candidates
1137                RunConstruction(false);
1138
1139                cout << "iteration " << i << " of " << limit << " finished" << endl;
1140                mSubdivisionStats.close();
1141
1142                if ((i ++) >= limit)
1143                        break;
1144        }
[1635]1145       
[1640]1146        cout << "\nfinished in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
[1580]1147
[1640]1148        mHierarchyStats.Stop();
1149        mVspTree->mVspStats.Stop();
1150        FinishObjectSpaceSubdivision(objects);
1151}
1152
1153
1154void HierarchyManager::OptimizeMultiLevel(const VssRayContainer &sampleRays,                                                                                     
1155                                                                                  const ObjectContainer &objects,
1156                                                                                  AxisAlignedBox3 *forcedViewSpace)
1157{
[1649]1158        const long startTime = GetTime();
1159        const int limit = mNumMultiLevels;
1160
1161        // open up new subdivision
1162        mSubdivisionStats.close();
1163
1164        int steps = 0;
1165
1166        int maxViewSpaceLeaves = mVspTree->mVspStats.Leaves();
1167        int maxObjectSpaceLeaves;
1168       
[1642]1169        // set the number of leaves 'evaluated' from the previous methods
[1649]1170        // we go for the same numbers, but we try to optimize both subdivisions
[1642]1171        switch (mObjectSpaceSubdivisionType)
1172        {
1173        case BV_BASED_OBJ_SUBDIV:
[1649]1174                maxObjectSpaceLeaves = mBvHierarchy->mBvhStats.Leaves();
[1642]1175                break;
1176        case KD_BASED_OBJ_SUBDIV:
[1649]1177                maxObjectSpaceLeaves = mOspTree->mOspStats.Leaves();
[1642]1178        default:
[1649]1179                maxObjectSpaceLeaves = 0;
[1642]1180                break;
1181        }
[1640]1182
[1624]1183        // This method subdivides view space / object space
1184        // in order to converge to some optimal cost for this partition
[1557]1185        // start with object space partiton
1186        // then optimizate view space partition for the current osp
1187        // and vice versa until iteration depth is reached.
1188        while (1)
[1548]1189        {
[1580]1190                char subdivisionStatsLog[100];
[1642]1191                sprintf(subdivisionStatsLog, "tests/i3d/subdivision-%04d.log", steps);
[1580]1192                mSubdivisionStats.open(subdivisionStatsLog);
1193
[1624]1194                // subdivide object space first
[1643]1195                SubdivisionCandidate *ospVc =
1196                        ResetObjectSpaceSubdivision(sampleRays, objects);
[1649]1197       
1198                // set the number of leaves 'evaluated' from the previous methods
1199                // we go for the same numbers, but we try to optimize both subdivisions
1200                mBvHierarchy->mTermMaxLeaves = maxObjectSpaceLeaves;
[1642]1201                mTQueue.Push(ospVc);
[1624]1202
[1548]1203                // process object space candidates
1204                RunConstruction(false);
[1449]1205
[1642]1206                cout << "iteration " << steps << " of " << limit << " finished" << endl;
[1580]1207                mSubdivisionStats.close();
[1635]1208
[1642]1209                if ((++ steps) >= limit)
[1557]1210                        break;
1211
[1642]1212                sprintf(subdivisionStatsLog, "tests/i3d/subdivision-%04d.log", steps);
[1580]1213                mSubdivisionStats.open(subdivisionStatsLog);
1214
[1557]1215                /////////////////
[1580]1216                // subdivide view space with respect to the objects
1217
[1643]1218                SubdivisionCandidate *vspVc =
1219                        ResetViewSpaceSubdivision(sampleRays, objects, forcedViewSpace);
[1649]1220
1221                mVspTree->mMaxViewCells = maxViewSpaceLeaves;
[1640]1222                mTQueue.Push(vspVc);
[1624]1223
[1548]1224                // process view space candidates
1225                RunConstruction(false);
[1624]1226
[1642]1227                cout << "iteration " << steps << " of " << limit << " finished" << endl;
[1580]1228                mSubdivisionStats.close();
1229
[1642]1230                if ((++ steps) >= limit)
[1557]1231                        break;
[1548]1232        }
1233       
[1449]1234        cout << "\nfinished in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
1235
1236        mHierarchyStats.Stop();
1237        mVspTree->mVspStats.Stop();
1238        FinishObjectSpaceSubdivision(objects);
1239}
1240
1241
[1640]1242
[1237]1243bool HierarchyManager::FinishedConstruction() const
1244{
1245        return mTQueue.Empty();
1246}
1247
1248
[1313]1249bool HierarchyManager::ObjectSpaceSubdivisionConstructed() const
[1311]1250{
[1642]1251        /*switch (mObjectSpaceSubdivisionType)
[1311]1252        {
1253        case KD_BASED_OBJ_SUBDIV:
1254                return mOspTree && mOspTree->GetRoot();
1255        case BV_BASED_OBJ_SUBDIV:
[1344]1256                return mBvHierarchy && mBvHierarchy->GetRoot();
[1311]1257        default:
[1580]1258                return false;
[1642]1259        }*/
1260        return mObjectSpaceSubdivisionType != NO_OBJ_SUBDIV;
[1311]1261}
1262
1263
[1329]1264bool HierarchyManager::ViewSpaceSubdivisionConstructed() const
1265{
[1635]1266        return mViewSpaceSubdivisionType != NO_VIEWSPACE_SUBDIV;
1267        //return mVspTree && mVspTree->GetRoot();
[1329]1268}
1269
1270
[1625]1271void HierarchyManager::CollectDirtyCandidates(const SubdivisionCandidateContainer &chosenCandidates,
1272                                                                                          SubdivisionCandidateContainer &dirtyList)
[1237]1273{
[1625]1274        SubdivisionCandidateContainer::const_iterator sit, sit_end = chosenCandidates.end();
[1633]1275        SubdivisionCandidate::NewMail();
[1625]1276
1277        for (sit = chosenCandidates.begin(); sit != sit_end; ++ sit)
1278        {
[1633]1279                (*sit)->CollectDirtyCandidates(dirtyList, true);
[1625]1280        }
1281}
1282
1283
[1633]1284void HierarchyManager::RepairQueue(const SubdivisionCandidateContainer &dirtyList,
1285                                                                   SplitQueue &splitQueue,
1286                                                                   const bool recomputeSplitPlaneOnRepair)
[1625]1287{
[1237]1288        // for each update of the view space partition:
1289        // the candidates from object space partition which
1290        // have been afected by the view space split (the kd split candidates
1291        // which saw the view cell which was split) must be reevaluated
1292        // (maybe not locally, just reinsert them into the queue)
1293        //
1294        // vice versa for the view cells
1295        // for each update of the object space partition
1296        // reevaluate split candidate for view cells which saw the split kd cell
1297        //
1298        // the priority queue update can be solved by implementing a binary heap
1299        // (explicit data structure, binary tree)
1300        // *) inserting and removal is efficient
1301        // *) search is not efficient => store queue position with each
1302        // split candidate
1303
1304        // collect list of "dirty" candidates
[1580]1305        const long startTime = GetTime();
[1625]1306        if (0) cout << "repairing " << (int)dirtyList.size() << " candidates ... ";
[1313]1307       
[1624]1308
[1684]1309        ///////////////////////////
[1305]1310        //-- reevaluate the dirty list
[1415]1311
[1313]1312        SubdivisionCandidateContainer::const_iterator sit, sit_end = dirtyList.end();
[1302]1313       
[1237]1314        for (sit = dirtyList.begin(); sit != sit_end; ++ sit)
1315        {
1316                SubdivisionCandidate* sc = *sit;
[1305]1317                const float rcd = sc->GetRenderCostDecrease();
[1302]1318               
[1667]1319                // erase from queue
1320                splitQueue.Erase(sc);
1321                // reevaluate candidate
1322                sc->EvalCandidate(recomputeSplitPlaneOnRepair);
1323                 // reinsert
1324                splitQueue.Push(sc);
1325
1326                cout << ".";
1327
[1580]1328#ifdef _DEBUG
[1305]1329                Debug << "candidate " << sc << " reevaluated\n"
1330                          << "render cost decrease diff " <<  rcd - sc->GetRenderCostDecrease()
[1580]1331                          << " old: " << rcd << " new " << sc->GetRenderCostDecrease() << endl;
1332#endif 
[1237]1333        }
[1313]1334
[1625]1335        const long endTime = GetTime();
1336        const Real timeDiff = TimeDiff(startTime, endTime);
1337
[1624]1338        mHierarchyStats.mRepairTime += timeDiff;
[1313]1339
[1633]1340        if (0) cout << "repaired in " << timeDiff * 1e-3f << " secs" << endl;
[1237]1341}
1342
[1259]1343
[1640]1344void HierarchyManager::ResetQueue(SplitQueue &splitQueue, const bool recomputeSplitPlane)
[1313]1345{
1346        SubdivisionCandidateContainer mCandidateBuffer;
1347
1348        // remove from queue
[1640]1349        while (!splitQueue.Empty())
[1313]1350        {
[1640]1351                SubdivisionCandidate *candidate = NextSubdivisionCandidate(splitQueue);
[1625]1352                 // reevaluate local split plane and priority
[1667]1353                candidate->EvalCandidate(recomputeSplitPlane);
[1313]1354                cout << ".";
1355                mCandidateBuffer.push_back(candidate);
1356        }
1357
1358        // put back into queue
1359        SubdivisionCandidateContainer::const_iterator sit, sit_end = mCandidateBuffer.end();
1360    for (sit = mCandidateBuffer.begin(); sit != sit_end; ++ sit)
[1580]1361        {
[1640]1362                splitQueue.Push(*sit);
[1313]1363        }
1364}
1365
1366
[1279]1367void HierarchyManager::ExportObjectSpaceHierarchy(OUT_STREAM &stream)
1368{
1369        // the type of the view cells hierarchy
[1308]1370        switch (mObjectSpaceSubdivisionType)
[1279]1371        {
1372        case KD_BASED_OBJ_SUBDIV:
1373                stream << "<ObjectSpaceHierarchy type=\"osp\">" << endl;
1374                mOspTree->Export(stream);
1375                stream << endl << "</ObjectSpaceHierarchy>" << endl;
[1305]1376                break;         
[1279]1377        case BV_BASED_OBJ_SUBDIV:
1378                stream << "<ObjectSpaceHierarchy type=\"bvh\">" << endl;
1379                mBvHierarchy->Export(stream);
1380                stream << endl << "</ObjectSpaceHierarchy>" << endl;
1381                break;
1382        }
1383}
1384
1385
1386bool HierarchyManager::AddSampleToPvs(Intersectable *obj,
1387                                                                          const Vector3 &hitPoint,
1388                                                                          ViewCell *vc,
1389                                                                          const float pdf,
1390                                                                          float &contribution) const
1391{
1392        if (!obj) return false;
1393
[1308]1394        switch (mObjectSpaceSubdivisionType)
[1279]1395        {
1396        case NO_OBJ_SUBDIV:
[1486]1397                {
1398                        // potentially visible objects
1399                        return vc->AddPvsSample(obj, pdf, contribution);
1400                }
[1279]1401        case KD_BASED_OBJ_SUBDIV:
1402                {
1403                        // potentially visible kd cells
1404                        KdLeaf *leaf = mOspTree->GetLeaf(hitPoint/*ray->mOriginNode*/);
1405                        return mOspTree->AddLeafToPvs(leaf, vc, pdf, contribution);
1406                }
1407        case BV_BASED_OBJ_SUBDIV:
1408                {
1409                        BvhLeaf *leaf = mBvHierarchy->GetLeaf(obj);
[1370]1410                        BvhIntersectable *bvhObj = mBvHierarchy->GetOrCreateBvhIntersectable(leaf);
1411                       
1412                        return vc->AddPvsSample(bvhObj, pdf, contribution);
[1279]1413                }
1414        default:
1415                return false;
1416        }
1417}
1418
1419
[1421]1420void HierarchyManager::PrintHierarchyStatistics(ostream &stream) const
[1279]1421{
[1313]1422        stream << mHierarchyStats << endl;
1423        stream << "\nview space:" << endl << endl;
1424        stream << mVspTree->GetStatistics() << endl;
1425        stream << "\nobject space:" << endl << endl;
[1370]1426
[1308]1427        switch (mObjectSpaceSubdivisionType)
[1279]1428        {
1429        case KD_BASED_OBJ_SUBDIV:
1430                {
[1313]1431                        stream << mOspTree->GetStatistics() << endl;
[1279]1432                        break;
1433                }
1434        case BV_BASED_OBJ_SUBDIV:
1435                {
[1313]1436                        stream << mBvHierarchy->GetStatistics() << endl;
[1279]1437                        break;
1438                }
1439        default:
1440                break;
1441        }
1442}
1443
1444
[1287]1445void HierarchyManager::ExportObjectSpaceHierarchy(Exporter *exporter,
[1416]1446                                                                                                  const ObjectContainer &objects,
[1418]1447                                                                                                  const AxisAlignedBox3 *bbox,
1448                                                                                                  const bool exportBounds) const
[1279]1449{
[1308]1450        switch (mObjectSpaceSubdivisionType)
[1286]1451        {
1452        case KD_BASED_OBJ_SUBDIV:
[1279]1453                {
[1287]1454                        ExportOspTree(exporter, objects);
[1286]1455                        break;
1456                }
1457        case BV_BASED_OBJ_SUBDIV:
1458                {
[1418]1459                        exporter->ExportBvHierarchy(*mBvHierarchy, 0, bbox, exportBounds);
[1286]1460                        break;
1461                }
1462        default:
1463                break;
1464        }
1465}
[1279]1466
[1286]1467
[1287]1468void HierarchyManager::ExportOspTree(Exporter *exporter,
1469                                                                         const ObjectContainer &objects) const
[1286]1470{
[1287]1471        if (0) exporter->ExportGeometry(objects);
[1279]1472                       
[1287]1473        exporter->SetWireframe();
1474        exporter->ExportOspTree(*mOspTree, 0);
[1286]1475}
1476
1477
[1418]1478Intersectable *HierarchyManager::GetIntersectable(const VssRay &ray,
1479                                                                                                  const bool isTermination) const
1480{
1481
1482        Intersectable *obj;
1483        Vector3 pt;
1484        KdNode *node;
1485
1486        ray.GetSampleData(isTermination, pt, &obj, &node);
1487       
1488        if (!obj) return NULL;
1489
1490        switch (mObjectSpaceSubdivisionType)
1491        {
1492        case HierarchyManager::KD_BASED_OBJ_SUBDIV:
1493                {
1494                        KdLeaf *leaf = mOspTree->GetLeaf(pt, node);
1495                        return mOspTree->GetOrCreateKdIntersectable(leaf);
1496                }
1497        case HierarchyManager::BV_BASED_OBJ_SUBDIV:
1498                {
1499                        BvhLeaf *leaf = mBvHierarchy->GetLeaf(obj);
1500                        return mBvHierarchy->GetOrCreateBvhIntersectable(leaf);
1501                }
1502        default:
1503                return obj;
1504        }
1505}
1506
1507
[1313]1508void HierarchyStatistics::Print(ostream &app) const
1509{
1510        app << "=========== Hierarchy statistics ===============\n";
1511
1512        app << setprecision(4);
1513
1514        app << "#N_CTIME  ( Construction time [s] )\n" << Time() << " \n";
1515       
[1624]1516        app << "#N_RTIME  ( Repair time [s] )\n" << mRepairTime * 1e-3f << " \n";
[1313]1517
[1624]1518        app << "#N_NODES ( Number of nodes )\n" << mNodes << "\n";
[1313]1519
1520        app << "#N_INTERIORS ( Number of interior nodes )\n" << Interior() << "\n";
1521
1522        app << "#N_LEAVES ( Number of leaves )\n" << Leaves() << "\n";
1523
[1624]1524        app << "#N_PMAXDEPTH ( Maximal reached depth )\n" << mMaxDepth << endl;
[1449]1525
1526        app << "#N_GLOBALCOSTMISSES ( Global cost misses )\n" << mGlobalCostMisses << endl;
[1313]1527       
1528        app << "========== END OF Hierarchy statistics ==========\n";
1529}
1530
1531
[1418]1532static void RemoveRayRefs(const ObjectContainer &objects)
[1370]1533{
[1418]1534        ObjectContainer::const_iterator oit, oit_end = objects.end();
1535        for (oit = objects.begin(); oit != oit_end; ++ oit)
1536        {
[1696]1537                (*oit)->DelRayRefs();
[1418]1538        }
1539}
1540
1541
[1679]1542void HierarchyManager::FinishObjectSpaceSubdivision(const ObjectContainer &objects,
1543                                                                                                        const bool removeRayRefs) const
[1418]1544{
[1370]1545        switch (mObjectSpaceSubdivisionType)
1546        {
1547        case KD_BASED_OBJ_SUBDIV:
1548                {
1549                        mOspTree->mOspStats.Stop();
1550                        break;
1551                }
1552        case BV_BASED_OBJ_SUBDIV:
1553                {
1554                        mBvHierarchy->mBvhStats.Stop();
[1649]1555                        if (removeRayRefs)
1556                                RemoveRayRefs(objects);
[1370]1557                        break;
1558                }
1559        default:
1560                break;
1561        }
1562}
1563
[1614]1564
1565void HierarchyManager::ExportBoundingBoxes(OUT_STREAM &stream, const ObjectContainer &objects)
1566{
1567        stream << "<BoundingBoxes>" << endl;
1568           
1569        if (mObjectSpaceSubdivisionType == KD_BASED_OBJ_SUBDIV)
1570        {
1571                KdIntersectableMap::const_iterator kit, kit_end = mOspTree->mKdIntersectables.end();
1572
1573                int id = 0;
1574                for (kit = mOspTree->mKdIntersectables.begin(); kit != kit_end; ++ kit, ++ id)
1575                {
1576                        Intersectable *obj = (*kit).second;
1577                        const AxisAlignedBox3 box = obj->GetBox();
1578               
1579                        obj->SetId(id);
1580
1581                        stream << "<BoundingBox" << " id=\"" << id << "\""
1582                                   << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
1583                                   << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\" />" << endl;
1584                }
1585        }
1586        else
1587        {
1588                ObjectContainer::const_iterator oit, oit_end = objects.end();
1589
1590                for (oit = objects.begin(); oit != oit_end; ++ oit)
1591                {
1592                        const AxisAlignedBox3 box = (*oit)->GetBox();
1593               
1594                        stream << "<BoundingBox" << " id=\"" << (*oit)->GetId() << "\""
1595                                   << " min=\"" << box.Min().x << " " << box.Min().y << " " << box.Min().z << "\""
1596                                   << " max=\"" << box.Max().x << " " << box.Max().y << " " << box.Max().z << "\" />" << endl;
1597                }
1598        }
1599               
1600        stream << "</BoundingBoxes>" << endl;
1601}
1602
[1680]1603
1604static void UpdateStats(ofstream &stats,
1605                                                const int splits,
1606                                                const float totalRenderCost,
1607                                                const int entriesInPvs,
1608                                                const float memoryCost,
1609                                                const bool vsp)
1610{
1611        stats << "#Pass\n" << 0 << endl
1612                   << "#Splits\n" << splits << endl
1613                   << "#TotalRenderCost\n" << totalRenderCost << endl
1614                   << "#TotalEntriesInPvs\n" << entriesInPvs << endl
1615                   << "#Memory\n" << memoryCost << endl
1616                   << "#Vsp\n" << (vsp ? 1 : 0) << endl
1617                   << endl;
1618}
1619
1620
[1706]1621class HierarchyNodeWrapper;
1622
1623
1624template <typename T> class myless
1625{
1626public:
1627        bool operator() (T v1, T v2) const
1628        {
1629                return (v1->GetMergeCost() < v2->GetMergeCost());
1630        }
1631};
1632
[1709]1633
[1706]1634typedef priority_queue<HierarchyNodeWrapper *, vector<HierarchyNodeWrapper *>,
1635                                           myless<vector<HierarchyNodeWrapper *>::value_type> > HierarchyNodeQueue;
1636
1637class HierarchyNodeWrapper
1638{
1639public:
[1707]1640        enum {VSP_NODE, BVH_NODE, VIEW_CELL};
[1706]1641
1642        virtual float GetMergeCost() const = 0;
1643        virtual int Type() const  = 0;
1644        virtual bool IsLeaf() const = 0;
1645
1646        virtual void PushChildren(HierarchyNodeQueue &tQueue) = 0;
1647};
1648
1649
1650class VspNodeWrapper: public HierarchyNodeWrapper
1651{
1652public:
1653        VspNodeWrapper(VspNode *node): mNode(node) {}
1654
1655        int Type() const { return VSP_NODE; }
1656
1657        float GetMergeCost() const { return (float) -mNode->mTimeStamp; };
1658
1659        bool IsLeaf() const { return mNode->IsLeaf(); }
1660
1661        void PushChildren(HierarchyNodeQueue &tQueue)
1662        {
1663                if (!mNode->IsLeaf())
1664                {
1665                        VspInterior *interior = dynamic_cast<VspInterior *>(mNode);
1666
1667                        tQueue.push(new VspNodeWrapper(interior->GetFront()));
1668                        tQueue.push(new VspNodeWrapper(interior->GetBack()));
1669                }
1670        }
1671
1672        VspNode *mNode;
1673};
1674
1675
1676class BvhNodeWrapper: public HierarchyNodeWrapper
1677{
1678public:
1679        BvhNodeWrapper(BvhNode *node): mNode(node) {}
[1686]1680       
[1706]1681        int Type()  const { return BVH_NODE; }
1682
1683        float GetMergeCost() const { return (float)-mNode->mTimeStamp; };
1684
1685        bool IsLeaf() const { return mNode->IsLeaf(); }
1686
1687        void PushChildren(HierarchyNodeQueue &tQueue)
1688        {
1689                if (!mNode->IsLeaf())
1690                {
1691                        BvhInterior *interior = dynamic_cast<BvhInterior *>(mNode);
1692
1693                        tQueue.push(new BvhNodeWrapper(interior->GetFront()));
1694                        tQueue.push(new BvhNodeWrapper(interior->GetBack()));
1695                }
1696        }
1697
1698        BvhNode *mNode;
1699};
1700
1701
[1707]1702class ViewCellWrapper: public HierarchyNodeWrapper
1703{
1704public:
1705
1706        ViewCellWrapper(ViewCell *vc): mViewCell(vc) {}
1707       
1708        int Type()  const { return VIEW_CELL; }
1709
1710        float GetMergeCost() const { return mViewCell->GetMergeCost(); };
1711
1712        bool IsLeaf() const { return mViewCell->IsLeaf(); }
1713
1714        void PushChildren(HierarchyNodeQueue &tQueue)
1715        {
1716                if (!mViewCell->IsLeaf())
1717                {
1718                        ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(mViewCell);
1719
1720                        ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
1721
1722                        for (it = interior->mChildren.begin(); it != it_end; ++ it)
1723                        {
1724                                tQueue.push(new ViewCellWrapper(*it));
1725                        }
1726                }
1727        }
1728
1729        ViewCell *mViewCell;
1730};
1731
1732
[1706]1733void HierarchyManager::CollectBestSet(const int maxSplits,
1734                                                                          const float maxMemoryCost,
[1707]1735                                                                          ViewCellContainer &viewCells,
[1706]1736                                                                          vector<BvhNode *> &bvhNodes)
1737{
1738        HierarchyNodeQueue tqueue;
[1707]1739        //tqueue.push(new VspNodeWrapper(mVspTree->GetRoot()));
1740        tqueue.push(new ViewCellWrapper(mVspTree->mViewCellsTree->GetRoot()));
[1706]1741        tqueue.push(new BvhNodeWrapper(mBvHierarchy->GetRoot()));
1742       
1743        float memCost = 0;
1744
1745        while (!tqueue.empty())
1746        {
1747                HierarchyNodeWrapper *nodeWrapper = tqueue.top();
1748                tqueue.pop();
1749
1750                // save the view cells if it is a leaf or if enough view cells have already been traversed
1751                // because of the priority queue, this will be the optimal set of v
1752                if (nodeWrapper->IsLeaf() ||
[1707]1753                        ((viewCells.size() + bvhNodes.size() + tqueue.size() + 1) >= maxSplits) ||
[1706]1754                        (memCost > maxMemoryCost)
1755                        )
1756                {
1757                        if (nodeWrapper->Type() == HierarchyNodeWrapper::VSP_NODE)
1758                        {
[1707]1759                                ViewCellWrapper *viewCellWrapper = dynamic_cast<ViewCellWrapper *>(nodeWrapper);
1760                                viewCells.push_back(viewCellWrapper->mViewCell);
[1706]1761                        }
1762                        else
1763                        {
1764                                BvhNodeWrapper *bvhNodeWrapper = dynamic_cast<BvhNodeWrapper *>(nodeWrapper);
1765                                bvhNodes.push_back(bvhNodeWrapper->mNode);
1766                        }
1767                }
1768                else
1769                {       
1770                        nodeWrapper->PushChildren(tqueue);
1771                }
1772
1773                delete nodeWrapper;
1774        }
1775}
1776
1777
[1709]1778bool HierarchyManager::ExtractStatistics(const int maxSplits,
[1706]1779                                                                                 const float maxMemoryCost,
1780                                                                                 float &renderCost,
1781                                                                                 float &memory,
1782                                                                                 int &pvsEntries)
1783{
[1707]1784        ViewCellContainer viewCells;
1785        vector<BvhNode *> bvhNodes;
1786
[1709]1787        // collect best set of view cells for this #splits
[1707]1788    CollectBestSet(maxSplits, maxMemoryCost, viewCells, bvhNodes);
1789
1790        vector<BvhNode *>::const_iterator bit, bit_end = bvhNodes.end();
1791       
1792        for (bit = bvhNodes.begin(); bit != bit_end; ++ bit)
1793        {
1794                mBvHierarchy->SetActive(*bit);
1795        }
1796
1797        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
1798
1799        int numEntries = 0;
1800        float pvsCost = 0.0f;
1801
1802        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
1803        {
1804                ViewCell *vc = *vit;
1805                ObjectPvs pvs;
1806                mVspTree->mViewCellsTree->GetPvs(vc, pvs);
1807
1808                BvhNode::NewMail();
1809
1810                // hack: should not be done here
1811                ObjectPvsMap::const_iterator oit, oit_end = pvs.mEntries.end();
1812
1813                for (oit = pvs.mEntries.begin(); oit != oit_end; ++ oit)
1814                {
1815                        BvhIntersectable *intersect = dynamic_cast<BvhIntersectable *>((*oit).first);
1816                        BvhLeaf *leaf = intersect->GetItem();
1817                        BvhNode *activeNode = leaf->GetActiveNode();
1818
1819                        if (!activeNode->Mailed())
1820                        {
1821                                activeNode->Mail();
1822
1823                                ++ numEntries;
1824                                pvsCost += mBvHierarchy->EvalAbsCost(leaf->mObjects);
1825                        }
1826                }
1827        }
1828
[1710]1829        return ((int)(viewCells.size() + bvhNodes.size()) < mHierarchyStats.Leaves());
[1709]1830}
[1706]1831
1832
[1709]1833void HierarchyManager::ExportStats(ofstream &stats,
1834                                                                   SplitQueue &tQueue,
1835                                                                   const ObjectContainer &objects)
1836{
1837        float totalRenderCost = (float)objects.size();
1838        int entriesInPvs = 1;
1839        int steps = 0;
[1706]1840
[1709]1841        cout << "exporting vsposp stats ... " << endl;
1842        const float memoryCost = (float)entriesInPvs * (float)ObjectPvs::GetEntrySize();
[1706]1843
1844        /////////////
1845        //-- first view cell
1846
[1709]1847        UpdateStats(stats, 2, totalRenderCost, entriesInPvs, memoryCost, true);
[1706]1848
1849        //-- go through tree in the order of render cost decrease
1850        //-- which is the same order as the view cells were merged
1851        //-- or the reverse order of subdivision for subdivision-only
1852        //-- view cell hierarchies.
[1709]1853       
1854        while (!tQueue.Empty())
[1706]1855        {
[1709]1856                SubdivisionCandidate *nextCandidate = NextSubdivisionCandidate(tQueue);
1857                bool isLeaf;
1858                int timeStamp;
1859                float rcDecr;
1860                int entriesIncr;
[1706]1861
[1709]1862        if (nextCandidate->Type() == SubdivisionCandidate::VIEW_SPACE)
1863                {
1864                        timeStamp = (int)-nextCandidate->GetPriority();
[1706]1865
[1709]1866                        VspNode *newNode = mVspTree->SubdivideAndCopy(tQueue, nextCandidate);
1867                        VspNode *oldNode = (VspNode *)nextCandidate->mEvaluationHack;
1868                       
1869                        isLeaf = newNode->IsLeaf();
1870                        rcDecr = oldNode->mRenderCostDecr;
1871                        entriesIncr = oldNode->mPvsEntriesIncr;
1872                }
1873                else
1874                {
1875                        timeStamp = (int)-nextCandidate->GetPriority();
1876                       
1877                        BvhNode *newNode = mBvHierarchy->SubdivideAndCopy(tQueue, nextCandidate);
1878                        BvhNode *oldNode = (BvhNode *)nextCandidate->mEvaluationHack;
1879                       
1880                        isLeaf = newNode->IsLeaf();
1881                        rcDecr = oldNode->mRenderCostDecr;
1882                        entriesIncr = oldNode->mPvsEntriesIncr;
1883                }               
1884                               
1885                if (!isLeaf)
1886                {
1887                        totalRenderCost -= rcDecr;
1888                        entriesInPvs += entriesIncr;
1889                        // if (rcDecr <= 0)
1890                        if (nextCandidate->Type() == SubdivisionCandidate::VIEW_SPACE)
1891                                cout << "v";//cout << "vsp t: " << timeStamp << " rc: " << rcDecr << " pvs: " << entriesIncr << endl;
1892                        else
1893                                cout << "o";//"osp t: " << timeStamp << " rc: " << rcDecr << " pvs: " << entriesIncr << endl;
[1706]1894
[1709]1895                        ++ steps;
[1706]1896
[1709]1897                        if ((steps % 500) == 499)
1898                                cout << steps << " steps taken" << endl;
1899                        const float memoryCost = (float)entriesInPvs * (float)ObjectPvs::GetEntrySize();
1900                        UpdateStats(stats, steps, totalRenderCost, entriesInPvs, memoryCost, false);
1901                }
[1706]1902
[1709]1903                DEL_PTR(nextCandidate);
1904        }
[1706]1905
[1709]1906        stats.close();
1907}
[1706]1908
1909
[1709]1910void HierarchyManager::EvaluateSubdivision(const VssRayContainer &sampleRays,                                                                                                                                             
1911                                                                                   const ObjectContainer &objects,
1912                                                                                   const string &filename)
1913{
1914        VspTree *oldVspTree = mVspTree;
1915        ViewCellsManager *vm = mVspTree->mViewCellsManager;
1916        BvHierarchy *oldHierarchy = mBvHierarchy;
[1706]1917
[1709]1918        mBvHierarchy = new BvHierarchy();
1919        mBvHierarchy->mHierarchyManager = this;
1920        mBvHierarchy->mViewCellsManager = vm;
[1706]1921
[1709]1922        mVspTree = new VspTree();
1923        mVspTree->mHierarchyManager = this;
1924        mVspTree->mViewCellsManager = vm;
[1706]1925
[1709]1926        // create first nodes
1927        mVspTree->Initialise(sampleRays, &oldVspTree->mBoundingBox);
1928        InitialiseObjectSpaceSubdivision(objects);
[1706]1929
[1709]1930        const long startTime = GetTime();
1931        cout << "Constructing evaluation hierarchies ... \n";
1932       
1933        ofstream stats;
1934        stats.open(filename.c_str());
1935        SplitQueue tQueue;
[1706]1936
[1709]1937        BvhNode *oldBvhRoot = oldHierarchy->GetRoot();
1938        VspNode *oldVspRoot = oldVspTree->GetRoot();
[1706]1939
[1709]1940        RayInfoContainer *viewSpaceRays = new RayInfoContainer();
1941       
1942        SubdivisionCandidate *firstVsp = mVspTree->PrepareConstruction(sampleRays, *viewSpaceRays);
1943        SubdivisionCandidate *firstBvh = mBvHierarchy->PrepareConstruction(sampleRays, objects);
1944
1945    firstVsp->mEvaluationHack = oldVspRoot;
1946        firstBvh->mEvaluationHack = oldBvhRoot;
1947
1948        firstVsp->SetPriority((float)-oldVspRoot->mTimeStamp);
1949        firstBvh->SetPriority((float)-oldBvhRoot->mTimeStamp);
1950
1951        tQueue.Push(firstVsp);
1952        tQueue.Push(firstBvh);
1953
1954        ExportStats(stats, tQueue, objects);
1955
1956        cout << "\nfinished in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
1957        RemoveRayRefs(objects);
1958
1959        // view cells needed only for evaluation
1960        ViewCellContainer viewCells;
1961        mVspTree->CollectViewCells(viewCells, false);
1962       
1963        // helper trees can be destroyed
1964        DEL_PTR(mVspTree);
1965        DEL_PTR(mBvHierarchy);
1966
1967        CLEAR_CONTAINER(viewCells);
1968
1969        // reset hierarchies
1970        mVspTree = oldVspTree;
1971        mBvHierarchy = oldHierarchy;
1972
1973        // reinstall old bv refs
1974        vector<BvhLeaf *> leaves;
1975        mBvHierarchy->CollectLeaves(mBvHierarchy->GetRoot(), leaves);
1976        vector<BvhLeaf *>::const_iterator bit, bit_end = leaves.end();
1977
1978        for (bit = leaves.begin(); bit != bit_end; ++ bit)
1979        {
1980                mBvHierarchy->AssociateObjectsWithLeaf(*bit);
[1706]1981        }
[1709]1982}
[1706]1983
[1709]1984
1985void HierarchyManager::EvaluateSubdivision2(ofstream &splitsStats,
1986                                                                                        ofstream &memStats,
1987                                                                                        const int splitsStepSize,
1988                                                                                        const float memStepSize)
1989{
1990        int splits = 0;
1991        float mem = 15;
1992
1993        float renderCost;
1994        float memory;
1995        int pvsEntries;
1996
1997        while (1)
1998        {
[1710]1999                if (!ExtractStatistics(splits, 99999.0, renderCost, memory, pvsEntries))
[1709]2000                        break;
2001
2002                UpdateStats(splitsStats, splits, renderCost, pvsEntries, memory, 0);
2003
[1710]2004                splits += splitsStepSize;
[1709]2005        }
2006
2007        while (1)
2008        {
2009                if (!ExtractStatistics(99999999, mem, renderCost, memory, pvsEntries))
2010                        break;
2011
2012                UpdateStats(splitsStats, splits, renderCost, pvsEntries, memory, 0);
2013
[1710]2014                mem += memStepSize;
[1709]2015        }
2016
[1706]2017}
[1709]2018
[1237]2019}
Note: See TracBrowser for help on using the repository browser.