by adding a ComputeTransformCallback to osg::Transform, and have now removed the recently added AutoTransform since it is nolonger required. Have also updated CullVisitor to account for the new ways for tracking transformation matrices in the scene.
411 lines
15 KiB
Plaintext
411 lines
15 KiB
Plaintext
//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield
|
|
//Distributed under the terms of the GNU Library General Public License (LGPL)
|
|
//as published by the Free Software Foundation.
|
|
|
|
#ifndef OSGUTIL_CULLVISITOR
|
|
#define OSGUTIL_CULLVISITOR 1
|
|
|
|
#include <osg/NodeVisitor>
|
|
#include <osg/BoundingSphere>
|
|
#include <osg/BoundingBox>
|
|
#include <osg/Matrix>
|
|
#include <osg/Drawable>
|
|
#include <osg/StateSet>
|
|
#include <osg/State>
|
|
#include <osg/Camera>
|
|
#include <osg/Impostor>
|
|
#include <osg/EarthSky>
|
|
#include <osg/Notify>
|
|
|
|
#include <osgUtil/RenderGraph>
|
|
#include <osgUtil/RenderStage>
|
|
#include <osgUtil/CullViewState>
|
|
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
#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 in 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:
|
|
|
|
CullVisitor();
|
|
virtual ~CullVisitor();
|
|
|
|
virtual void reset();
|
|
|
|
virtual void apply(osg::Node&);
|
|
virtual void apply(osg::Geode& node);
|
|
virtual void apply(osg::Billboard& node);
|
|
virtual void apply(osg::LightSource& node);
|
|
|
|
virtual void apply(osg::Group& node);
|
|
virtual void apply(osg::Transform& node);
|
|
virtual void apply(osg::Switch& node);
|
|
virtual void apply(osg::LOD& node);
|
|
virtual void apply(osg::EarthSky& node);
|
|
virtual void apply(osg::Impostor& node);
|
|
|
|
|
|
|
|
void setCamera(const osg::Camera& camera);
|
|
const osg::Camera* getCamera() const { return _camera.get(); }
|
|
|
|
|
|
void setEarthSky(const osg::EarthSky* earthSky) { _earthSky = earthSky; }
|
|
const osg::EarthSky* getEarthSky() const { return _earthSky.get(); }
|
|
|
|
|
|
void setLODBias(const float bias) { _LODBias = bias; }
|
|
const float getLODBias() const { return _LODBias; }
|
|
|
|
/** Switch the creation of Impostors on or off.
|
|
* Setting active to false forces the CullVisitor to use the Impostor
|
|
* LOD children for rendering. Setting active to true forces the
|
|
* CullVisitor to create the appropriate pre-rendering stages which
|
|
* render to the ImpostorSprite's texture.*/
|
|
void setImpostorsActive(const bool active) { _impostorActive = active; }
|
|
|
|
/** Get whether impostors are active or not. */
|
|
const bool getImpostorsActive() const { return _impostorActive; }
|
|
|
|
/** Set the impostor error threshold.
|
|
* Used in calculation of whether impostors remain valid.*/
|
|
void setImpostorPixelErrorThreshold(const float numPixels) { _impostorPixelErrorThreshold=numPixels; }
|
|
|
|
/** Get the impostor error threshold.*/
|
|
const float getImpostorPixelErrorThreshold() const { return _impostorPixelErrorThreshold; }
|
|
|
|
/** Set whether ImpsotorSprite's should be placed in a depth sorted bin for rendering.*/
|
|
void setDepthSortImpostorSprites(const bool doDepthSort) { _depthSortImpostorSprites = doDepthSort; }
|
|
|
|
/** Get whether ImpsotorSprite's are depth sorted bin for rendering.*/
|
|
const bool setDepthSortImpostorSprites() const { return _depthSortImpostorSprites; }
|
|
|
|
/** Set the number of frames that an ImpsotorSprite's is kept whilst not being beyond,
|
|
* before being recycled.*/
|
|
void setNumberOfFrameToKeepImpostorSprites(const int numFrames) { _numFramesToKeepImpostorSprites = numFrames; }
|
|
|
|
/** Get the number of frames that an ImpsotorSprite's is kept whilst not being beyond,
|
|
* before being recycled.*/
|
|
const int getNumberOfFrameToKeepImpostorSprites() const { return _numFramesToKeepImpostorSprites; }
|
|
|
|
enum TransparencySortMode {
|
|
LOOK_VECTOR_DISTANCE,
|
|
OBJECT_EYE_POINT_DISTANCE
|
|
};
|
|
|
|
void setTransparencySortMode(TransparencySortMode tsm) { _tsm = tsm; }
|
|
|
|
/** Sets the current CullingMode.*/
|
|
void setCullingMode(CullViewState::CullingMode mode);
|
|
|
|
/** Returns the current CullingMode.*/
|
|
CullViewState::CullingMode getCullingMode() const;
|
|
|
|
|
|
/** Set the viewport.
|
|
* Used to enable the CullVisitor can make decision
|
|
* such as based on viewport dimensions.*/
|
|
void setViewport(osg::Viewport* viewport) { _viewport = viewport; }
|
|
|
|
/** Get the const viewport. */
|
|
const osg::Viewport* getViewport() const { return _viewport.get(); }
|
|
|
|
/** Get the viewport. */
|
|
osg::Viewport* getViewport() { return _viewport.get(); }
|
|
|
|
void pushCullViewState(osg::Matrix* matrix=NULL);
|
|
void popCullViewState();
|
|
|
|
/** 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)
|
|
{
|
|
_currentRenderGraph = _currentRenderGraph->find_or_insert(ss);
|
|
if (ss->useRenderBinDetails())
|
|
{
|
|
_currentRenderBin = _currentRenderBin->find_or_insert(ss->getBinNumber(),ss->getBinName());
|
|
}
|
|
}
|
|
|
|
/** 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()
|
|
{
|
|
if (_currentRenderGraph->_stateset->useRenderBinDetails())
|
|
{
|
|
_currentRenderBin = _currentRenderBin->_parent;
|
|
}
|
|
_currentRenderGraph = _currentRenderGraph->_parent;
|
|
}
|
|
|
|
void setRenderGraph(RenderGraph* rg)
|
|
{
|
|
_rootRenderGraph = rg;
|
|
_currentRenderGraph = rg;
|
|
}
|
|
|
|
RenderGraph* getRenderGraph()
|
|
{
|
|
return _rootRenderGraph.get();
|
|
}
|
|
|
|
void setRenderStage(RenderStage* rg)
|
|
{
|
|
_rootRenderStage = rg;
|
|
_currentRenderBin = rg;
|
|
}
|
|
|
|
RenderStage* getRenderStage()
|
|
{
|
|
return _rootRenderStage.get();
|
|
}
|
|
|
|
const float getCalculatedNearPlane() const { return _calculated_znear; }
|
|
|
|
const float getCalculatedFarPlane() const { return _calculated_zfar; }
|
|
|
|
//SandB
|
|
/**sets the flag for detailed culling*/
|
|
void setDetailedCulling(bool detailed) {_detailedCulling = detailed;}
|
|
|
|
/**gets the status of detailed culling*/
|
|
const bool getDetailedCulling() const {return _detailedCulling;}
|
|
|
|
/**calculates unit directions of vectors that are intersections of cameras' clipping planes*/
|
|
void calcClippingDirections() const;
|
|
|
|
protected:
|
|
|
|
/** prevent unwanted copy construction.*/
|
|
CullVisitor(const CullVisitor&):osg::NodeVisitor() {}
|
|
|
|
/** prevent unwanted copy operator.*/
|
|
CullVisitor& operator = (const CullVisitor&) { return *this; }
|
|
|
|
inline osg::Matrix* getCurrentMatrix()
|
|
{
|
|
return _cvs->_matrix.get();
|
|
}
|
|
|
|
|
|
inline osg::Matrix* getInverseCurrentMatrix()
|
|
{
|
|
return _cvs->_inverse.get();
|
|
}
|
|
|
|
inline const osg::Vec3& getEyeLocal() const
|
|
{
|
|
return _cvs->_eyePoint;
|
|
}
|
|
|
|
inline const osg::Vec3& getUpLocal() const
|
|
{
|
|
return _cvs->_upVector;
|
|
}
|
|
|
|
inline const osg::Vec3& getCenterLocal() const
|
|
{
|
|
return _cvs->_centerPoint;
|
|
}
|
|
|
|
|
|
inline const osg::Vec3& getLookVectorLocal() const
|
|
{
|
|
return _cvs->_lookVector;
|
|
}
|
|
|
|
|
|
inline bool isCulled(const osg::BoundingSphere& sp,CullViewState::CullingMode& mode) const
|
|
{
|
|
return _cvs->isCulled(sp,mode);
|
|
}
|
|
|
|
inline const bool isCulled(const osg::BoundingBox& bb,const CullViewState::CullingMode mode) const
|
|
{
|
|
return _cvs->isCulled(bb,mode);
|
|
}
|
|
|
|
void updateCalculatedNearFar(const osg::BoundingBox& bb);
|
|
|
|
void updateCalculatedNearFar(const osg::Vec3& pos);
|
|
|
|
|
|
//SandB added: ////////////////////////////////////////////////////////////////////////////////
|
|
/**updates near and far clipping values for case of detailed culling*/
|
|
void updateCalculatedNearFar(osg::Drawable* pDrawable);
|
|
|
|
/**calculates near for "global" vertex in scene*/
|
|
double calculateZNear(const osg::Vec3& position, const osg::Vec3& eye, const osg::Vec3& look);
|
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**unit vector of direction along intersection of cameras left and top clipping planes in "global" coordinates*/
|
|
mutable osg::Vec3 _LeftUp;
|
|
/**unit vector of direction along intersection of cameras right and top clipping planes in "global" coordinates*/
|
|
mutable osg::Vec3 _RightUp;
|
|
/**unit vector of direction along intersection of cameras left and down clipping planes in "global" coordinates*/
|
|
mutable osg::Vec3 _LeftDown;
|
|
/**unit vector of direction along intersection of cameras right and down clipping planes in "global" coordinates*/
|
|
mutable osg::Vec3 _RightDown;
|
|
|
|
|
|
/** Add a drawable to current render graph.*/
|
|
inline void addDrawable(osg::Drawable* drawable,osg::Matrix* matrix)
|
|
{
|
|
if (_currentRenderGraph->leaves_empty())
|
|
{
|
|
// this is first leaf to be added to RenderGraph
|
|
// and therefore should not already know to current render bin,
|
|
// so need to add it.
|
|
_currentRenderBin->addRenderGraph(_currentRenderGraph);
|
|
}
|
|
//_currentRenderGraph->addLeaf(new RenderLeaf(drawable,matrix));
|
|
_currentRenderGraph->addLeaf(createOrReuseRenderLeaf(drawable,matrix));
|
|
}
|
|
|
|
/** Add a drawable and depth to current render graph.*/
|
|
inline void addDrawableAndDepth(osg::Drawable* drawable,osg::Matrix* matrix,const float depth)
|
|
{
|
|
if (_currentRenderGraph->leaves_empty())
|
|
{
|
|
// this is first leaf to be added to RenderGraph
|
|
// and therefore should not already know to current render bin,
|
|
// so need to add it.
|
|
_currentRenderBin->addRenderGraph(_currentRenderGraph);
|
|
}
|
|
//_currentRenderGraph->addLeaf(new RenderLeaf(drawable,matrix,depth));
|
|
_currentRenderGraph->addLeaf(createOrReuseRenderLeaf(drawable,matrix,depth));
|
|
}
|
|
|
|
/** Add a light to current render graph.*/
|
|
inline void addLight(osg::Light* light,osg::Matrix* matrix)
|
|
{
|
|
_currentRenderBin->_stage->addLight(light,matrix);
|
|
}
|
|
|
|
/** create an impostor sprite by setting up a pre-rendering stage
|
|
* to generate the impostor texture. */
|
|
osg::ImpostorSprite* createImpostorSprite(osg::Impostor& node);
|
|
|
|
bool _detailedCulling;
|
|
|
|
typedef std::vector< osg::ref_ptr<CullViewState> > CullViewStateStack;
|
|
CullViewStateStack _viewStateStack;
|
|
osg::ref_ptr<CullViewState> _tvs;
|
|
osg::ref_ptr<CullViewState> _cvs;
|
|
|
|
osg::ref_ptr<RenderGraph> _rootRenderGraph;
|
|
RenderGraph* _currentRenderGraph;
|
|
|
|
osg::ref_ptr<RenderStage> _rootRenderStage;
|
|
RenderBin* _currentRenderBin;
|
|
|
|
std::vector<CullViewState::CullingMode> _cullingModeStack;
|
|
|
|
float _LODBias;
|
|
|
|
float _calculated_znear;
|
|
float _calculated_zfar;
|
|
|
|
osg::ref_ptr<const osg::Camera> _camera;
|
|
|
|
osg::ref_ptr<const osg::EarthSky> _earthSky;
|
|
|
|
TransparencySortMode _tsm;
|
|
|
|
// viewport x,y,width,height respectively.
|
|
osg::ref_ptr<osg::Viewport> _viewport;
|
|
|
|
bool _impostorActive;
|
|
bool _depthSortImpostorSprites;
|
|
float _impostorPixelErrorThreshold;
|
|
int _numFramesToKeepImpostorSprites;
|
|
|
|
typedef std::vector< osg::ref_ptr<osg::Matrix> > MatrixList;
|
|
MatrixList _reuseMatrixList;
|
|
unsigned int _currentReuseMatrixIndex;
|
|
|
|
inline osg::Matrix* createOrReuseMatrix()
|
|
{
|
|
// skip of any already reused matrix.
|
|
while (_currentReuseMatrixIndex<_reuseMatrixList.size() &&
|
|
_reuseMatrixList[_currentReuseMatrixIndex]->referenceCount()>1)
|
|
{
|
|
osg::notify(osg::NOTICE)<<"Warning:createOrReuseMatrix() skipping multiply refrenced entry."<< std::endl;
|
|
++_currentReuseMatrixIndex;
|
|
}
|
|
|
|
// if still within list, element must be singularly referenced
|
|
// there return it to be reused.
|
|
if (_currentReuseMatrixIndex<_reuseMatrixList.size())
|
|
{
|
|
osg::Matrix* matrix = _reuseMatrixList[_currentReuseMatrixIndex++].get();
|
|
matrix->makeIdentity();
|
|
return matrix;
|
|
}
|
|
|
|
// otherwise need to create new matrix.
|
|
osg::Matrix* matrix = new osg::Matrix();
|
|
_reuseMatrixList.push_back(matrix);
|
|
++_currentReuseMatrixIndex;
|
|
return matrix;
|
|
}
|
|
|
|
typedef std::vector< osg::ref_ptr<RenderLeaf> > RenderLeafList;
|
|
RenderLeafList _reuseRenderLeafList;
|
|
unsigned int _currentReuseRenderLeafIndex;
|
|
|
|
inline RenderLeaf* createOrReuseRenderLeaf(osg::Drawable* drawable,osg::Matrix* matrix, float depth=0.0f)
|
|
{
|
|
// skip of any already reused renderleaf.
|
|
while (_currentReuseRenderLeafIndex<_reuseRenderLeafList.size() &&
|
|
_reuseRenderLeafList[_currentReuseRenderLeafIndex]->referenceCount()>1)
|
|
{
|
|
osg::notify(osg::NOTICE)<<"Warning:createOrReuseRenderLeaf() skipping multiply refrenced entry."<< std::endl;
|
|
++_currentReuseRenderLeafIndex;
|
|
}
|
|
|
|
// if still within list, element must be singularly referenced
|
|
// there return it to be reused.
|
|
if (_currentReuseRenderLeafIndex<_reuseRenderLeafList.size())
|
|
{
|
|
RenderLeaf* renderleaf = _reuseRenderLeafList[_currentReuseRenderLeafIndex++].get();
|
|
renderleaf->set(drawable,matrix,depth);
|
|
return renderleaf;
|
|
}
|
|
|
|
// otherwise need to create new renderleaf.
|
|
RenderLeaf* renderleaf = new RenderLeaf(drawable,matrix,depth);
|
|
_reuseRenderLeafList.push_back(renderleaf);
|
|
++_currentReuseRenderLeafIndex;
|
|
return renderleaf;
|
|
}
|
|
|
|
osg::ref_ptr<osg::ImpostorSpriteManager> _impostorSpriteManager;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|
|
|