//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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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(); } inline void pushCullViewState() { pushCullViewState(NULL,NULL); } void pushCullViewState(osg::Matrix* matrix); void pushCullViewState(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; } //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 > CullViewStateStack; CullViewStateStack _viewStateStack; osg::ref_ptr _tvs; osg::ref_ptr _cvs; osg::ref_ptr _rootRenderGraph; RenderGraph* _currentRenderGraph; osg::ref_ptr _rootRenderStage; RenderBin* _currentRenderBin; std::vector _cullingModeStack; float _LODBias; float _calculated_znear; float _calculated_zfar; osg::ref_ptr _camera; osg::ref_ptr _earthSky; TransparencySortMode _tsm; // viewport x,y,width,height respectively. osg::ref_ptr _viewport; bool _impostorActive; bool _depthSortImpostorSprites; float _impostorPixelErrorThreshold; int _numFramesToKeepImpostorSprites; typedef std::vector< osg::ref_ptr > 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 > 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 _impostorSpriteManager; }; } #endif