123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492 |
- /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2008 Robert Osfield
- *
- * This library is open source and may be redistributed and/or modified under
- * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
- * (at your option) any later version. The full license is in LICENSE file
- * included with this distribution, and on the openscenegraph.org website.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * OpenSceneGraph Public License for more details.
- */
- #ifndef OSGUTIL_CULLVISITOR
- #define OSGUTIL_CULLVISITOR 1
- #include <map>
- #include <vector>
- #include <osg/NodeVisitor>
- #include <osg/BoundingSphere>
- #include <osg/BoundingBox>
- #include <osg/Matrix>
- #include <osg/Drawable>
- #include <osg/StateSet>
- #include <osg/State>
- #include <osg/ClearNode>
- #include <osg/Camera>
- #include <osg/Notify>
- #include <osg/CullStack>
- #include <osgUtil/StateGraph>
- #include <osgUtil/RenderStage>
- #include <osg/Vec3>
- namespace osgUtil {
- /**
- * Basic NodeVisitor implementation for rendering a scene.
- * This visitor traverses the scene graph, collecting transparent and
- * opaque osg::Drawables into a depth sorted transparent bin and a state
- * sorted opaque bin. The opaque bin is rendered first, and then the
- * transparent bin is rendered in order from the furthest osg::Drawable
- * from the eye to the one nearest the eye.
- */
- class OSGUTIL_EXPORT CullVisitor : public osg::NodeVisitor, public osg::CullStack
- {
- public:
- typedef osg::Matrix::value_type value_type;
- CullVisitor();
- /// Copy constructor that does a shallow copy.
- CullVisitor(const CullVisitor&);
- META_NodeVisitor(osgUtil, CullVisitor)
- /** Convert 'this' into a osgUtil::CullVisitor pointer if Object is a osgUtil::CullVisitor, otherwise return 0.
- * Equivalent to dynamic_cast<osgUtil::CullVisitor*>(this).*/
- virtual osgUtil::CullVisitor* asCullVisitor() { return this; }
- /** convert 'const this' into a const osgUtil::CullVisitor pointer if Object is a osgUtil::CullVisitor, otherwise return 0.
- * Equivalent to dynamic_cast<const osgUtil::CullVisitor*>(this).*/
- virtual const osgUtil::CullVisitor* asCullVisitor() const { return this; }
- /** Convert 'this' into a osg::CullStack pointer if Object is a osg::CullStack, otherwise return 0.
- * Equivalent to dynamic_cast<osg::CullStack*>(this).*/
- virtual osg::CullStack* asCullStack() { return static_cast<osg::CullStack*>(this); }
- /** convert 'const this' into a const osg::CullStack pointer if Object is a osg::CullStack, otherwise return 0.
- * Equivalent to dynamic_cast<const osg::CullStack*>(this).*/
- virtual const osg::CullStack* asCullStack() const { return static_cast<const osg::CullStack*>(this); }
- using osg::NodeVisitor::clone;
- /** Create a shallow copy of the CullVisitor, used by CullVisitor::create() to clone the prototype. */
- virtual CullVisitor* clone() const { return new CullVisitor(*this); }
- /** get the prototype singleton used by CullVisitor::create().*/
- static osg::ref_ptr<CullVisitor>& prototype();
- /** create a CullVisitor by cloning CullVisitor::prototype().*/
- static CullVisitor* create();
- virtual void reset();
- struct Identifier : public osg::Referenced
- {
- Identifier() {}
- virtual ~Identifier() {}
- };
- void setIdentifier(Identifier* identifier) { _identifier = identifier; }
- Identifier* getIdentifier() { return _identifier.get(); }
- const Identifier* getIdentifier() const { return _identifier.get(); }
- virtual osg::Vec3 getEyePoint() const { return getEyeLocal(); }
- virtual osg::Vec3 getViewPoint() const { return getViewPointLocal(); }
- virtual float getDistanceToEyePoint(const osg::Vec3& pos, bool withLODScale) const;
- virtual float getDistanceFromEyePoint(const osg::Vec3& pos, bool withLODScale) const;
- virtual float getDistanceToViewPoint(const osg::Vec3& pos, bool withLODScale) const;
- virtual void apply(osg::Node&);
- virtual void apply(osg::Geode& node);
- virtual void apply(osg::Drawable& drawable);
- virtual void apply(osg::Billboard& node);
- virtual void apply(osg::LightSource& node);
- virtual void apply(osg::ClipNode& node);
- virtual void apply(osg::TexGenNode& node);
- virtual void apply(osg::Group& node);
- virtual void apply(osg::Transform& node);
- virtual void apply(osg::Projection& node);
- virtual void apply(osg::Switch& node);
- virtual void apply(osg::LOD& node);
- virtual void apply(osg::ClearNode& node);
- virtual void apply(osg::Camera& node);
- virtual void apply(osg::OccluderNode& node);
- virtual void apply(osg::OcclusionQueryNode& node);
- /** Push state set on the current state group.
- * If the state exists in a child state group of the current
- * state group then move the current state group to that child.
- * Otherwise, create a new state group for the state set, add
- * it to the current state group then move the current state
- * group pointer to the new state group.
- */
- inline void pushStateSet(const osg::StateSet* ss)
- {
- _currentStateGraph = _currentStateGraph->find_or_insert(ss);
- bool useRenderBinDetails = (ss->useRenderBinDetails() && !ss->getBinName().empty()) &&
- (_numberOfEncloseOverrideRenderBinDetails==0 || (ss->getRenderBinMode()&osg::StateSet::PROTECTED_RENDERBIN_DETAILS)!=0);
- if (useRenderBinDetails)
- {
- _renderBinStack.push_back(_currentRenderBin);
- _currentRenderBin = ss->getNestRenderBins() ?
- _currentRenderBin->find_or_insert(ss->getBinNumber(),ss->getBinName()) :
- _currentRenderBin->getStage()->find_or_insert(ss->getBinNumber(),ss->getBinName());
- }
- if ((ss->getRenderBinMode()&osg::StateSet::OVERRIDE_RENDERBIN_DETAILS)!=0)
- {
- ++_numberOfEncloseOverrideRenderBinDetails;
- }
- }
- /** Pop the top state set and hence associated state group.
- * Move the current state group to the parent of the popped
- * state group.
- */
- inline void popStateSet()
- {
- const osg::StateSet* ss = _currentStateGraph->getStateSet();
- if ((ss->getRenderBinMode()&osg::StateSet::OVERRIDE_RENDERBIN_DETAILS)!=0)
- {
- --_numberOfEncloseOverrideRenderBinDetails;
- }
- bool useRenderBinDetails = (ss->useRenderBinDetails() && !ss->getBinName().empty()) &&
- (_numberOfEncloseOverrideRenderBinDetails==0 || (ss->getRenderBinMode()&osg::StateSet::PROTECTED_RENDERBIN_DETAILS)!=0);
- if (useRenderBinDetails)
- {
- if (_renderBinStack.empty())
- {
- _currentRenderBin = _currentRenderBin->getStage();
- }
- else
- {
- _currentRenderBin = _renderBinStack.back();
- _renderBinStack.pop_back();
- }
- }
- _currentStateGraph = _currentStateGraph->_parent;
- }
- inline void setStateGraph(StateGraph* rg)
- {
- _rootStateGraph = rg;
- _currentStateGraph = rg;
- }
- inline StateGraph* getRootStateGraph()
- {
- return _rootStateGraph.get();
- }
- inline StateGraph* getCurrentStateGraph()
- {
- return _currentStateGraph;
- }
- inline void setRenderStage(RenderStage* rg)
- {
- _rootRenderStage = rg;
- _currentRenderBin = rg;
- }
- inline RenderStage* getRenderStage()
- {
- return _rootRenderStage.get();
- }
- inline RenderStage* getCurrentRenderStage()
- {
- return _currentRenderBin->getStage();
- }
- inline osg::Camera* getCurrentCamera()
- {
- return getCurrentRenderStage()->getCamera();
- }
- inline RenderBin* getCurrentRenderBin()
- {
- return _currentRenderBin;
- }
- inline void setCurrentRenderBin(RenderBin* rb)
- {
- _currentRenderBin = rb;
- }
- void setCalculatedNearPlane(value_type value) { _computed_znear = value; }
- inline value_type getCalculatedNearPlane() const { return _computed_znear; }
- void setCalculatedFarPlane(value_type value) { _computed_zfar = value; }
- inline value_type getCalculatedFarPlane() const { return _computed_zfar; }
- value_type computeNearestPointInFrustum(const osg::Matrix& matrix, const osg::Polytope::PlaneList& planes,const osg::Drawable& drawable);
- value_type computeFurthestPointInFrustum(const osg::Matrix& matrix, const osg::Polytope::PlaneList& planes,const osg::Drawable& drawable);
- bool updateCalculatedNearFar(const osg::Matrix& matrix,const osg::BoundingBox& bb);
- bool updateCalculatedNearFar(const osg::Matrix& matrix,const osg::Drawable& drawable, bool isBillboard=false);
- void updateCalculatedNearFar(const osg::Vec3& pos);
- /** Add a drawable to current render graph.*/
- inline void addDrawable(osg::Drawable* drawable,osg::RefMatrix* matrix);
- /** Add a drawable and depth to current render graph.*/
- inline void addDrawableAndDepth(osg::Drawable* drawable,osg::RefMatrix* matrix,float depth);
- /** Add an attribute which is positioned relative to the modelview matrix.*/
- inline void addPositionedAttribute(osg::RefMatrix* matrix,const osg::StateAttribute* attr);
- /** Add an attribute which is positioned relative to the modelview matrix.*/
- inline void addPositionedTextureAttribute(unsigned int textureUnit, osg::RefMatrix* matrix,const osg::StateAttribute* attr);
- /** compute near plane based on the polgon intersection of primtives in near plane candidate list of drawables.
- * 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. */
- void computeNearPlane();
- /** Re-implement CullStack's popProjectionMatrix() adding clamping of the projection matrix to
- * the computed near and far.*/
- virtual void popProjectionMatrix();
- /** CullVisitor's default clamping of the projection float matrix to computed near and far values.
- * Note, do not call this method directly, use clampProjectionMatrix(..) instead, unless you want to bypass the callback.*/
- virtual bool clampProjectionMatrixImplementation(osg::Matrixf& projection, double& znear, double& zfar) const;
- /** CullVisitor's default clamping of the projection double matrix to computed near and far values.
- * Note, do not call this method directly, use clampProjectionMatrix(..) instead, unless you want to bypass the callback.*/
- virtual bool clampProjectionMatrixImplementation(osg::Matrixd& projection, double& znear, double& zfar) const;
- /** Clamp the projection float matrix to computed near and far values, use callback if it exists,
- * otherwise use default CullVisitor implementation.*/
- inline bool clampProjectionMatrix(osg::Matrixf& projection, value_type& znear, value_type& zfar) const
- {
- double zn = znear;
- double zf = zfar;
- bool result = false;
- if (_clampProjectionMatrixCallback.valid()) result = _clampProjectionMatrixCallback->clampProjectionMatrixImplementation(projection, zn, zf);
- else result = clampProjectionMatrixImplementation(projection, zn, zf);
- if (result)
- {
- znear = zn;
- zfar = zf;
- return true;
- }
- else
- return false;
- }
- /** Clamp the projection double matrix to computed near and far values, use callback if it exists,
- * otherwise use default CullVisitor implementation.*/
- inline bool clampProjectionMatrix(osg::Matrixd& projection, value_type& znear, value_type& zfar) const
- {
- double zn = znear;
- double zf = zfar;
- bool result = false;
- if (_clampProjectionMatrixCallback.valid()) result = _clampProjectionMatrixCallback->clampProjectionMatrixImplementation(projection, zn, zf);
- else result = clampProjectionMatrixImplementation(projection, zn, zf);
- if (result)
- {
- znear = zn;
- zfar = zf;
- return true;
- }
- else
- return false;
- }
- void setState(osg::State* state) { _renderInfo.setState(state); }
- osg::State* getState() { return _renderInfo.getState(); }
- const osg::State* getState() const { return _renderInfo.getState(); }
- void setRenderInfo(osg::RenderInfo& renderInfo) { _renderInfo = renderInfo; }
- osg::RenderInfo& getRenderInfo() { return _renderInfo; }
- const osg::RenderInfo& getRenderInfo() const { return _renderInfo; }
- protected:
- virtual ~CullVisitor();
- /** Prevent unwanted copy operator.*/
- CullVisitor& operator = (const CullVisitor&) { return *this; }
- inline void handle_cull_callbacks_and_traverse(osg::Node& node)
- {
- osg::Callback* callback = node.getCullCallback();
- if (callback) callback->run(&node,this);
- else traverse(node);
- }
- inline void handle_cull_callbacks_and_accept(osg::Node& node,osg::Node* acceptNode)
- {
- osg::Callback* callback = node.getCullCallback();
- if (callback) callback->run(&node,this);
- else acceptNode->accept(*this);
- }
- osg::ref_ptr<StateGraph> _rootStateGraph;
- StateGraph* _currentStateGraph;
- osg::ref_ptr<RenderStage> _rootRenderStage;
- RenderBin* _currentRenderBin;
- std::vector<RenderBin*> _renderBinStack;
- value_type _computed_znear;
- value_type _computed_zfar;
- unsigned int _traversalOrderNumber;
- typedef std::vector< osg::ref_ptr<RenderLeaf> > RenderLeafList;
- RenderLeafList _reuseRenderLeafList;
- unsigned int _currentReuseRenderLeafIndex;
- inline RenderLeaf* createOrReuseRenderLeaf(osg::Drawable* drawable,osg::RefMatrix* projection,osg::RefMatrix* matrix, float depth=0.0f);
- unsigned int _numberOfEncloseOverrideRenderBinDetails;
- osg::RenderInfo _renderInfo;
- struct MatrixPlanesDrawables
- {
- MatrixPlanesDrawables():
- _drawable(0)
- {
- }
- void set(const osg::Matrix& matrix, const osg::Drawable* drawable, const osg::Polytope& frustum)
- {
- _matrix = matrix;
- _drawable = drawable;
- if (!_planes.empty()) _planes.clear();
- // create a new list of planes from the active walls of the frustum.
- osg::Polytope::ClippingMask result_mask = frustum.getResultMask();
- osg::Polytope::ClippingMask selector_mask = 0x1;
- for(osg::Polytope::PlaneList::const_iterator itr=frustum.getPlaneList().begin();
- itr!=frustum.getPlaneList().end();
- ++itr)
- {
- if (result_mask&selector_mask) _planes.push_back(*itr);
- selector_mask <<= 1;
- }
- }
- MatrixPlanesDrawables(const MatrixPlanesDrawables& mpd):
- _matrix(mpd._matrix),
- _drawable(mpd._drawable),
- _planes(mpd._planes) {}
- MatrixPlanesDrawables& operator = (const MatrixPlanesDrawables& mpd)
- {
- _matrix = mpd._matrix;
- _drawable = mpd._drawable;
- _planes = mpd._planes;
- return *this;
- }
- osg::Matrix _matrix;
- const osg::Drawable* _drawable;
- osg::Polytope::PlaneList _planes;
- };
- typedef std::multimap<value_type, MatrixPlanesDrawables> DistanceMatrixDrawableMap;
- DistanceMatrixDrawableMap _nearPlaneCandidateMap;
- DistanceMatrixDrawableMap _farPlaneCandidateMap;
- osg::ref_ptr<Identifier> _identifier;
- };
- inline void CullVisitor::addDrawable(osg::Drawable* drawable,osg::RefMatrix* matrix)
- {
- if (_currentStateGraph->leaves_empty())
- {
- // this is first leaf to be added to StateGraph
- // and therefore should not already know to current render bin,
- // so need to add it.
- _currentRenderBin->addStateGraph(_currentStateGraph);
- }
- //_currentStateGraph->addLeaf(new RenderLeaf(drawable,matrix));
- _currentStateGraph->addLeaf(createOrReuseRenderLeaf(drawable,_projectionStack.back().get(),matrix));
- }
- /** Add a drawable and depth to current render graph.*/
- inline void CullVisitor::addDrawableAndDepth(osg::Drawable* drawable,osg::RefMatrix* matrix,float depth)
- {
- if (_currentStateGraph->leaves_empty())
- {
- // this is first leaf to be added to StateGraph
- // and therefore should not already know to current render bin,
- // so need to add it.
- _currentRenderBin->addStateGraph(_currentStateGraph);
- }
- //_currentStateGraph->addLeaf(new RenderLeaf(drawable,matrix,depth));
- _currentStateGraph->addLeaf(createOrReuseRenderLeaf(drawable,_projectionStack.back().get(),matrix,depth));
- }
- /** Add an attribute which is positioned relative to the modelview matrix.*/
- inline void CullVisitor::addPositionedAttribute(osg::RefMatrix* matrix,const osg::StateAttribute* attr)
- {
- _currentRenderBin->getStage()->addPositionedAttribute(matrix,attr);
- }
- /** Add an attribute which is positioned relative to the modelview matrix.*/
- inline void CullVisitor::addPositionedTextureAttribute(unsigned int textureUnit, osg::RefMatrix* matrix,const osg::StateAttribute* attr)
- {
- _currentRenderBin->getStage()->addPositionedTextureAttribute(textureUnit,matrix,attr);
- }
- inline RenderLeaf* CullVisitor::createOrReuseRenderLeaf(osg::Drawable* drawable,osg::RefMatrix* projection,osg::RefMatrix* matrix, float depth)
- {
- // Skips any already reused renderleaf.
- while (_currentReuseRenderLeafIndex<_reuseRenderLeafList.size() &&
- _reuseRenderLeafList[_currentReuseRenderLeafIndex]->referenceCount()>1)
- {
- osg::notify(osg::INFO)<<"CullVisitor:createOrReuseRenderLeaf() skipping multiply referenced entry. _reuseRenderLeafList.size()="<< _reuseRenderLeafList.size()<<" _reuseRenderLeafList["<<_currentReuseRenderLeafIndex<<"]->referenceCount()="<<_reuseRenderLeafList[_currentReuseRenderLeafIndex]->referenceCount()<<std::endl;
- ++_currentReuseRenderLeafIndex;
- }
- // If still within list, element must be singularly referenced then return it to be reused.
- if (_currentReuseRenderLeafIndex<_reuseRenderLeafList.size())
- {
- RenderLeaf* renderleaf = _reuseRenderLeafList[_currentReuseRenderLeafIndex++].get();
- renderleaf->set(drawable,projection,matrix,depth,_traversalOrderNumber++);
- return renderleaf;
- }
- // Otherwise need to create new renderleaf.
- RenderLeaf* renderleaf = new RenderLeaf(drawable,projection,matrix,depth,_traversalOrderNumber++);
- _reuseRenderLeafList.push_back(renderleaf);
- ++_currentReuseRenderLeafIndex;
- return renderleaf;
- }
- }
- #endif
|