2008-06-19 19:09:20 +08:00
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2008 Robert Osfield
2003-01-22 00:45:36 +08:00
*
* 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.
*/
2001-10-04 23:12:57 +08:00
2001-09-22 10:42:08 +08:00
#ifndef OSGUTIL_CULLVISITOR
#define OSGUTIL_CULLVISITOR 1
2001-09-20 05:19:47 +08:00
2004-08-04 16:27:43 +08:00
#include <map>
#include <vector>
2001-09-20 05:19:47 +08:00
#include <osg/NodeVisitor>
#include <osg/BoundingSphere>
#include <osg/BoundingBox>
#include <osg/Matrix>
#include <osg/Drawable>
#include <osg/StateSet>
#include <osg/State>
2002-08-19 19:42:37 +08:00
#include <osg/ClearNode>
2006-11-27 22:52:07 +08:00
#include <osg/Camera>
2001-09-20 05:19:47 +08:00
#include <osg/Notify>
2002-06-10 19:21:21 +08:00
#include <osg/CullStack>
2002-05-28 18:24:43 +08:00
2005-10-13 20:51:00 +08:00
#include <osgUtil/StateGraph>
2001-09-20 05:19:47 +08:00
#include <osgUtil/RenderStage>
2001-12-17 06:20:26 +08:00
#include <osg/Vec3>
2001-09-20 05:19:47 +08:00
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
2004-09-27 02:39:34 +08:00
* transparent bin is rendered in order from the furthest osg::Drawable
2001-09-20 05:19:47 +08:00
* from the eye to the one nearest the eye.
*/
2002-06-10 19:21:21 +08:00
class OSGUTIL_EXPORT CullVisitor : public osg::NodeVisitor, public osg::CullStack
2001-09-20 05:19:47 +08:00
{
public:
2003-09-03 18:47:25 +08:00
typedef osg::Matrix::value_type value_type;
2001-09-20 05:19:47 +08:00
CullVisitor();
2007-08-08 16:10:38 +08:00
/// Copy constructor that does a shallow copy.
CullVisitor(const CullVisitor&);
2007-08-09 16:19:58 +08:00
/** Create a shallow copy of the CullVisitor, used by CullVisitor::create() to clone the prototype..*/
2007-08-08 16:10:38 +08:00
virtual CullVisitor* clone() const { return new CullVisitor(*this); }
2001-09-20 05:19:47 +08:00
2007-08-08 16:10:38 +08:00
/** get the prototype singleton used by CullVisitor::create().*/
static osg::ref_ptr<CullVisitor>& prototype();
/** create a CullVisitor by cloning CullVisitor::prototype().*/
static CullVisitor* create();
2002-02-19 07:01:09 +08:00
2001-09-22 10:42:08 +08:00
virtual void reset();
2004-04-30 23:35:31 +08:00
2002-12-17 23:41:05 +08:00
virtual osg::Vec3 getEyePoint() const { return getEyeLocal(); }
2006-12-16 01:27:18 +08:00
virtual osg::Vec3 getViewPoint() const { return getViewPointLocal(); }
2002-11-12 18:22:38 +08:00
virtual float getDistanceToEyePoint(const osg::Vec3& pos, bool withLODScale) const;
virtual float getDistanceFromEyePoint(const osg::Vec3& pos, bool withLODScale) const;
2001-09-20 05:19:47 +08:00
2006-12-16 01:27:18 +08:00
virtual float getDistanceToViewPoint(const osg::Vec3& pos, bool withLODScale) const;
2001-09-20 05:19:47 +08:00
virtual void apply(osg::Node&);
virtual void apply(osg::Geode& node);
virtual void apply(osg::Billboard& node);
virtual void apply(osg::LightSource& node);
2002-05-02 08:14:40 +08:00
virtual void apply(osg::ClipNode& node);
2004-06-15 03:11:04 +08:00
virtual void apply(osg::TexGenNode& node);
2001-09-20 05:19:47 +08:00
virtual void apply(osg::Group& node);
virtual void apply(osg::Transform& node);
2002-04-01 00:40:44 +08:00
virtual void apply(osg::Projection& node);
2001-09-20 05:19:47 +08:00
virtual void apply(osg::Switch& node);
virtual void apply(osg::LOD& node);
2002-08-19 19:42:37 +08:00
virtual void apply(osg::ClearNode& node);
2006-11-27 22:52:07 +08:00
virtual void apply(osg::Camera& node);
2002-06-05 17:39:04 +08:00
virtual void apply(osg::OccluderNode& node);
2007-12-21 22:45:16 +08:00
virtual void apply(osg::OcclusionQueryNode& node);
2001-09-20 05:19:47 +08:00
/** 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)
{
2005-10-13 20:51:00 +08:00
_currentStateGraph = _currentStateGraph->find_or_insert(ss);
2008-06-19 19:09:20 +08:00
2006-07-12 05:53:57 +08:00
if (_numberOfEncloseOverrideRenderBinDetails==0 && ss->useRenderBinDetails() && !ss->getBinName().empty())
2001-09-20 05:19:47 +08:00
{
2008-06-19 19:09:20 +08:00
_renderBinStack.push_back(_currentRenderBin);
_currentRenderBin = ss->getNestRenderBins() ?
_currentRenderBin->find_or_insert(ss->getBinNumber(),ss->getBinName()) :
2008-06-19 20:02:20 +08:00
_currentRenderBin->getStage()->find_or_insert(ss->getBinNumber(),ss->getBinName());
2001-09-20 05:19:47 +08:00
}
2008-06-19 19:09:20 +08:00
2006-07-12 05:53:57 +08:00
if (ss->getRenderBinMode()==osg::StateSet::OVERRIDE_RENDERBIN_DETAILS)
{
++_numberOfEncloseOverrideRenderBinDetails;
}
2001-09-20 05:19:47 +08:00
}
/** 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()
{
2007-09-01 00:05:24 +08:00
const osg::StateSet* ss = _currentStateGraph->getStateSet();
2006-07-18 21:05:26 +08:00
if (ss->getRenderBinMode()==osg::StateSet::OVERRIDE_RENDERBIN_DETAILS)
{
--_numberOfEncloseOverrideRenderBinDetails;
}
2006-07-12 05:53:57 +08:00
if (_numberOfEncloseOverrideRenderBinDetails==0 && ss->useRenderBinDetails() && !ss->getBinName().empty())
2001-09-20 05:19:47 +08:00
{
2008-06-19 19:09:20 +08:00
if (_renderBinStack.empty())
{
_currentRenderBin = _currentRenderBin->getStage();
}
else
2006-07-12 05:53:57 +08:00
{
2008-06-19 19:09:20 +08:00
_currentRenderBin = _renderBinStack.back();
_renderBinStack.pop_back();
2006-07-12 05:53:57 +08:00
}
}
2005-10-13 20:51:00 +08:00
_currentStateGraph = _currentStateGraph->_parent;
2001-09-20 05:19:47 +08:00
}
2005-10-13 20:51:00 +08:00
inline void setStateGraph(StateGraph* rg)
2001-09-20 05:19:47 +08:00
{
2005-10-13 20:51:00 +08:00
_rootStateGraph = rg;
_currentStateGraph = rg;
2001-09-20 05:19:47 +08:00
}
2005-10-13 20:51:00 +08:00
inline StateGraph* getRootStateGraph()
2001-09-20 05:19:47 +08:00
{
2005-10-13 20:51:00 +08:00
return _rootStateGraph.get();
2001-09-20 05:19:47 +08:00
}
2005-10-13 20:51:00 +08:00
inline StateGraph* getCurrentStateGraph()
2002-05-22 20:01:12 +08:00
{
2005-10-13 20:51:00 +08:00
return _currentStateGraph;
2002-05-22 20:01:12 +08:00
}
2002-05-15 19:27:47 +08:00
inline void setRenderStage(RenderStage* rg)
2001-09-20 05:19:47 +08:00
{
_rootRenderStage = rg;
_currentRenderBin = rg;
}
2002-05-15 19:27:47 +08:00
inline RenderStage* getRenderStage()
2001-09-20 05:19:47 +08:00
{
return _rootRenderStage.get();
}
2002-05-15 19:27:47 +08:00
inline RenderBin* getCurrentRenderBin()
{
return _currentRenderBin;
}
2002-07-10 17:04:28 +08:00
inline void setCurrentRenderBin(RenderBin* rb)
{
_currentRenderBin = rb;
}
2004-01-30 04:14:20 +08:00
inline value_type getCalculatedNearPlane() const { return _computed_znear; }
2002-05-15 19:27:47 +08:00
2004-01-30 04:14:20 +08:00
inline value_type getCalculatedFarPlane() const { return _computed_zfar; }
2002-05-10 02:59:19 +08:00
2004-04-30 06:21:06 +08:00
value_type computeNearestPointInFrustum(const osg::Matrix& matrix, const osg::Polytope::PlaneList& planes,const osg::Drawable& drawable);
2004-09-27 02:39:34 +08:00
bool updateCalculatedNearFar(const osg::Matrix& matrix,const osg::BoundingBox& bb);
2004-04-30 06:21:06 +08:00
2004-09-27 02:39:34 +08:00
bool updateCalculatedNearFar(const osg::Matrix& matrix,const osg::Drawable& drawable, bool isBillboard=false);
void updateCalculatedNearFar(const osg::Vec3& pos);
2004-04-30 06:21:06 +08:00
2002-05-14 18:20:55 +08:00
/** Add a drawable to current render graph.*/
2003-01-10 17:25:42 +08:00
inline void addDrawable(osg::Drawable* drawable,osg::RefMatrix* matrix);
2002-05-14 18:20:55 +08:00
/** Add a drawable and depth to current render graph.*/
2003-01-10 17:25:42 +08:00
inline void addDrawableAndDepth(osg::Drawable* drawable,osg::RefMatrix* matrix,float depth);
2002-05-14 18:20:55 +08:00
2004-09-27 02:39:34 +08:00
/** Add an attribute which is positioned relative to the modelview matrix.*/
2003-01-10 17:25:42 +08:00
inline void addPositionedAttribute(osg::RefMatrix* matrix,const osg::StateAttribute* attr);
2002-05-10 02:59:19 +08:00
2004-09-27 02:39:34 +08:00
/** Add an attribute which is positioned relative to the modelview matrix.*/
2004-06-17 22:02:15 +08:00
inline void addPositionedTextureAttribute(unsigned int textureUnit, osg::RefMatrix* matrix,const osg::StateAttribute* attr);
2007-05-16 01:04:57 +08:00
/** 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();
2004-09-27 02:39:34 +08:00
/** Re-implement CullStack's popProjectionMatrix() adding clamping of the projection matrix to
* the computed near and far.*/
2003-01-10 17:25:42 +08:00
virtual void popProjectionMatrix();
2003-12-16 07:23:45 +08:00
2004-01-28 18:49:23 +08:00
/** 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.*/
2004-05-26 04:35:14 +08:00
virtual bool clampProjectionMatrixImplementation(osg::Matrixf& projection, double& znear, double& zfar) const;
2004-01-28 18:49:23 +08:00
/** 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.*/
2004-05-26 04:35:14 +08:00
virtual bool clampProjectionMatrixImplementation(osg::Matrixd& projection, double& znear, double& zfar) const;
2004-01-28 18:49:23 +08:00
2004-09-27 02:39:34 +08:00
/** Clamp the projection float matrix to computed near and far values, use callback if it exists,
* otherwise use default CullVisitor implementation.*/
2004-05-26 04:35:14 +08:00
inline bool clampProjectionMatrix(osg::Matrixf& projection, value_type& znear, value_type& zfar) const
2004-01-28 18:49:23 +08:00
{
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;
2007-08-18 00:10:45 +08:00
zfar = zf;
2004-01-28 18:49:23 +08:00
return true;
}
else
return false;
}
2004-09-27 02:39:34 +08:00
/** Clamp the projection double matrix to computed near and far values, use callback if it exists,
* otherwise use default CullVisitor implementation.*/
2004-07-27 03:40:02 +08:00
inline bool clampProjectionMatrix(osg::Matrixd& projection, value_type& znear, value_type& zfar) const
2004-01-28 18:49:23 +08:00
{
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;
2007-08-18 00:10:45 +08:00
zfar = zf;
2004-01-28 18:49:23 +08:00
return true;
}
else
return false;
}
2002-06-10 19:21:21 +08:00
2006-09-19 04:54:48 +08:00
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; }
2002-07-02 14:22:28 +08:00
2001-09-20 05:19:47 +08:00
protected:
2007-08-08 16:10:38 +08:00
virtual ~CullVisitor();
2004-09-27 02:39:34 +08:00
/** Prevent unwanted copy operator.*/
2001-09-20 05:19:47 +08:00
CullVisitor& operator = (const CullVisitor&) { return *this; }
2002-04-15 21:15:48 +08:00
inline void handle_cull_callbacks_and_traverse(osg::Node& node)
{
osg::NodeCallback* callback = node.getCullCallback();
if (callback) (*callback)(&node,this);
else traverse(node);
}
inline void handle_cull_callbacks_and_accept(osg::Node& node,osg::Node* acceptNode)
{
osg::NodeCallback* callback = node.getCullCallback();
if (callback) (*callback)(&node,this);
else acceptNode->accept(*this);
}
2005-10-13 20:51:00 +08:00
osg::ref_ptr<StateGraph> _rootStateGraph;
StateGraph* _currentStateGraph;
2001-09-20 05:19:47 +08:00
2002-05-28 18:24:43 +08:00
osg::ref_ptr<RenderStage> _rootRenderStage;
RenderBin* _currentRenderBin;
2008-06-19 19:09:20 +08:00
std::vector<RenderBin*> _renderBinStack;
2001-09-20 05:19:47 +08:00
2003-09-03 01:19:18 +08:00
2003-09-03 18:47:25 +08:00
value_type _computed_znear;
value_type _computed_zfar;
2001-09-20 05:19:47 +08:00
2002-05-15 19:27:47 +08:00
2004-09-27 02:39:34 +08:00
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);
2002-05-15 19:27:47 +08:00
2006-07-12 05:53:57 +08:00
unsigned int _numberOfEncloseOverrideRenderBinDetails;
2006-09-19 04:54:48 +08:00
osg::RenderInfo _renderInfo;
2004-04-30 06:21:06 +08:00
struct MatrixPlanesDrawables
{
MatrixPlanesDrawables(const osg::Matrix& matrix, const osg::Drawable* drawable, const osg::Polytope& frustum):
_matrix(matrix),
_drawable(drawable)
{
// 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;
2004-09-27 02:39:34 +08:00
2001-09-20 05:19:47 +08:00
};
2003-01-10 17:25:42 +08:00
inline void CullVisitor::addDrawable(osg::Drawable* drawable,osg::RefMatrix* matrix)
2002-05-15 19:27:47 +08:00
{
2005-10-13 20:51:00 +08:00
if (_currentStateGraph->leaves_empty())
2002-05-15 19:27:47 +08:00
{
2005-10-13 20:51:00 +08:00
// this is first leaf to be added to StateGraph
2002-05-15 19:27:47 +08:00
// and therefore should not already know to current render bin,
// so need to add it.
2005-10-13 20:51:00 +08:00
_currentRenderBin->addStateGraph(_currentStateGraph);
2002-05-15 19:27:47 +08:00
}
2005-10-13 20:51:00 +08:00
//_currentStateGraph->addLeaf(new RenderLeaf(drawable,matrix));
_currentStateGraph->addLeaf(createOrReuseRenderLeaf(drawable,_projectionStack.back().get(),matrix));
2002-05-15 19:27:47 +08:00
}
/** Add a drawable and depth to current render graph.*/
2003-01-10 17:25:42 +08:00
inline void CullVisitor::addDrawableAndDepth(osg::Drawable* drawable,osg::RefMatrix* matrix,float depth)
2002-05-15 19:27:47 +08:00
{
2005-10-13 20:51:00 +08:00
if (_currentStateGraph->leaves_empty())
2002-05-15 19:27:47 +08:00
{
2005-10-13 20:51:00 +08:00
// this is first leaf to be added to StateGraph
2002-05-15 19:27:47 +08:00
// and therefore should not already know to current render bin,
// so need to add it.
2005-10-13 20:51:00 +08:00
_currentRenderBin->addStateGraph(_currentStateGraph);
2002-05-15 19:27:47 +08:00
}
2005-10-13 20:51:00 +08:00
//_currentStateGraph->addLeaf(new RenderLeaf(drawable,matrix,depth));
_currentStateGraph->addLeaf(createOrReuseRenderLeaf(drawable,_projectionStack.back().get(),matrix,depth));
2002-05-15 19:27:47 +08:00
}
2004-09-27 02:39:34 +08:00
/** Add an attribute which is positioned relative to the modelview matrix.*/
2003-01-10 17:25:42 +08:00
inline void CullVisitor::addPositionedAttribute(osg::RefMatrix* matrix,const osg::StateAttribute* attr)
2002-05-15 19:27:47 +08:00
{
2004-08-02 20:19:50 +08:00
_currentRenderBin->getStage()->addPositionedAttribute(matrix,attr);
2002-05-15 19:27:47 +08:00
}
2004-09-27 02:39:34 +08:00
/** Add an attribute which is positioned relative to the modelview matrix.*/
2004-06-17 22:02:15 +08:00
inline void CullVisitor::addPositionedTextureAttribute(unsigned int textureUnit, osg::RefMatrix* matrix,const osg::StateAttribute* attr)
{
2004-08-02 20:19:50 +08:00
_currentRenderBin->getStage()->addPositionedTextureAttribute(textureUnit,matrix,attr);
2004-06-17 22:02:15 +08:00
}
2003-01-10 17:25:42 +08:00
inline RenderLeaf* CullVisitor::createOrReuseRenderLeaf(osg::Drawable* drawable,osg::RefMatrix* projection,osg::RefMatrix* matrix, float depth)
2002-05-15 19:27:47 +08:00
{
2004-09-27 02:39:34 +08:00
// Skips any already reused renderleaf.
2002-05-15 19:27:47 +08:00
while (_currentReuseRenderLeafIndex<_reuseRenderLeafList.size() &&
_reuseRenderLeafList[_currentReuseRenderLeafIndex]->referenceCount()>1)
{
osg::notify(osg::NOTICE)<<"Warning:createOrReuseRenderLeaf() skipping multiply refrenced entry."<< std::endl;
++_currentReuseRenderLeafIndex;
}
2004-09-27 02:39:34 +08:00
// If still within list, element must be singularly referenced then return it to be reused.
2002-05-15 19:27:47 +08:00
if (_currentReuseRenderLeafIndex<_reuseRenderLeafList.size())
{
RenderLeaf* renderleaf = _reuseRenderLeafList[_currentReuseRenderLeafIndex++].get();
renderleaf->set(drawable,projection,matrix,depth);
return renderleaf;
}
2004-09-27 02:39:34 +08:00
// Otherwise need to create new renderleaf.
2002-12-16 21:40:58 +08:00
RenderLeaf* renderleaf = new RenderLeaf(drawable,projection,matrix,depth);
2002-05-15 19:27:47 +08:00
_reuseRenderLeafList.push_back(renderleaf);
++_currentReuseRenderLeafIndex;
return renderleaf;
}
2002-02-03 20:33:41 +08:00
}
2001-09-20 05:19:47 +08:00
#endif