CullVisitor 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2008 Robert Osfield
  2. *
  3. * This library is open source and may be redistributed and/or modified under
  4. * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
  5. * (at your option) any later version. The full license is in LICENSE file
  6. * included with this distribution, and on the openscenegraph.org website.
  7. *
  8. * This library is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * OpenSceneGraph Public License for more details.
  12. */
  13. #ifndef OSGUTIL_CULLVISITOR
  14. #define OSGUTIL_CULLVISITOR 1
  15. #include <map>
  16. #include <vector>
  17. #include <osg/NodeVisitor>
  18. #include <osg/BoundingSphere>
  19. #include <osg/BoundingBox>
  20. #include <osg/Matrix>
  21. #include <osg/Drawable>
  22. #include <osg/StateSet>
  23. #include <osg/State>
  24. #include <osg/ClearNode>
  25. #include <osg/Camera>
  26. #include <osg/Notify>
  27. #include <osg/CullStack>
  28. #include <osgUtil/StateGraph>
  29. #include <osgUtil/RenderStage>
  30. #include <osg/Vec3>
  31. namespace osgUtil {
  32. /**
  33. * Basic NodeVisitor implementation for rendering a scene.
  34. * This visitor traverses the scene graph, collecting transparent and
  35. * opaque osg::Drawables into a depth sorted transparent bin and a state
  36. * sorted opaque bin. The opaque bin is rendered first, and then the
  37. * transparent bin is rendered in order from the furthest osg::Drawable
  38. * from the eye to the one nearest the eye.
  39. */
  40. class OSGUTIL_EXPORT CullVisitor : public osg::NodeVisitor, public osg::CullStack
  41. {
  42. public:
  43. typedef osg::Matrix::value_type value_type;
  44. CullVisitor();
  45. /// Copy constructor that does a shallow copy.
  46. CullVisitor(const CullVisitor&);
  47. META_NodeVisitor(osgUtil, CullVisitor)
  48. /** Convert 'this' into a osgUtil::CullVisitor pointer if Object is a osgUtil::CullVisitor, otherwise return 0.
  49. * Equivalent to dynamic_cast<osgUtil::CullVisitor*>(this).*/
  50. virtual osgUtil::CullVisitor* asCullVisitor() { return this; }
  51. /** convert 'const this' into a const osgUtil::CullVisitor pointer if Object is a osgUtil::CullVisitor, otherwise return 0.
  52. * Equivalent to dynamic_cast<const osgUtil::CullVisitor*>(this).*/
  53. virtual const osgUtil::CullVisitor* asCullVisitor() const { return this; }
  54. /** Convert 'this' into a osg::CullStack pointer if Object is a osg::CullStack, otherwise return 0.
  55. * Equivalent to dynamic_cast<osg::CullStack*>(this).*/
  56. virtual osg::CullStack* asCullStack() { return static_cast<osg::CullStack*>(this); }
  57. /** convert 'const this' into a const osg::CullStack pointer if Object is a osg::CullStack, otherwise return 0.
  58. * Equivalent to dynamic_cast<const osg::CullStack*>(this).*/
  59. virtual const osg::CullStack* asCullStack() const { return static_cast<const osg::CullStack*>(this); }
  60. using osg::NodeVisitor::clone;
  61. /** Create a shallow copy of the CullVisitor, used by CullVisitor::create() to clone the prototype. */
  62. virtual CullVisitor* clone() const { return new CullVisitor(*this); }
  63. /** get the prototype singleton used by CullVisitor::create().*/
  64. static osg::ref_ptr<CullVisitor>& prototype();
  65. /** create a CullVisitor by cloning CullVisitor::prototype().*/
  66. static CullVisitor* create();
  67. virtual void reset();
  68. struct Identifier : public osg::Referenced
  69. {
  70. Identifier() {}
  71. virtual ~Identifier() {}
  72. };
  73. void setIdentifier(Identifier* identifier) { _identifier = identifier; }
  74. Identifier* getIdentifier() { return _identifier.get(); }
  75. const Identifier* getIdentifier() const { return _identifier.get(); }
  76. virtual osg::Vec3 getEyePoint() const { return getEyeLocal(); }
  77. virtual osg::Vec3 getViewPoint() const { return getViewPointLocal(); }
  78. virtual float getDistanceToEyePoint(const osg::Vec3& pos, bool withLODScale) const;
  79. virtual float getDistanceFromEyePoint(const osg::Vec3& pos, bool withLODScale) const;
  80. virtual float getDistanceToViewPoint(const osg::Vec3& pos, bool withLODScale) const;
  81. virtual void apply(osg::Node&);
  82. virtual void apply(osg::Geode& node);
  83. virtual void apply(osg::Drawable& drawable);
  84. virtual void apply(osg::Billboard& node);
  85. virtual void apply(osg::LightSource& node);
  86. virtual void apply(osg::ClipNode& node);
  87. virtual void apply(osg::TexGenNode& node);
  88. virtual void apply(osg::Group& node);
  89. virtual void apply(osg::Transform& node);
  90. virtual void apply(osg::Projection& node);
  91. virtual void apply(osg::Switch& node);
  92. virtual void apply(osg::LOD& node);
  93. virtual void apply(osg::ClearNode& node);
  94. virtual void apply(osg::Camera& node);
  95. virtual void apply(osg::OccluderNode& node);
  96. virtual void apply(osg::OcclusionQueryNode& node);
  97. /** Push state set on the current state group.
  98. * If the state exists in a child state group of the current
  99. * state group then move the current state group to that child.
  100. * Otherwise, create a new state group for the state set, add
  101. * it to the current state group then move the current state
  102. * group pointer to the new state group.
  103. */
  104. inline void pushStateSet(const osg::StateSet* ss)
  105. {
  106. _currentStateGraph = _currentStateGraph->find_or_insert(ss);
  107. bool useRenderBinDetails = (ss->useRenderBinDetails() && !ss->getBinName().empty()) &&
  108. (_numberOfEncloseOverrideRenderBinDetails==0 || (ss->getRenderBinMode()&osg::StateSet::PROTECTED_RENDERBIN_DETAILS)!=0);
  109. if (useRenderBinDetails)
  110. {
  111. _renderBinStack.push_back(_currentRenderBin);
  112. _currentRenderBin = ss->getNestRenderBins() ?
  113. _currentRenderBin->find_or_insert(ss->getBinNumber(),ss->getBinName()) :
  114. _currentRenderBin->getStage()->find_or_insert(ss->getBinNumber(),ss->getBinName());
  115. }
  116. if ((ss->getRenderBinMode()&osg::StateSet::OVERRIDE_RENDERBIN_DETAILS)!=0)
  117. {
  118. ++_numberOfEncloseOverrideRenderBinDetails;
  119. }
  120. }
  121. /** Pop the top state set and hence associated state group.
  122. * Move the current state group to the parent of the popped
  123. * state group.
  124. */
  125. inline void popStateSet()
  126. {
  127. const osg::StateSet* ss = _currentStateGraph->getStateSet();
  128. if ((ss->getRenderBinMode()&osg::StateSet::OVERRIDE_RENDERBIN_DETAILS)!=0)
  129. {
  130. --_numberOfEncloseOverrideRenderBinDetails;
  131. }
  132. bool useRenderBinDetails = (ss->useRenderBinDetails() && !ss->getBinName().empty()) &&
  133. (_numberOfEncloseOverrideRenderBinDetails==0 || (ss->getRenderBinMode()&osg::StateSet::PROTECTED_RENDERBIN_DETAILS)!=0);
  134. if (useRenderBinDetails)
  135. {
  136. if (_renderBinStack.empty())
  137. {
  138. _currentRenderBin = _currentRenderBin->getStage();
  139. }
  140. else
  141. {
  142. _currentRenderBin = _renderBinStack.back();
  143. _renderBinStack.pop_back();
  144. }
  145. }
  146. _currentStateGraph = _currentStateGraph->_parent;
  147. }
  148. inline void setStateGraph(StateGraph* rg)
  149. {
  150. _rootStateGraph = rg;
  151. _currentStateGraph = rg;
  152. }
  153. inline StateGraph* getRootStateGraph()
  154. {
  155. return _rootStateGraph.get();
  156. }
  157. inline StateGraph* getCurrentStateGraph()
  158. {
  159. return _currentStateGraph;
  160. }
  161. inline void setRenderStage(RenderStage* rg)
  162. {
  163. _rootRenderStage = rg;
  164. _currentRenderBin = rg;
  165. }
  166. inline RenderStage* getRenderStage()
  167. {
  168. return _rootRenderStage.get();
  169. }
  170. inline RenderStage* getCurrentRenderStage()
  171. {
  172. return _currentRenderBin->getStage();
  173. }
  174. inline osg::Camera* getCurrentCamera()
  175. {
  176. return getCurrentRenderStage()->getCamera();
  177. }
  178. inline RenderBin* getCurrentRenderBin()
  179. {
  180. return _currentRenderBin;
  181. }
  182. inline void setCurrentRenderBin(RenderBin* rb)
  183. {
  184. _currentRenderBin = rb;
  185. }
  186. void setCalculatedNearPlane(value_type value) { _computed_znear = value; }
  187. inline value_type getCalculatedNearPlane() const { return _computed_znear; }
  188. void setCalculatedFarPlane(value_type value) { _computed_zfar = value; }
  189. inline value_type getCalculatedFarPlane() const { return _computed_zfar; }
  190. value_type computeNearestPointInFrustum(const osg::Matrix& matrix, const osg::Polytope::PlaneList& planes,const osg::Drawable& drawable);
  191. value_type computeFurthestPointInFrustum(const osg::Matrix& matrix, const osg::Polytope::PlaneList& planes,const osg::Drawable& drawable);
  192. bool updateCalculatedNearFar(const osg::Matrix& matrix,const osg::BoundingBox& bb);
  193. bool updateCalculatedNearFar(const osg::Matrix& matrix,const osg::Drawable& drawable, bool isBillboard=false);
  194. void updateCalculatedNearFar(const osg::Vec3& pos);
  195. /** Add a drawable to current render graph.*/
  196. inline void addDrawable(osg::Drawable* drawable,osg::RefMatrix* matrix);
  197. /** Add a drawable and depth to current render graph.*/
  198. inline void addDrawableAndDepth(osg::Drawable* drawable,osg::RefMatrix* matrix,float depth);
  199. /** Add an attribute which is positioned relative to the modelview matrix.*/
  200. inline void addPositionedAttribute(osg::RefMatrix* matrix,const osg::StateAttribute* attr);
  201. /** Add an attribute which is positioned relative to the modelview matrix.*/
  202. inline void addPositionedTextureAttribute(unsigned int textureUnit, osg::RefMatrix* matrix,const osg::StateAttribute* attr);
  203. /** compute near plane based on the polgon intersection of primtives in near plane candidate list of drawables.
  204. * Note, you have to set ComputeNearFarMode to COMPUTE_NEAR_FAR_USING_PRIMITIVES to be able to near plane candidate drawables to be recorded by the cull traversal. */
  205. void computeNearPlane();
  206. /** Re-implement CullStack's popProjectionMatrix() adding clamping of the projection matrix to
  207. * the computed near and far.*/
  208. virtual void popProjectionMatrix();
  209. /** CullVisitor's default clamping of the projection float matrix to computed near and far values.
  210. * Note, do not call this method directly, use clampProjectionMatrix(..) instead, unless you want to bypass the callback.*/
  211. virtual bool clampProjectionMatrixImplementation(osg::Matrixf& projection, double& znear, double& zfar) const;
  212. /** CullVisitor's default clamping of the projection double matrix to computed near and far values.
  213. * Note, do not call this method directly, use clampProjectionMatrix(..) instead, unless you want to bypass the callback.*/
  214. virtual bool clampProjectionMatrixImplementation(osg::Matrixd& projection, double& znear, double& zfar) const;
  215. /** Clamp the projection float matrix to computed near and far values, use callback if it exists,
  216. * otherwise use default CullVisitor implementation.*/
  217. inline bool clampProjectionMatrix(osg::Matrixf& projection, value_type& znear, value_type& zfar) const
  218. {
  219. double zn = znear;
  220. double zf = zfar;
  221. bool result = false;
  222. if (_clampProjectionMatrixCallback.valid()) result = _clampProjectionMatrixCallback->clampProjectionMatrixImplementation(projection, zn, zf);
  223. else result = clampProjectionMatrixImplementation(projection, zn, zf);
  224. if (result)
  225. {
  226. znear = zn;
  227. zfar = zf;
  228. return true;
  229. }
  230. else
  231. return false;
  232. }
  233. /** Clamp the projection double matrix to computed near and far values, use callback if it exists,
  234. * otherwise use default CullVisitor implementation.*/
  235. inline bool clampProjectionMatrix(osg::Matrixd& projection, value_type& znear, value_type& zfar) const
  236. {
  237. double zn = znear;
  238. double zf = zfar;
  239. bool result = false;
  240. if (_clampProjectionMatrixCallback.valid()) result = _clampProjectionMatrixCallback->clampProjectionMatrixImplementation(projection, zn, zf);
  241. else result = clampProjectionMatrixImplementation(projection, zn, zf);
  242. if (result)
  243. {
  244. znear = zn;
  245. zfar = zf;
  246. return true;
  247. }
  248. else
  249. return false;
  250. }
  251. void setState(osg::State* state) { _renderInfo.setState(state); }
  252. osg::State* getState() { return _renderInfo.getState(); }
  253. const osg::State* getState() const { return _renderInfo.getState(); }
  254. void setRenderInfo(osg::RenderInfo& renderInfo) { _renderInfo = renderInfo; }
  255. osg::RenderInfo& getRenderInfo() { return _renderInfo; }
  256. const osg::RenderInfo& getRenderInfo() const { return _renderInfo; }
  257. protected:
  258. virtual ~CullVisitor();
  259. /** Prevent unwanted copy operator.*/
  260. CullVisitor& operator = (const CullVisitor&) { return *this; }
  261. inline void handle_cull_callbacks_and_traverse(osg::Node& node)
  262. {
  263. osg::Callback* callback = node.getCullCallback();
  264. if (callback) callback->run(&node,this);
  265. else traverse(node);
  266. }
  267. inline void handle_cull_callbacks_and_accept(osg::Node& node,osg::Node* acceptNode)
  268. {
  269. osg::Callback* callback = node.getCullCallback();
  270. if (callback) callback->run(&node,this);
  271. else acceptNode->accept(*this);
  272. }
  273. osg::ref_ptr<StateGraph> _rootStateGraph;
  274. StateGraph* _currentStateGraph;
  275. osg::ref_ptr<RenderStage> _rootRenderStage;
  276. RenderBin* _currentRenderBin;
  277. std::vector<RenderBin*> _renderBinStack;
  278. value_type _computed_znear;
  279. value_type _computed_zfar;
  280. unsigned int _traversalOrderNumber;
  281. typedef std::vector< osg::ref_ptr<RenderLeaf> > RenderLeafList;
  282. RenderLeafList _reuseRenderLeafList;
  283. unsigned int _currentReuseRenderLeafIndex;
  284. inline RenderLeaf* createOrReuseRenderLeaf(osg::Drawable* drawable,osg::RefMatrix* projection,osg::RefMatrix* matrix, float depth=0.0f);
  285. unsigned int _numberOfEncloseOverrideRenderBinDetails;
  286. osg::RenderInfo _renderInfo;
  287. struct MatrixPlanesDrawables
  288. {
  289. MatrixPlanesDrawables():
  290. _drawable(0)
  291. {
  292. }
  293. void set(const osg::Matrix& matrix, const osg::Drawable* drawable, const osg::Polytope& frustum)
  294. {
  295. _matrix = matrix;
  296. _drawable = drawable;
  297. if (!_planes.empty()) _planes.clear();
  298. // create a new list of planes from the active walls of the frustum.
  299. osg::Polytope::ClippingMask result_mask = frustum.getResultMask();
  300. osg::Polytope::ClippingMask selector_mask = 0x1;
  301. for(osg::Polytope::PlaneList::const_iterator itr=frustum.getPlaneList().begin();
  302. itr!=frustum.getPlaneList().end();
  303. ++itr)
  304. {
  305. if (result_mask&selector_mask) _planes.push_back(*itr);
  306. selector_mask <<= 1;
  307. }
  308. }
  309. MatrixPlanesDrawables(const MatrixPlanesDrawables& mpd):
  310. _matrix(mpd._matrix),
  311. _drawable(mpd._drawable),
  312. _planes(mpd._planes) {}
  313. MatrixPlanesDrawables& operator = (const MatrixPlanesDrawables& mpd)
  314. {
  315. _matrix = mpd._matrix;
  316. _drawable = mpd._drawable;
  317. _planes = mpd._planes;
  318. return *this;
  319. }
  320. osg::Matrix _matrix;
  321. const osg::Drawable* _drawable;
  322. osg::Polytope::PlaneList _planes;
  323. };
  324. typedef std::multimap<value_type, MatrixPlanesDrawables> DistanceMatrixDrawableMap;
  325. DistanceMatrixDrawableMap _nearPlaneCandidateMap;
  326. DistanceMatrixDrawableMap _farPlaneCandidateMap;
  327. osg::ref_ptr<Identifier> _identifier;
  328. };
  329. inline void CullVisitor::addDrawable(osg::Drawable* drawable,osg::RefMatrix* matrix)
  330. {
  331. if (_currentStateGraph->leaves_empty())
  332. {
  333. // this is first leaf to be added to StateGraph
  334. // and therefore should not already know to current render bin,
  335. // so need to add it.
  336. _currentRenderBin->addStateGraph(_currentStateGraph);
  337. }
  338. //_currentStateGraph->addLeaf(new RenderLeaf(drawable,matrix));
  339. _currentStateGraph->addLeaf(createOrReuseRenderLeaf(drawable,_projectionStack.back().get(),matrix));
  340. }
  341. /** Add a drawable and depth to current render graph.*/
  342. inline void CullVisitor::addDrawableAndDepth(osg::Drawable* drawable,osg::RefMatrix* matrix,float depth)
  343. {
  344. if (_currentStateGraph->leaves_empty())
  345. {
  346. // this is first leaf to be added to StateGraph
  347. // and therefore should not already know to current render bin,
  348. // so need to add it.
  349. _currentRenderBin->addStateGraph(_currentStateGraph);
  350. }
  351. //_currentStateGraph->addLeaf(new RenderLeaf(drawable,matrix,depth));
  352. _currentStateGraph->addLeaf(createOrReuseRenderLeaf(drawable,_projectionStack.back().get(),matrix,depth));
  353. }
  354. /** Add an attribute which is positioned relative to the modelview matrix.*/
  355. inline void CullVisitor::addPositionedAttribute(osg::RefMatrix* matrix,const osg::StateAttribute* attr)
  356. {
  357. _currentRenderBin->getStage()->addPositionedAttribute(matrix,attr);
  358. }
  359. /** Add an attribute which is positioned relative to the modelview matrix.*/
  360. inline void CullVisitor::addPositionedTextureAttribute(unsigned int textureUnit, osg::RefMatrix* matrix,const osg::StateAttribute* attr)
  361. {
  362. _currentRenderBin->getStage()->addPositionedTextureAttribute(textureUnit,matrix,attr);
  363. }
  364. inline RenderLeaf* CullVisitor::createOrReuseRenderLeaf(osg::Drawable* drawable,osg::RefMatrix* projection,osg::RefMatrix* matrix, float depth)
  365. {
  366. // Skips any already reused renderleaf.
  367. while (_currentReuseRenderLeafIndex<_reuseRenderLeafList.size() &&
  368. _reuseRenderLeafList[_currentReuseRenderLeafIndex]->referenceCount()>1)
  369. {
  370. osg::notify(osg::INFO)<<"CullVisitor:createOrReuseRenderLeaf() skipping multiply referenced entry. _reuseRenderLeafList.size()="<< _reuseRenderLeafList.size()<<" _reuseRenderLeafList["<<_currentReuseRenderLeafIndex<<"]->referenceCount()="<<_reuseRenderLeafList[_currentReuseRenderLeafIndex]->referenceCount()<<std::endl;
  371. ++_currentReuseRenderLeafIndex;
  372. }
  373. // If still within list, element must be singularly referenced then return it to be reused.
  374. if (_currentReuseRenderLeafIndex<_reuseRenderLeafList.size())
  375. {
  376. RenderLeaf* renderleaf = _reuseRenderLeafList[_currentReuseRenderLeafIndex++].get();
  377. renderleaf->set(drawable,projection,matrix,depth,_traversalOrderNumber++);
  378. return renderleaf;
  379. }
  380. // Otherwise need to create new renderleaf.
  381. RenderLeaf* renderleaf = new RenderLeaf(drawable,projection,matrix,depth,_traversalOrderNumber++);
  382. _reuseRenderLeafList.push_back(renderleaf);
  383. ++_currentReuseRenderLeafIndex;
  384. return renderleaf;
  385. }
  386. }
  387. #endif