source: trunk/VUT/GtpVisibilityPreprocessor/src/VspKdTree.h @ 412

Revision 412, 16.6 KB checked in by mattausch, 19 years ago (diff)
Line 
1// ================================================================
2// $Id$
3// ****************************************************************
4//
5// Initial coding by
6/**
7   @author Jiri Bittner
8*/
9
10#ifndef __VSPKDTREE_H__
11#define __VSPKDTREE_H__
12
13// Standard headers
14#include <iomanip>
15#include <vector>
16#include <functional>
17#include <stack>
18
19
20// User headers
21#include "VssRay.h"
22#include "AxisAlignedBox3.h"
23
24
25#define USE_KDNODE_VECTORS 1
26#define _RSS_STATISTICS
27#define _RSS_TRAVERSAL_STATISTICS
28
29
30#include "Statistics.h"
31#include "Ray.h"
32
33// --------------------------------------------------------------
34// Static statistics for kd-tree search
35// --------------------------------------------------------------
36class VspKdStatistics:  public StatisticsBase
37{
38public: 
39  // total number of nodes
40  int nodes;
41  // number of splits along each of the axes
42  int splits[7];
43  // totals number of rays
44  int rays;
45        // initial size of the pvs
46  int initialPvsSize;
47        // total number of query domains
48  int queryDomains;
49  // total number of ray references
50  int rayRefs;
51
52        // max depth nodes
53  int maxDepthNodes;
54  // max depth nodes
55  int minPvsNodes;
56  int minRaysNodes;
57        // max ray contribution nodes
58  int maxRayContribNodes;
59        // max depth nodes
60  int minSizeNodes;
61       
62  // max number of rays per node
63  int maxRayRefs;
64  // number of dynamically added ray refs
65  int addedRayRefs;
66  // number of dynamically removed ray refs
67  int removedRayRefs;
68 
69  // Constructor
70  VspKdStatistics()
71  {
72          Reset();
73  }
74
75  int Nodes() const {return nodes;}
76  int Interior() const { return nodes/2; }
77  int Leaves() const { return (nodes/2) + 1; }
78
79  void Reset()
80  {
81          nodes = 0;
82          for (int i=0; i<7; i++)
83                  splits[i] = 0;
84          rays = queryDomains = 0;
85          rayRefs = 0;
86          maxDepthNodes = 0;
87          minPvsNodes = 0;
88          minRaysNodes = 0;
89          maxRayRefs = 0;
90          addedRayRefs = removedRayRefs = 0;
91          initialPvsSize = 0;
92          maxRayContribNodes = 0;
93          minSizeNodes = 0;
94  }
95 
96  void
97  Print(ostream &app) const;
98
99  friend ostream &operator<<(ostream &s, const VspKdStatistics &stat) {
100    stat.Print(s);
101    return s;
102  }
103 
104};
105
106
107class VspKdTreeInterior;
108
109
110// --------------------------------------------------------------
111// KD-tree node - abstract class
112// --------------------------------------------------------------
113class VspKdTreeNode
114{
115public:
116
117#define USE_FIXEDPOINT_T 1
118
119struct RayInfo
120{
121        // pointer to the actual ray
122        VssRay *mRay;
123       
124        // endpoints  - do we need them?
125#if USE_FIXEDPOINT_T
126        short mMinT, mMaxT;
127#else
128        float mMinT, mMaxT;
129#endif
130       
131        RayInfo():mRay(NULL) {}
132       
133        RayInfo(VssRay *r):mRay(r), mMinT(0),
134#if USE_FIXEDPOINT_T
135#define FIXEDPOINT_ONE 0x7FFE
136        // mMaxT(0xFFFF)
137                mMaxT(FIXEDPOINT_ONE)
138#else
139                mMaxT(1.0f)
140#endif
141        {}
142       
143        RayInfo(VssRay *r,
144                        const float _min,
145                        const float _max
146                        ):mRay(r)
147        {
148                SetMinT(_min);
149                SetMaxT(_max);
150        }
151       
152        RayInfo(VssRay *r,
153                        const short _min,
154                        const float _max):mRay(r), mMinT(_min)
155        {
156                SetMaxT(_max);
157        }
158       
159        RayInfo(VssRay *r,
160                        const float _min,
161                        const short _max):
162        mRay(r), mMaxT(_max)
163        {
164                SetMinT(_min);
165        }
166       
167        friend bool operator<(const RayInfo &a, const RayInfo &b) {
168                return a.mRay < b.mRay;
169        }
170 
171       
172        float ExtrapOrigin(const int axis) const {
173                return mRay->GetOrigin(axis) + GetMinT()*mRay->GetDir(axis);
174        }
175       
176        float ExtrapTermination(const int axis) const {
177                return mRay->GetOrigin(axis) + GetMaxT()*mRay->GetDir(axis);
178        }
179       
180#if USE_FIXEDPOINT_T
181        float GetMinT () const { return mMinT/(float)(FIXEDPOINT_ONE); }
182        float GetMaxT () const { return mMaxT/(float)(FIXEDPOINT_ONE); }
183       
184        void SetMinT (const float t) {
185                mMinT = (short) (t*(float)(FIXEDPOINT_ONE));
186        }
187       
188        void SetMaxT (const float t) {
189                mMaxT = (short) (t*(float)(FIXEDPOINT_ONE));
190                mMaxT++;
191                //      if (mMaxT!=0xFFFF)
192                //      mMaxT++;
193        }
194#else
195        float GetMinT () const { return mMinT; }
196        float GetMaxT () const { return mMaxT; }
197       
198        void SetMinT (const float t) { mMinT = t; }
199        void SetMaxT (const float t) { mMaxT = t; }
200#endif
201
202
203        int ComputeRayIntersection(const int axis, const float position, float &t) const
204        {               
205                // intersect the ray with the plane
206                float denom = mRay->GetDir(axis);
207   
208                if (fabs(denom) < 1e-20)
209                        //if (denom == 0.0f)
210                        return (mRay->GetOrigin(axis) > position) ? 1 : -1;
211   
212                t = (position - mRay->GetOrigin(axis))/denom;
213
214                if (t < GetMinT())
215                        return (denom > 0) ? 1 : -1;
216
217                if (t > GetMaxT())
218                        return (denom > 0) ? -1 : 1;
219
220                return 0;
221        }
222
223
224};
225
226
227typedef vector<RayInfo> RayInfoContainer;
228
229enum {EInterior, ELeaf};
230
231  /////////////////////////////////
232  // The actual data goes here
233 
234  // link to the parent
235  VspKdTreeInterior *parent;
236
237  enum {SPLIT_X=0, SPLIT_Y, SPLIT_Z, SPLIT_DIRX, SPLIT_DIRY, SPLIT_DIRZ};
238 
239  // splitting axis
240  char axis;
241       
242  // depth
243  unsigned char depth;
244 
245  //  short depth;
246  //
247  /////////////////////////////////
248 
249  inline VspKdTreeNode(VspKdTreeInterior *p);
250
251 
252  virtual ~VspKdTreeNode() {};
253  virtual int Type() const  = 0;
254 
255
256  bool IsLeaf() const { return axis == -1; }
257 
258  virtual void Print(ostream &s) const = 0;
259
260  virtual int GetAccessTime() {
261    return 0x7FFFFFF;
262  }
263
264 
265       
266};
267
268// --------------------------------------------------------------
269// KD-tree node - interior node
270// --------------------------------------------------------------
271class VspKdTreeInterior: public VspKdTreeNode
272{
273public:
274  // plane in local modelling coordinates
275  float position;
276
277  // pointers to children
278  VspKdTreeNode *back, *front;
279
280  // the bbox of the node
281  AxisAlignedBox3 bbox;
282
283  // the bbox of the node
284  AxisAlignedBox3 dirBBox;
285 
286  // data for caching
287  long accesses;
288  long lastAccessTime;
289 
290  VspKdTreeInterior(VspKdTreeInterior *p):VspKdTreeNode(p),
291                                        back(NULL),
292                                        front(NULL),
293                                        accesses(0),
294                                        lastAccessTime(-1)
295  { }
296
297  virtual int GetAccessTime() {
298    return lastAccessTime;
299  }
300
301  void SetupChildLinks(VspKdTreeNode *b, VspKdTreeNode *f) {
302    back = b;
303    front = f;
304    b->parent = f->parent = this;
305  }
306
307  void ReplaceChildLink(VspKdTreeNode *oldChild, VspKdTreeNode *newChild) {
308    if (back == oldChild)
309      back = newChild;
310    else
311      front = newChild;
312  }
313
314  virtual int Type() const  { return EInterior; }
315 
316  virtual ~VspKdTreeInterior()
317  {
318          DEL_PTR(back);
319          DEL_PTR(front);
320  }
321 
322  virtual void Print(ostream &s) const
323  {
324          if (axis == 0)
325                  s << "x ";
326          else
327                  if (axis == 1)
328                          s << "y ";
329                  else
330                          s << "z ";
331          s << position << " ";
332          back->Print(s);
333          front->Print(s);
334  }
335       
336  int ComputeRayIntersection(const RayInfo &rayData, float &t)
337  {
338          return rayData.ComputeRayIntersection(axis, position, t);
339  }
340
341};
342
343
344// --------------------------------------------------------------
345// KD-tree node - leaf node
346// --------------------------------------------------------------
347class VspKdTreeLeaf : public VspKdTreeNode
348{
349private:
350        int mPvsSize;
351public:
352        static int mailID;
353        int mailbox;
354 
355        RayInfoContainer rays;
356        bool mValidPvs;
357       
358        VspKdTreeLeaf(VspKdTreeInterior *p,     const int nRays):
359        VspKdTreeNode(p), rays(), mPvsSize(0), mValidPvs(false)
360        {
361                rays.reserve(nRays);
362        }
363       
364        virtual ~VspKdTreeLeaf() { }
365
366        virtual int Type() const 
367        {
368                return ELeaf;
369        }
370
371        virtual void Print(ostream &s) const
372        {
373                s << endl << "L: r = " << rays.size() << endl;
374        };
375 
376        void AddRay(const RayInfo &data)
377        {
378                mValidPvs = false;
379                rays.push_back(data);
380                data.mRay->Ref();
381        }
382       
383        int GetPvsSize() const
384        {
385                return mPvsSize;
386        }
387        void SetPvsSize(const int s)
388        {
389                mPvsSize = s;
390        }
391
392        void UpdatePvsSize();
393
394        void Mail()
395        {
396                mailbox = mailID;
397        }
398 
399        static void NewMail()
400        {
401                ++ mailID;
402        }
403 
404        bool Mailed() const
405        {
406                return mailbox == mailID;
407        }
408 
409        bool Mailed(const int mail)
410        {
411                return mailbox >= mailID + mail;
412        }
413
414        float GetAvgRayContribution() const
415        {
416                return GetPvsSize()/((float)rays.size() + Limits::Small);
417        }
418
419        float GetSqrRayContribution() const
420        {
421                return sqr(GetPvsSize()/((float)rays.size() + Limits::Small));
422        }
423
424};
425
426// Inline functions
427inline VspKdTreeNode::VspKdTreeNode(VspKdTreeInterior *p):
428parent(p), axis(-1), depth(p ? p->depth + 1 : 0)
429{}
430
431
432
433// ---------------------------------------------------------------
434// Main LSDS search class
435// ---------------------------------------------------------------
436class VspKdTree
437{
438        // --------------------------------------------------------------
439        // For sorting rays
440        // -------------------------------------------------------------
441        struct SortableEntry
442        {
443                enum EType
444                {
445                        ERayMin,
446                        ERayMax
447                };
448
449                int type;
450                float value;
451                void *data;
452 
453                SortableEntry() {}
454                SortableEntry(const int t, const float v, void *d):type(t),
455                                          value(v), data(d)
456                {
457                }
458               
459                friend bool operator<(const SortableEntry &a, const SortableEntry &b)
460                {
461                        return a.value < b.value;
462                }
463        };
464
465        struct TraversalData
466        { 
467                VspKdTreeNode *node;
468                AxisAlignedBox3 bbox;
469                int depth;
470                float priority;
471       
472                TraversalData() {}
473
474                TraversalData(VspKdTreeNode *n, const float p):
475                node(n), priority(p)
476                {}
477
478                TraversalData(VspKdTreeNode *n, const AxisAlignedBox3 &b, const int d):
479                node(n), bbox(b), depth(d) {}
480   
481                // comparator for the
482                struct less_priority : public binary_function<const TraversalData, const TraversalData, bool>
483                {
484                        bool operator()(const TraversalData a, const TraversalData b)
485                        {
486                                return a.priority < b.priority;
487                        }
488                };
489
490                //    ~TraversalData() {}
491                //    TraversalData(const TraversalData &s):node(s.node), bbox(s.bbox), depth(s.depth) {}
492   
493                friend bool operator<(const TraversalData &a, const TraversalData &b)
494                {
495                        // return a.node->queries.size() < b.node->queries.size();
496                        VspKdTreeLeaf *leafa = (VspKdTreeLeaf *) a.node;
497                        VspKdTreeLeaf *leafb = (VspKdTreeLeaf *) b.node;
498#if 0
499                        return
500                                leafa->rays.size()*a.bbox.GetVolume()
501                                <
502                                leafb->rays.size()*b.bbox.GetVolume();
503#endif
504#if 1
505                        return
506                                leafa->GetPvsSize()*a.bbox.GetVolume()
507                                <
508                                leafb->GetPvsSize()*b.bbox.GetVolume();
509#endif
510#if 0
511                        return
512                                leafa->GetPvsSize()
513                                <
514                                leafb->GetPvsSize();
515#endif
516#if 0
517                        return
518                                leafa->GetPvsSize() / (float)(leafa->rays.size() + 1)
519                                >
520                                leafb->GetPvsSize() / (float)(leafb->rays.size() + 1);
521#endif
522#if 0
523                        return
524                                leafa->GetPvsSize() * (float)leafa->rays.size()
525                                <
526                                leafb->GetPvsSize() * (float)leafb->rays.size();
527#endif
528    }
529  };
530 
531  // simplified data for ray traversal only...
532
533  struct RayTraversalData
534  {
535          VspKdTreeNode::RayInfo rayData;
536          VspKdTreeNode *node;
537     
538          RayTraversalData() {}
539         
540          RayTraversalData(VspKdTreeNode *n, const VspKdTreeNode::RayInfo &data):
541          rayData(data), node(n) {}
542  };
543       
544public:
545       
546        /////////////////////////////
547        // The core pointer
548        VspKdTreeNode *root;
549 
550        /////////////////////////////
551        // Basic properties
552
553        // total number of nodes of the tree
554        int nodes;
555       
556        // axis aligned bounding box of the scene
557        AxisAlignedBox3 bbox;
558
559        // axis aligned bounding box of directions
560        AxisAlignedBox3 dirBBox;
561
562        const VspKdStatistics &GetStatistics() const {
563                return mStat;
564        }
565        /////////////////////////////
566        // Construction parameters
567
568        // epsilon used for the construction
569        float epsilon;
570
571        // ratio between traversal and intersection costs
572        float ct_div_ci;
573       
574        // max depth of the tree
575        int termMaxDepth;
576        // minimal ratio of the volume of the cell and the query volume
577        float termMinSize;
578
579        // minimal pvs per node to still get subdivided
580        int termMinPvs;
581
582        // minimal ray number per node to still get subdivided
583        int termMinRays;
584       
585        // maximal cost ration to subdivide a node
586        float termMaxCostRatio;
587       
588        // maximal contribution per ray to subdivide the node
589        float termMaxRayContribution;
590
591        // randomized construction
592        bool randomize;
593
594        // type of the splitting to use for the tree construction
595        enum {ESplitRegular, ESplitHeuristic };
596        int splitType;
597       
598        // maximal size of the box on which the refdir splitting can be performed
599        // (relative to the scene bbox
600        float refDirBoxMaxSize;
601 
602        // maximum alovable memory in MB
603        float maxTotalMemory;
604
605        // maximum alovable memory for static kd tree in MB
606        float maxStaticMemory;
607
608        // this is used during the construction depending
609        // on the type of the tree and queries...
610        float maxMemory;
611
612        // minimal acess time for collapse
613        int accessTimeThreshold;
614
615        // minimal depth at which to perform collapse
616        int minCollapseDepth;
617       
618        // reusable array of split candidates
619        vector<SortableEntry> *splitCandidates;
620       
621        /////////////////////////////
622        VspKdStatistics mstat;
623       
624        VspKdTree();
625        virtual ~VspKdTree();
626
627        virtual void Construct(VssRayContainer &rays,
628                                                   AxisAlignedBox3 *forcedBoundingBox = NULL);
629       
630        // incemental construction
631        virtual void UpdateRays(VssRayContainer &remove, VssRayContainer &add);
632
633        virtual void AddRays(VssRayContainer &add)
634        {
635                VssRayContainer remove;
636                UpdateRays(remove, add);
637        }
638
639        VspKdTreeNode *Locate(const Vector3 &v);
640       
641        VspKdTreeNode *SubdivideNode(VspKdTreeLeaf *leaf,
642                                                                 const AxisAlignedBox3 &box,
643                                                                 AxisAlignedBox3 &backBox,
644                                                                 AxisAlignedBox3 &frontBox);
645       
646        VspKdTreeNode *Subdivide(const TraversalData &tdata);
647       
648        int SelectPlane(VspKdTreeLeaf *leaf,
649                                        const AxisAlignedBox3 &box,
650                                        float &position,
651                                        int &raysBack,
652                                        int &raysFront,
653                                        int &pvsBack,
654                                        int &pvsFront);
655
656        void SortSplitCandidates(VspKdTreeLeaf *node,
657                                                         const int axis);
658       
659 
660        // return memory usage in MB
661        float GetMemUsage() const
662        {
663                return
664                        (sizeof(VspKdTree) +
665                         stat.Leaves() * sizeof(VspKdTreeLeaf) +
666                         stat.Interior() * sizeof(VspKdTreeInterior) +
667                         stat.rayRefs * sizeof(VspKdTreeNode::RayInfo)) / (1024.0f*1024.0f);
668        }
669       
670        float GetRayMemUsage() const
671        {
672                return stat.rays * (sizeof(VssRay))/(1024.0f * 1024.0f);
673        }
674 
675        float BestCostRatioHeuristic(VspKdTreeLeaf *node,
676                                                                 int &axis,
677                                                                 float &position,
678                                                                 int &raysBack,
679                                                                 int &raysFront,
680                                                                 int &pvsBack,
681                                                                 int &pvsFront);
682
683        float BestCostRatioRegular(VspKdTreeLeaf *node,
684                                                           int &axis,
685                                                           float &position,
686                                                           int &raysBack,
687                                                           int &raysFront,
688                                                           int &pvsBack,
689                                                           int &pvsFront);
690       
691        float EvalCostRatio(VspKdTreeLeaf *node,
692                                                const int axis,
693                                                const float position,
694                                                int &raysBack,
695                                                int &raysFront,
696                                                int &pvsBack,
697                                                int &pvsFront);
698
699        AxisAlignedBox3 GetBBox(const VspKdTreeNode *node)
700        {
701                if (node->parent == NULL)
702                        return bbox;
703
704                if (!node->IsLeaf())
705                        return ((VspKdTreeInterior *)node)->bbox;
706
707                if (node->parent->axis >= 3)
708                        return node->parent->bbox;
709     
710                AxisAlignedBox3 box(node->parent->bbox);
711                if (node->parent->front == node)
712                        box.SetMin(node->parent->axis, node->parent->position);
713                else
714                        box.SetMax(node->parent->axis, node->parent->position);
715                return box;
716        }
717
718        AxisAlignedBox3 GetDirBBox(const VspKdTreeNode *node)
719        {
720                if (node->parent == NULL)
721                        return dirBBox;
722                if (!node->IsLeaf())
723                        return ((VspKdTreeInterior *)node)->dirBBox;
724                if (node->parent->axis < 3)
725                        return node->parent->dirBBox;
726   
727                AxisAlignedBox3 dBBox(node->parent->dirBBox);
728
729                if (node->parent->front == node)
730                        dBBox.SetMin(node->parent->axis - 3, node->parent->position);
731                else
732                        dBBox.SetMax(node->parent->axis - 3, node->parent->position);
733                return dBBox;
734        }
735 
736        int     ReleaseMemory(const int time);
737
738        int     CollapseSubtree(VspKdTreeNode *node, const int time);
739       
740        void CountAccess(VspKdTreeInterior *node, const long time)
741        {
742                ++ node->accesses;
743                node->lastAccessTime = time;
744        }
745
746        VspKdTreeNode * SubdivideLeaf(VspKdTreeLeaf *leaf,
747                                                                  const float SAThreshold);
748
749        void RemoveRay(VssRay *ray,
750                                   vector<VspKdTreeLeaf *> *affectedLeaves,
751                                   const bool removeAllScheduledRays);
752
753        void AddRay(VssRay *ray);
754       
755        void TraverseInternalNode(RayTraversalData &data,
756                                                         stack<RayTraversalData> &tstack);
757
758        void EvaluateLeafStats(const TraversalData &data);
759
760
761        int     GetRootPvsSize() const
762        {
763                return GetPvsSize(root, bbox);
764        }
765       
766        int     GetPvsSize(VspKdTreeNode *node, const AxisAlignedBox3 &box) const;
767
768        void GetRayContributionStatistics(float &minRayContribution,
769                                                                          float &maxRayContribution,
770                                                                          float &avgRayContribution);
771
772        int GenerateRays(const float ratioPerLeaf,
773                                         SimpleRayContainer &rays);
774
775        float GetAvgPvsSize();
776};
777
778
779#endif // __LSDS_KDTREE_H__
780
Note: See TracBrowser for help on using the repository browser.