octree.h
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:11k
源码类别:

OpenGL

开发平台:

Visual C++

  1. // octree.h
  2. //
  3. // Octree-based visibility determination for objects.
  4. //
  5. // Copyright (C) 2001, Chris Laurel <claurel@shatters.net>
  6. //
  7. // This program is free software; you can redistribute it and/or
  8. // modify it under the terms of the GNU General Public License
  9. // as published by the Free Software Foundation; either version 2
  10. // of the License, or (at your option) any later version.
  11. #ifndef _OCTREE_H_
  12. #define _OCTREE_H_
  13. #include <vector>
  14. #include <celmath/quaternion.h>
  15. #include <celmath/plane.h>
  16. #include <celengine/observer.h>
  17. // The DynamicOctree and StaticOctree template arguments are:
  18. // OBJ:  object hanging from the node,
  19. // PREC: floating point precision of the culling operations at node level.
  20. // The hierarchy of octree nodes is built using a single precision value (excludingFactor), which relates to an
  21. // OBJ's limiting property defined by the octree particular specialization: ie. we use [absolute magnitude] for star octrees, etc.
  22. // For details, see notes below.
  23. template <class OBJ, class PREC> class OctreeProcessor
  24. {
  25.  public:
  26.     OctreeProcessor()          {};
  27.     virtual ~OctreeProcessor() {};
  28.     virtual void process(const OBJ& obj, PREC distance, float appMag) = 0;
  29. };
  30. struct OctreeLevelStatistics
  31. {
  32.     unsigned int nodeCount;
  33.     unsigned int objectCount;
  34.     double size;
  35. };
  36. template <class OBJ, class PREC> class StaticOctree;
  37. template <class OBJ, class PREC> class DynamicOctree
  38. {
  39.  typedef std::vector<const OBJ*> ObjectList;
  40.  typedef bool (LimitingFactorPredicate)     (const OBJ&, const float);
  41.  typedef bool (StraddlingPredicate)         (const Point3<PREC>&, const OBJ&, const float);
  42.  typedef PREC (ExclusionFactorDecayFunction)(const PREC);
  43.  public:
  44.     DynamicOctree(const Point3<PREC>& cellCenterPos,
  45.                   const float         exclusionFactor);
  46.     ~DynamicOctree();
  47.     void insertObject  (const OBJ&, const PREC);
  48.     void rebuildAndSort(StaticOctree<OBJ, PREC>*&, OBJ*&);
  49.  private:
  50.    static unsigned int SPLIT_THRESHOLD;
  51.    static LimitingFactorPredicate*      limitingFactorPredicate;
  52.    static StraddlingPredicate*          straddlingPredicate;
  53.    static ExclusionFactorDecayFunction* decayFunction;
  54.  private:
  55.     void           add  (const OBJ&);
  56.     void           split(const PREC);
  57.     void           sortIntoChildNodes();
  58.     DynamicOctree* getChild(const OBJ&, const Point3<PREC>&);
  59.     DynamicOctree** _children;
  60.     Point3<PREC>    cellCenterPos;
  61.     PREC            exclusionFactor;
  62.     ObjectList*     _objects;
  63. };
  64. template <class OBJ, class PREC> class StaticOctree
  65. {
  66.  friend class DynamicOctree<OBJ, PREC>;
  67.  public:
  68.     StaticOctree(const Point3<PREC>& cellCenterPos,
  69.                  const float         exclusionFactor,
  70.                  OBJ*                _firstObject,
  71.                  unsigned int        nObjects);
  72.     ~StaticOctree();
  73.     // These methods are only declared at the template level; we'll implement them as
  74.     // full specializations, allowing for different traversal strategies depending on the
  75.     // object type and nature.
  76.     // This method searches the octree for objects that are likely to be visible
  77.     // to a viewer with the specified obsPosition and limitingFactor.  The
  78.     // octreeProcessor is invoked for each potentially visible object --no object with
  79.     // a property greater than limitingFactor will be processed, but
  80.     // objects that are outside the view frustum may be.  Frustum tests are performed
  81.     // only at the node level to optimize the octree traversal, so an exact test
  82.     // (if one is required) is the responsibility of the callback method.
  83.     void processVisibleObjects(OctreeProcessor<OBJ, PREC>& processor,
  84.                                const Point3<PREC>&         obsPosition,
  85.                                const Plane<PREC>*          frustumPlanes,
  86.                                float                       limitingFactor,
  87.                                PREC                        scale) const;
  88.     void processCloseObjects(OctreeProcessor<OBJ, PREC>& processor,
  89.                              const Point3<PREC>&         obsPosition,
  90.                              PREC                        boundingRadius,
  91.                              PREC                        scale) const;
  92.     int countChildren() const;
  93.     int countObjects()  const;
  94.     void computeStatistics(std::vector<OctreeLevelStatistics>& stats, unsigned int level = 0);
  95.  private:
  96.     static const PREC SQRT3;
  97.  private:
  98.     StaticOctree** _children;
  99.     Point3<PREC>   cellCenterPos;
  100.     float          exclusionFactor;
  101.     OBJ*           _firstObject;
  102.     unsigned int   nObjects;
  103. };
  104. // There are two classes implemented in this module: StaticOctree and
  105. // DynamicOctree.  The DynamicOctree is built first by inserting
  106. // objects from a database or catalog and is then 'compiled' into a StaticOctree.
  107. // In the process of building the StaticOctree, the original object database is
  108. // reorganized, with objects in the same octree node all placed adjacent to each
  109. // other.  This spatial sorting of the objects dramatically improves the
  110. // performance of octree operations through much more coherent memory access.
  111. enum
  112. {
  113.     XPos = 1,
  114.     YPos = 2,
  115.     ZPos = 4,
  116. };
  117. // The SPLIT_THRESHOLD is the number of objects a node must contain before its
  118. // children are generated. Increasing this number will decrease the number of
  119. // octree nodes in the tree, which will use less memory but make culling less
  120. // efficient.
  121. template <class OBJ, class PREC>
  122. inline DynamicOctree<OBJ, PREC>::DynamicOctree(const Point3<PREC>& cellCenterPos,
  123.                                                const float         exclusionFactor):
  124.         _children      (NULL),
  125.         cellCenterPos  (cellCenterPos),
  126.         exclusionFactor(exclusionFactor),
  127.         _objects       (NULL)
  128. {
  129. }
  130. template <class OBJ, class PREC>
  131. inline DynamicOctree<OBJ, PREC>::~DynamicOctree()
  132. {
  133.     if (_children != NULL)
  134.     {
  135.         for (int i=0; i<8; ++i)
  136.         {
  137.             delete _children[i];
  138.         }
  139.         delete[] _children;
  140.     }
  141.     delete _objects;
  142. }
  143. template <class OBJ, class PREC>
  144. inline void DynamicOctree<OBJ, PREC>::insertObject(const OBJ& obj, const PREC scale)
  145. {
  146.     // If the object can't be placed into this node's children, then put it here:
  147.     if (limitingFactorPredicate(obj, exclusionFactor) || straddlingPredicate(cellCenterPos, obj, exclusionFactor) )
  148.         add(obj);
  149.     else
  150.     {
  151.         // If we haven't allocated child nodes yet, try to fit
  152.         // the object in this node, even though it could be put
  153.         // in a child. Only if there are more than SPLIT_THRESHOLD
  154.         // objects in the node will we attempt to place the
  155.         // object into a child node.  This is done in order
  156.         // to avoid having the octree degenerate into one object
  157.         // per node.
  158.         if (_children == NULL)
  159.         {
  160.             // Make sure that there's enough room left in this node
  161.             if (_objects != NULL && _objects->size() >= DynamicOctree<OBJ, PREC>::SPLIT_THRESHOLD)
  162.                 split(scale * 0.5f);
  163.             add(obj);
  164.         }
  165.         else
  166.             // We've already allocated child nodes; place the object
  167.             // into the appropriate one.
  168.             this->getChild(obj, cellCenterPos)->insertObject(obj, scale * (PREC) 0.5);
  169.     }
  170. }
  171. template <class OBJ, class PREC>
  172. inline void DynamicOctree<OBJ, PREC>::add(const OBJ& obj)
  173. {
  174.     if (_objects == NULL)
  175.         _objects = new ObjectList;
  176.     _objects->push_back(&obj);
  177. }
  178. template <class OBJ, class PREC>
  179. inline void DynamicOctree<OBJ, PREC>::split(const PREC scale)
  180. {
  181.     _children = new DynamicOctree*[8];
  182.     for (int i=0; i<8; ++i)
  183.     {
  184.         Point3<PREC> centerPos    = cellCenterPos;
  185.         centerPos.x     += ((i & XPos) != 0) ? scale : -scale;
  186.         centerPos.y     += ((i & YPos) != 0) ? scale : -scale;
  187.         centerPos.z     += ((i & ZPos) != 0) ? scale : -scale;
  188.         _children[i] = new DynamicOctree(centerPos,
  189.                                          decayFunction(exclusionFactor));
  190.     }
  191.     sortIntoChildNodes();
  192. }
  193. // Sort this node's objects into objects that can remain here,
  194. // and objects that should be placed into one of the eight
  195. // child nodes.
  196. template <class OBJ, class PREC>
  197. inline void DynamicOctree<OBJ, PREC>::sortIntoChildNodes()
  198. {
  199.     unsigned int nKeptInParent = 0;
  200.     for (unsigned int i=0; i<_objects->size(); ++i)
  201.     {
  202.         const OBJ& obj    = *(*_objects)[i];
  203.         if (limitingFactorPredicate(obj, exclusionFactor) ||
  204.             straddlingPredicate(cellCenterPos, obj, exclusionFactor) )
  205.         {
  206.             (*_objects)[nKeptInParent++] = (*_objects)[i];
  207.         }
  208.         else
  209.             this->getChild(obj, cellCenterPos)->add(obj);
  210.     }
  211.     _objects->resize(nKeptInParent);
  212. }
  213. template <class OBJ, class PREC>
  214. inline void DynamicOctree<OBJ, PREC>::rebuildAndSort(StaticOctree<OBJ, PREC>*& _staticNode, OBJ*& _sortedObjects)
  215. {
  216.     OBJ* _firstObject = _sortedObjects;
  217.     if (_objects != NULL)
  218.         for (typename ObjectList::const_iterator iter = _objects->begin(); iter != _objects->end(); ++iter)
  219.         {
  220.             *_sortedObjects++ = **iter;
  221.         }
  222.     unsigned int nObjects  = (unsigned int) (_sortedObjects - _firstObject);
  223.     _staticNode            = new StaticOctree<OBJ, PREC>(cellCenterPos, exclusionFactor, _firstObject, nObjects);
  224.     if (_children != NULL)
  225.     {
  226.         _staticNode->_children    = new StaticOctree<OBJ, PREC>*[8];
  227.         for (int i=0; i<8; ++i)
  228.             _children[i]->rebuildAndSort(_staticNode->_children[i], _sortedObjects);
  229.     }
  230. }
  231. //MS VC++ wants this to be placed here:
  232. template <class OBJ, class PREC>
  233. const PREC StaticOctree<OBJ, PREC>::SQRT3 = (PREC) 1.732050807568877;
  234. template <class OBJ, class PREC>
  235. inline StaticOctree<OBJ, PREC>::StaticOctree(const Point3<PREC>& cellCenterPos,
  236.                                              const float         exclusionFactor,
  237.                                              OBJ*                _firstObject,
  238.                                              unsigned int        nObjects):
  239.     _children      (NULL),
  240.     cellCenterPos  (cellCenterPos),
  241.     exclusionFactor(exclusionFactor),
  242.     _firstObject   (_firstObject),
  243.     nObjects       (nObjects)
  244. {
  245. }
  246. template <class OBJ, class PREC>
  247. inline StaticOctree<OBJ, PREC>::~StaticOctree()
  248. {
  249.     if (_children != NULL)
  250.     {
  251.         for (int i=0; i<8; ++i)
  252.             delete _children[i];
  253.         delete[] _children;
  254.     }
  255. }
  256. template <class OBJ, class PREC>
  257. inline int StaticOctree<OBJ, PREC>::countChildren() const
  258. {
  259.     int count    = 0;
  260.     for (int i=0; i<8; ++i)
  261.         count    += _children != NULL ? 1 + _children[i]->countChildren() : 0;
  262.     return count;
  263. }
  264. template <class OBJ, class PREC>
  265. inline int StaticOctree<OBJ, PREC>::countObjects() const
  266. {
  267.     int count    = nObjects;
  268.     if (_children != NULL)
  269.         for (int i=0; i<8; ++i)
  270.             count    += _children[i]->countObjects();
  271.     return count;
  272. }
  273. template <class OBJ, class PREC>
  274. void StaticOctree<OBJ, PREC>::computeStatistics(std::vector<OctreeLevelStatistics>& stats, unsigned int level)
  275. {
  276.     if (level >= stats.size())
  277.     {
  278.         while (level >= stats.size())
  279.         {
  280.             OctreeLevelStatistics levelStats;
  281.             levelStats.nodeCount = 0;
  282.             levelStats.objectCount = 0;
  283.             levelStats.size = 0.0;
  284.             stats.push_back(levelStats);
  285.         }
  286.     }
  287.     stats[level].nodeCount++;
  288.     stats[level].objectCount += nObjects;
  289.     stats[level].size = 0.0;
  290.     if (_children != NULL)
  291.     {
  292.         for (int i = 0; i < 8; i++)
  293.             _children[i]->computeStatistics(stats, level + 1);
  294.     }
  295. }
  296. #endif // _OCTREE_H_