3351306d80
in progress for the new support for controlling the projection matrix from within the scene graph. Also Added osg::State::getClippingVolume(), getProjectionMatrix() and getModelViewMatrix() with allows drawables to access the current projection, and model view matrices and the view frustum in local coords to the drawable.
392 lines
14 KiB
Plaintext
392 lines
14 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_NEWCULLVISITOR
|
|
#define OSGUTIL_NEWCULLVISITOR 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 NewCullVisitor : public osg::NodeVisitor
|
|
{
|
|
public:
|
|
|
|
NewCullVisitor();
|
|
virtual ~NewCullVisitor();
|
|
|
|
virtual NewCullVisitor* cloneType() const { return new NewCullVisitor(); }
|
|
|
|
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::Projection& 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 NewCullVisitor to use the Impostor
|
|
* LOD children for rendering. Setting active to true forces the
|
|
* NewCullVisitor 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 NewCullVisitor 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(); }
|
|
|
|
inline void pushCullViewState() { pushCullViewState_ModelView(NULL,NULL); }
|
|
|
|
void pushCullViewState_Projection(osg::Matrix* matrix);
|
|
void pushCullViewState_ModelView(osg::Matrix* matrix);
|
|
void pushCullViewState_ModelView(osg::Matrix* matrix,osg::Matrix* inverse);
|
|
|
|
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; }
|
|
|
|
protected:
|
|
|
|
/** prevent unwanted copy construction.*/
|
|
NewCullVisitor(const NewCullVisitor&):osg::NodeVisitor() {}
|
|
|
|
/** prevent unwanted copy operator.*/
|
|
NewCullVisitor& operator = (const NewCullVisitor&) { 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);
|
|
|
|
/**calculates near for "global" vertex in scene*/
|
|
double calculateZNear(const osg::Vec3& position, const osg::Vec3& eye, const osg::Vec3& look);
|
|
|
|
|
|
/** 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,_cvs->_projection.get(),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,_cvs->_projection.get(),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);
|
|
|
|
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* projection,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,projection,matrix,depth);
|
|
return renderleaf;
|
|
}
|
|
|
|
// otherwise need to create new renderleaf.
|
|
RenderLeaf* renderleaf = new RenderLeaf(drawable,projection,matrix,depth);
|
|
_reuseRenderLeafList.push_back(renderleaf);
|
|
++_currentReuseRenderLeafIndex;
|
|
return renderleaf;
|
|
}
|
|
|
|
osg::ref_ptr<osg::ImpostorSpriteManager> _impostorSpriteManager;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|
|
|