/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 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 OSG_CullingSet #define OSG_CullingSet 1 #include #include #include #include namespace osg { #define COMPILE_WITH_SHADOW_OCCLUSION_CULLING /** A CullingSet class which contains a frustum and a list of occluders. */ class OSG_EXPORT CullingSet : public Referenced { public: typedef std::pair< osg::ref_ptr, osg::Polytope > StateFrustumPair; typedef std::vector< StateFrustumPair > StateFrustumList; CullingSet(); CullingSet(const CullingSet& cs): Referenced(), _mask(cs._mask), _frustum(cs._frustum), _stateFrustumList(cs._stateFrustumList), _occluderList(cs._occluderList), _pixelSizeVector(cs._pixelSizeVector), _smallFeatureCullingPixelSize(cs._smallFeatureCullingPixelSize) { } CullingSet(const CullingSet& cs,const Matrix& matrix, const Vec4& pixelSizeVector): _mask(cs._mask), _frustum(cs._frustum), _stateFrustumList(cs._stateFrustumList), _occluderList(cs._occluderList), _pixelSizeVector(pixelSizeVector), _smallFeatureCullingPixelSize(cs._smallFeatureCullingPixelSize) { _frustum.transformProvidingInverse(matrix); for(OccluderList::iterator itr=_occluderList.begin(); itr!=_occluderList.end(); ++itr) { itr->transformProvidingInverse(matrix); } } CullingSet& operator = (const CullingSet& cs) { if (this==&cs) return *this; _mask = cs._mask; _frustum = cs._frustum; _stateFrustumList = cs._stateFrustumList; _occluderList = cs._occluderList; _pixelSizeVector = cs._pixelSizeVector; _smallFeatureCullingPixelSize = cs._smallFeatureCullingPixelSize; return *this; } inline void set(const CullingSet& cs) { _mask = cs._mask; _frustum = cs._frustum; _stateFrustumList = cs._stateFrustumList; _occluderList = cs._occluderList; _pixelSizeVector = cs._pixelSizeVector; _smallFeatureCullingPixelSize = cs._smallFeatureCullingPixelSize; } inline void set(const CullingSet& cs,const Matrix& matrix, const Vec4& pixelSizeVector) { _mask = cs._mask; _stateFrustumList = cs._stateFrustumList; _occluderList = cs._occluderList; _pixelSizeVector = pixelSizeVector; _smallFeatureCullingPixelSize = cs._smallFeatureCullingPixelSize; //_frustum = cs._frustum; //_frustum.transformProvidingInverse(matrix); _frustum.setAndTransformProvidingInverse(cs._frustum,matrix); for(StateFrustumList::iterator sitr=_stateFrustumList.begin(); sitr!=_stateFrustumList.end(); ++sitr) { sitr->second.transformProvidingInverse(matrix); } for(OccluderList::iterator oitr=_occluderList.begin(); oitr!=_occluderList.end(); ++oitr) { oitr->transformProvidingInverse(matrix); } } typedef std::vector OccluderList; typedef int Mask; enum MaskValues { NO_CULLING = 0x0, VIEW_FRUSTUM_SIDES_CULLING = 0x1, NEAR_PLANE_CULLING = 0x2, FAR_PLANE_CULLING = 0x4, VIEW_FRUSTUM_CULLING = VIEW_FRUSTUM_SIDES_CULLING| NEAR_PLANE_CULLING| FAR_PLANE_CULLING, SMALL_FEATURE_CULLING = 0x8, SHADOW_OCCLUSION_CULLING = 0x10, DEFAULT_CULLING = VIEW_FRUSTUM_SIDES_CULLING| SMALL_FEATURE_CULLING| SHADOW_OCCLUSION_CULLING, ENABLE_ALL_CULLING = VIEW_FRUSTUM_CULLING| SMALL_FEATURE_CULLING| SHADOW_OCCLUSION_CULLING }; void setCullingMask(Mask mask) { _mask = mask; } Mask getCullingMask() const { return _mask; } void setFrustum(Polytope& cv) { _frustum = cv; } Polytope& getFrustum() { return _frustum; } const Polytope& getFrustum() const { return _frustum; } void addStateFrustum(StateSet* stateset, Polytope& polytope) { _stateFrustumList.push_back(StateFrustumPair(stateset,polytope)); } void getStateFrustumList(StateFrustumList& sfl) { _stateFrustumList = sfl; } StateFrustumList& getStateFrustumList() { return _stateFrustumList; } void addOccluder(ShadowVolumeOccluder& cv) { _occluderList.push_back(cv); } void setPixelSizeVector(const Vec4& v) { _pixelSizeVector = v; } Vec4& getPixelSizeVector() { return _pixelSizeVector; } const Vec4& getPixelSizeVector() const { return _pixelSizeVector; } void setSmallFeatureCullingPixelSize(float value) { _smallFeatureCullingPixelSize=value; } float& getSmallFeatureCullingPixelSize() { return _smallFeatureCullingPixelSize; } float getSmallFeatureCullingPixelSize() const { return _smallFeatureCullingPixelSize; } /** Compute the pixel of an object at position v, with specified radius.*/ float pixelSize(const Vec3& v,float radius) const { return radius/(v*_pixelSizeVector); } /** Compute the pixel of a bounding sphere.*/ float pixelSize(const BoundingSphere& bs) const { return bs.radius()/(bs.center()*_pixelSizeVector); } /** Compute the pixel of an object at position v, with specified radius. fabs()ed to always be positive. */ float clampedPixelSize(const Vec3& v,float radius) const { return fabs(pixelSize(v, radius)); } /** Compute the pixel of a bounding sphere. fabs()ed to always be positive. */ float clampedPixelSize(const BoundingSphere& bs) const { return fabs(pixelSize(bs)); } inline bool isCulled(const std::vector& vertices) { if (_mask&VIEW_FRUSTUM_CULLING) { // is it outside the view frustum... if (!_frustum.contains(vertices)) return true; } if (_mask&SMALL_FEATURE_CULLING) { } if (_mask&SHADOW_OCCLUSION_CULLING) { // is it in one of the shadow occluder volumes. if (!_occluderList.empty()) { for(OccluderList::iterator itr=_occluderList.begin(); itr!=_occluderList.end(); ++itr) { if (itr->contains(vertices)) return true; } } } return false; } inline bool isCulled(const BoundingBox& bb) { if (_mask&VIEW_FRUSTUM_CULLING) { // is it outside the view frustum... if (!_frustum.contains(bb)) return true; } if (_mask&SMALL_FEATURE_CULLING) { } if (_mask&SHADOW_OCCLUSION_CULLING) { // is it in one of the shadow occluder volumes. if (!_occluderList.empty()) { for(OccluderList::iterator itr=_occluderList.begin(); itr!=_occluderList.end(); ++itr) { if (itr->contains(bb)) return true; } } } return false; } inline bool isCulled(const BoundingSphere& bs) { if (_mask&VIEW_FRUSTUM_CULLING) { // is it outside the view frustum... if (!_frustum.contains(bs)) return true; } if (_mask&SMALL_FEATURE_CULLING) { if (((bs.center()*_pixelSizeVector)*_smallFeatureCullingPixelSize)>bs.radius()) return true; } #ifdef COMPILE_WITH_SHADOW_OCCLUSION_CULLING if (_mask&SHADOW_OCCLUSION_CULLING) { // is it in one of the shadow occluder volumes. if (!_occluderList.empty()) { for(OccluderList::iterator itr=_occluderList.begin(); itr!=_occluderList.end(); ++itr) { if (itr->contains(bs)) return true; } } } #endif return false; } inline void pushCurrentMask() { _frustum.pushCurrentMask(); if (!_stateFrustumList.empty()) { for(StateFrustumList::iterator itr=_stateFrustumList.begin(); itr!=_stateFrustumList.end(); ++itr) { itr->second.pushCurrentMask(); } } #ifdef COMPILE_WITH_SHADOW_OCCLUSION_CULLING if (!_occluderList.empty()) { for(OccluderList::iterator itr=_occluderList.begin(); itr!=_occluderList.end(); ++itr) { itr->pushCurrentMask(); } } #endif } inline void popCurrentMask() { _frustum.popCurrentMask(); if (!_stateFrustumList.empty()) { for(StateFrustumList::iterator itr=_stateFrustumList.begin(); itr!=_stateFrustumList.end(); ++itr) { itr->second.popCurrentMask(); } } #ifdef COMPILE_WITH_SHADOW_OCCLUSION_CULLING if (!_occluderList.empty()) { for(OccluderList::iterator itr=_occluderList.begin(); itr!=_occluderList.end(); ++itr) { itr->popCurrentMask(); } } #endif } void disableAndPushOccludersCurrentMask(NodePath& nodePath); void popOccludersCurrentMask(NodePath& nodePath); static osg::Vec4 computePixelSizeVector(const Viewport& W, const Matrix& P, const Matrix& M); virtual ~CullingSet(); protected: Mask _mask; Polytope _frustum; StateFrustumList _stateFrustumList; OccluderList _occluderList; Vec4 _pixelSizeVector; float _smallFeatureCullingPixelSize; }; } // end of namespace #endif