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

Revision 1707, 57.9 KB checked in by mattausch, 18 years ago (diff)

worked on full render cost evaluation
warning: some change sin render cost evaluation for pvs which could have bugs

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
[1692]1621void HierarchyManager::EvaluateSubdivision(const VssRayContainer &sampleRays,                                                                                                                                             
1622                                                                                   const ObjectContainer &objects,
[1686]1623                                                                                   const string &filename)
[1680]1624{
1625        VspTree *oldVspTree = mVspTree;
[1686]1626        ViewCellsManager *vm = mVspTree->mViewCellsManager;
[1684]1627        BvHierarchy *oldHierarchy = mBvHierarchy;
[1680]1628
[1684]1629        mBvHierarchy = new BvHierarchy();
1630        mBvHierarchy->mHierarchyManager = this;
[1686]1631        mBvHierarchy->mViewCellsManager = vm;
1632
[1680]1633        mVspTree = new VspTree();
1634        mVspTree->mHierarchyManager = this;
[1686]1635        mVspTree->mViewCellsManager = vm;
[1680]1636
1637        // create first nodes
1638        mVspTree->Initialise(sampleRays, &oldVspTree->mBoundingBox);
1639        InitialiseObjectSpaceSubdivision(objects);
1640
[1686]1641        const long startTime = GetTime();
1642        cout << "Constructing evaluation hierarchies ... \n";
1643       
1644        ofstream stats;
1645        stats.open(filename.c_str());
1646        SplitQueue tQueue;
[1680]1647
[1686]1648        BvhNode *oldBvhRoot = oldHierarchy->GetRoot();
1649        VspNode *oldVspRoot = oldVspTree->GetRoot();
[1680]1650
[1686]1651        RayInfoContainer *viewSpaceRays = new RayInfoContainer();
[1680]1652       
[1686]1653        SubdivisionCandidate *firstVsp = mVspTree->PrepareConstruction(sampleRays, *viewSpaceRays);
1654        SubdivisionCandidate *firstBvh = mBvHierarchy->PrepareConstruction(sampleRays, objects);
[1680]1655
[1686]1656    firstVsp->mEvaluationHack = oldVspRoot;
1657        firstBvh->mEvaluationHack = oldBvhRoot;
[1680]1658
[1687]1659        firstVsp->SetPriority((float)-oldVspRoot->mTimeStamp);
1660        firstBvh->SetPriority((float)-oldBvhRoot->mTimeStamp);
1661
[1686]1662        tQueue.Push(firstVsp);
1663        tQueue.Push(firstBvh);
[1680]1664
[1686]1665        ExportStats(stats, tQueue, objects);
[1680]1666
[1686]1667        cout << "\nfinished in " << TimeDiff(startTime, GetTime()) * 1e-3 << " secs" << endl;
1668        RemoveRayRefs(objects);
[1680]1669
[1686]1670        // view cells needed only for evaluation
1671        ViewCellContainer viewCells;
1672        mVspTree->CollectViewCells(viewCells, false);
[1692]1673       
[1686]1674        // helper trees can be destroyed
1675        DEL_PTR(mVspTree);
1676        DEL_PTR(mBvHierarchy);
[1684]1677
[1692]1678        CLEAR_CONTAINER(viewCells);
1679
[1686]1680        // reset hierarchies
1681        mVspTree = oldVspTree;
1682        mBvHierarchy = oldHierarchy;
[1684]1683
[1686]1684        // reinstall old bv refs
1685        vector<BvhLeaf *> leaves;
[1707]1686        mBvHierarchy->CollectLeaves(mBvHierarchy->GetRoot(), leaves);
[1686]1687        vector<BvhLeaf *>::const_iterator bit, bit_end = leaves.end();
[1680]1688
[1686]1689        for (bit = leaves.begin(); bit != bit_end; ++ bit)
1690        {
1691                mBvHierarchy->AssociateObjectsWithLeaf(*bit);
1692        }
1693}
[1680]1694
[1686]1695
1696void HierarchyManager::ExportStats(ofstream &stats,
1697                                                                   SplitQueue &tQueue,
1698                                                                   const ObjectContainer &objects)
1699{
1700        float totalRenderCost = (float)objects.size();
1701        int entriesInPvs = 1;
1702        int steps = 0;
1703
[1680]1704        cout << "exporting vsposp stats ... " << endl;
1705        const float memoryCost = (float)entriesInPvs * (float)ObjectPvs::GetEntrySize();
1706
1707        /////////////
1708        //-- first view cell
[1684]1709        UpdateStats(stats, 2, totalRenderCost, entriesInPvs, memoryCost, true);
[1680]1710
1711        //-- go through tree in the order of render cost decrease
1712        //-- which is the same order as the view cells were merged
1713        //-- or the reverse order of subdivision for subdivision-only
1714        //-- view cell hierarchies.
[1686]1715       
[1684]1716        while (!tQueue.Empty())
1717        {
1718                SubdivisionCandidate *nextCandidate = NextSubdivisionCandidate(tQueue);
[1692]1719                bool isLeaf;
1720                int timeStamp;
1721                float rcDecr;
1722                int entriesIncr;
[1684]1723
[1687]1724        if (nextCandidate->Type() == SubdivisionCandidate::VIEW_SPACE)
1725                {
[1692]1726                        timeStamp = (int)-nextCandidate->GetPriority();
[1687]1727
[1692]1728                        VspNode *newNode = mVspTree->SubdivideAndCopy(tQueue, nextCandidate);
[1687]1729                        VspNode *oldNode = (VspNode *)nextCandidate->mEvaluationHack;
1730                       
[1692]1731                        isLeaf = newNode->IsLeaf();
1732                        rcDecr = oldNode->mRenderCostDecr;
1733                        entriesIncr = oldNode->mPvsEntriesIncr;
[1687]1734                }
[1686]1735                else
[1692]1736                {
1737                        timeStamp = (int)-nextCandidate->GetPriority();
[1687]1738                       
[1692]1739                        BvhNode *newNode = mBvHierarchy->SubdivideAndCopy(tQueue, nextCandidate);
[1687]1740                        BvhNode *oldNode = (BvhNode *)nextCandidate->mEvaluationHack;
1741                       
[1692]1742                        isLeaf = newNode->IsLeaf();
1743                        rcDecr = oldNode->mRenderCostDecr;
1744                        entriesIncr = oldNode->mPvsEntriesIncr;
[1687]1745                }               
[1692]1746                               
1747                if (!isLeaf)
1748                {
1749                        totalRenderCost -= rcDecr;
1750                        entriesInPvs += entriesIncr;
1751                        // if (rcDecr <= 0)
1752                        if (nextCandidate->Type() == SubdivisionCandidate::VIEW_SPACE)
1753                                cout << "v";//cout << "vsp t: " << timeStamp << " rc: " << rcDecr << " pvs: " << entriesIncr << endl;
1754                        else
1755                                cout << "o";//"osp t: " << timeStamp << " rc: " << rcDecr << " pvs: " << entriesIncr << endl;
[1686]1756
[1692]1757                        ++ steps;
[1684]1758
[1692]1759                        if ((steps % 500) == 499)
1760                                cout << steps << " steps taken" << endl;
1761                        const float memoryCost = (float)entriesInPvs * (float)ObjectPvs::GetEntrySize();
1762                        UpdateStats(stats, steps, totalRenderCost, entriesInPvs, memoryCost, false);
1763                }
1764
1765                DEL_PTR(nextCandidate);
[1684]1766        }
[1686]1767
[1684]1768        stats.close();
1769}
1770
[1706]1771
1772
1773class HierarchyNodeWrapper;
1774
1775
1776template <typename T> class myless
1777{
1778public:
1779        bool operator() (T v1, T v2) const
1780        {
1781                return (v1->GetMergeCost() < v2->GetMergeCost());
1782        }
1783};
1784
1785typedef priority_queue<HierarchyNodeWrapper *, vector<HierarchyNodeWrapper *>,
1786                                           myless<vector<HierarchyNodeWrapper *>::value_type> > HierarchyNodeQueue;
1787
1788class HierarchyNodeWrapper
1789{
1790public:
[1707]1791        enum {VSP_NODE, BVH_NODE, VIEW_CELL};
[1706]1792
1793        virtual float GetMergeCost() const = 0;
1794        virtual int Type() const  = 0;
1795        virtual bool IsLeaf() const = 0;
1796
1797        virtual void PushChildren(HierarchyNodeQueue &tQueue) = 0;
1798};
1799
1800
1801class VspNodeWrapper: public HierarchyNodeWrapper
1802{
1803public:
1804        VspNodeWrapper(VspNode *node): mNode(node) {}
1805
1806        int Type() const { return VSP_NODE; }
1807
1808        float GetMergeCost() const { return (float) -mNode->mTimeStamp; };
1809
1810        bool IsLeaf() const { return mNode->IsLeaf(); }
1811
1812        void PushChildren(HierarchyNodeQueue &tQueue)
1813        {
1814                if (!mNode->IsLeaf())
1815                {
1816                        VspInterior *interior = dynamic_cast<VspInterior *>(mNode);
1817
1818                        tQueue.push(new VspNodeWrapper(interior->GetFront()));
1819                        tQueue.push(new VspNodeWrapper(interior->GetBack()));
1820                }
1821        }
1822
1823        VspNode *mNode;
1824};
1825
1826
1827class BvhNodeWrapper: public HierarchyNodeWrapper
1828{
1829public:
1830        BvhNodeWrapper(BvhNode *node): mNode(node) {}
[1686]1831       
[1706]1832        int Type()  const { return BVH_NODE; }
1833
1834        float GetMergeCost() const { return (float)-mNode->mTimeStamp; };
1835
1836        bool IsLeaf() const { return mNode->IsLeaf(); }
1837
1838        void PushChildren(HierarchyNodeQueue &tQueue)
1839        {
1840                if (!mNode->IsLeaf())
1841                {
1842                        BvhInterior *interior = dynamic_cast<BvhInterior *>(mNode);
1843
1844                        tQueue.push(new BvhNodeWrapper(interior->GetFront()));
1845                        tQueue.push(new BvhNodeWrapper(interior->GetBack()));
1846                }
1847        }
1848
1849        BvhNode *mNode;
1850};
1851
1852
[1707]1853class ViewCellWrapper: public HierarchyNodeWrapper
1854{
1855public:
1856
1857        ViewCellWrapper(ViewCell *vc): mViewCell(vc) {}
1858       
1859        int Type()  const { return VIEW_CELL; }
1860
1861        float GetMergeCost() const { return mViewCell->GetMergeCost(); };
1862
1863        bool IsLeaf() const { return mViewCell->IsLeaf(); }
1864
1865        void PushChildren(HierarchyNodeQueue &tQueue)
1866        {
1867                if (!mViewCell->IsLeaf())
1868                {
1869                        ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(mViewCell);
1870
1871                        ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
1872
1873                        for (it = interior->mChildren.begin(); it != it_end; ++ it)
1874                        {
1875                                tQueue.push(new ViewCellWrapper(*it));
1876                        }
1877                }
1878        }
1879
1880        ViewCell *mViewCell;
1881};
1882
1883
[1706]1884void HierarchyManager::CollectBestSet(const int maxSplits,
1885                                                                          const float maxMemoryCost,
[1707]1886                                //                                        vector<VspNode *> &vspNodes,
1887                                                                          ViewCellContainer &viewCells,
[1706]1888                                                                          vector<BvhNode *> &bvhNodes)
1889{
1890        HierarchyNodeQueue tqueue;
[1707]1891        //tqueue.push(new VspNodeWrapper(mVspTree->GetRoot()));
1892        tqueue.push(new ViewCellWrapper(mVspTree->mViewCellsTree->GetRoot()));
[1706]1893        tqueue.push(new BvhNodeWrapper(mBvHierarchy->GetRoot()));
1894       
1895        float memCost = 0;
1896
1897        while (!tqueue.empty())
1898        {
1899                HierarchyNodeWrapper *nodeWrapper = tqueue.top();
1900                tqueue.pop();
1901
1902                // save the view cells if it is a leaf or if enough view cells have already been traversed
1903                // because of the priority queue, this will be the optimal set of v
1904                if (nodeWrapper->IsLeaf() ||
[1707]1905                        ((viewCells.size() + bvhNodes.size() + tqueue.size() + 1) >= maxSplits) ||
[1706]1906                        (memCost > maxMemoryCost)
1907                        )
1908                {
1909                        if (nodeWrapper->Type() == HierarchyNodeWrapper::VSP_NODE)
1910                        {
[1707]1911                                ViewCellWrapper *viewCellWrapper = dynamic_cast<ViewCellWrapper *>(nodeWrapper);
1912                                viewCells.push_back(viewCellWrapper->mViewCell);
[1706]1913                        }
1914                        else
1915                        {
1916                                BvhNodeWrapper *bvhNodeWrapper = dynamic_cast<BvhNodeWrapper *>(nodeWrapper);
1917                                bvhNodes.push_back(bvhNodeWrapper->mNode);
1918                        }
1919                }
1920                else
1921                {       
1922                        nodeWrapper->PushChildren(tqueue);
1923                }
1924
1925                delete nodeWrapper;
1926        }
1927}
1928
1929
1930void HierarchyManager::ExtractStatistics(const int maxSplits,
1931                                                                                 const float maxMemoryCost,
1932                                                                                 float &renderCost,
1933                                                                                 float &memory,
1934                                                                                 int &pvsEntries)
1935{
[1707]1936        //vector<VspNode *> vspNodes;
1937        ViewCellContainer viewCells;
1938        vector<BvhNode *> bvhNodes;
1939
1940    CollectBestSet(maxSplits, maxMemoryCost, viewCells, bvhNodes);
1941
1942        vector<BvhNode *>::const_iterator bit, bit_end = bvhNodes.end();
1943       
1944        for (bit = bvhNodes.begin(); bit != bit_end; ++ bit)
1945        {
1946                mBvHierarchy->SetActive(*bit);
1947        }
1948
1949        //vector<VspNode *>::const_iterator vit, vit_end = vspNodes.end();
1950
1951        ViewCellContainer::const_iterator vit, vit_end = viewCells.end();
1952
1953        int numEntries = 0;
1954        float pvsCost = 0.0f;
1955
1956        for (vit = viewCells.begin(); vit != vit_end; ++ vit)
1957        {
1958                ViewCell *vc = *vit;
1959                ObjectPvs pvs;
1960                mVspTree->mViewCellsTree->GetPvs(vc, pvs);
1961
1962                BvhNode::NewMail();
1963
1964                // hack: should not be done here
1965                ObjectPvsMap::const_iterator oit, oit_end = pvs.mEntries.end();
1966
1967                for (oit = pvs.mEntries.begin(); oit != oit_end; ++ oit)
1968                {
1969                        BvhIntersectable *intersect = dynamic_cast<BvhIntersectable *>((*oit).first);
1970                        BvhLeaf *leaf = intersect->GetItem();
1971                        BvhNode *activeNode = leaf->GetActiveNode();
1972
1973                        if (!activeNode->Mailed())
1974                        {
1975                                activeNode->Mail();
1976
1977                                ++ numEntries;
1978                                pvsCost += mBvHierarchy->EvalAbsCost(leaf->mObjects);
1979                        }
1980                }
1981        }
1982
[1706]1983        /*TraversalQueue tqueue;
1984        tqueue.push(mRoot);
1985
1986        //cout << "exporting stats ... " << endl;
1987        int numViewCells = 1;
1988       
1989        const AxisAlignedBox3 box = mViewCellsManager->GetViewSpaceBox();
1990        const float vol = box.GetVolume();
1991
1992        const int rootPvs = GetPvsSize(mRoot);
1993        const int rootEntries = GetPvsEntries(mRoot);
1994        float totalRenderCost, avgRenderCost, expectedCost;
1995
1996        float deviation = 0;
1997        int totalPvs = rootPvs;
1998        int entriesInPvs = rootEntries;
1999
2000        totalRenderCost = avgRenderCost = expectedCost = (float)rootPvs;
2001
2002        ofstream stats;
2003        stats.open(mergeStats.c_str());
2004
2005        const float memoryCost = (float)entriesInPvs * ObjectPvs::GetEntrySize();
2006
2007        /////////////
2008        //-- first view cell
2009
2010        UpdateStats(stats,
2011                                0,
2012                                numViewCells,
2013                                0,
2014                                totalRenderCost,
2015                                rootPvs,
2016                                expectedCost,
2017                                avgRenderCost,
2018                                deviation,
2019                                totalPvs,
2020                                entriesInPvs,
2021                                memoryCost,
2022                                0,
2023                                mRoot->GetVolume());
2024               
2025
2026        //-- go through tree in the order of render cost decrease
2027        //-- which is the same order as the view cells were merged
2028        //-- or the reverse order of subdivision for subdivision-only
2029        //-- view cell hierarchies.
2030
2031        while (!tqueue.empty())
2032        {
2033                ViewCell *vc = tqueue.top();
2034                tqueue.pop();
2035
2036                if (!vc->IsLeaf())
2037                {       
2038                        ViewCellInterior *interior = dynamic_cast<ViewCellInterior *>(vc);
2039
2040                        const int parentPvs = GetPvsSize(interior);
2041                        const int parentPvsEntries = GetPvsEntries(interior);
2042            const float parentCost = (float)parentPvs * interior->GetVolume();
2043
2044                        float childCost = 0;
2045                        int childPvs = 0;
2046                        int childPvsEntries = 0;
2047
2048                        -- numViewCells;
2049
2050                        ViewCellContainer::const_iterator it, it_end = interior->mChildren.end();
2051
2052                        for (it = interior->mChildren.begin(); it != it_end; ++ it)
2053                        {
2054                                ViewCell *vc = *it;
2055
2056                                const int pvsSize = GetPvsSize(vc);
2057                                const int pvsEntries = GetPvsEntries(vc);
2058
2059                                childCost += (float) pvsSize * vc->GetVolume();
2060                                childPvs += pvsSize;
2061                                childPvsEntries += pvsEntries;
2062
2063                                tqueue.push(vc);
2064                                ++ numViewCells;
2065                        }
2066
2067                        // update stats for this view cell
2068                        const float costDecr = (parentCost - childCost) / vol;
2069
2070                        totalRenderCost -= costDecr;
2071                        totalPvs += childPvs - parentPvs;
2072                        entriesInPvs += childPvsEntries - parentPvsEntries;
2073
2074                        expectedCost = totalRenderCost / (float)numViewCells;
2075                        avgRenderCost = (float)totalPvs / (float)numViewCells;
2076
2077                        const float memoryCost = (float)entriesInPvs * ObjectPvs::GetEntrySize();
2078
2079                        UpdateStats(stats,
2080                                                0,
2081                                                numViewCells,
2082                                                costDecr,
2083                                                totalRenderCost,
2084                                                parentPvs,
2085                                                expectedCost,
2086                                                avgRenderCost,
2087                                                deviation,
2088                        totalPvs,
2089                                                entriesInPvs,
2090                                                memoryCost,
2091                                                childPvs - parentPvs,
2092                                                vc->GetVolume());
2093                }
2094        }
2095
2096        stats.close();
2097        */
2098}
2099       
[1237]2100}
Note: See TracBrowser for help on using the repository browser.