365 lines
12 KiB
C++
365 lines
12 KiB
C++
/* -*-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 <osg/Polytope>
|
|
#include <osg/ShadowVolumeOccluder>
|
|
#include <osg/Viewport>
|
|
|
|
#include <math.h>
|
|
|
|
|
|
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::StateSet>, 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<ShadowVolumeOccluder> 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; }
|
|
|
|
/** Threshold at which small features are culled.
|
|
\param value Boulding volume size in screen space. Default is 2.0. */
|
|
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<Vec3>& 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;
|
|
}
|
|
|
|
#ifdef OSG_USE_BOUND
|
|
inline bool isCulled(const Bound& bound)
|
|
{
|
|
if (bound.bb) return isCulled(*bound.bb);
|
|
else return isCulled(*bound.bs);
|
|
}
|
|
#endif
|
|
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
|
|
}
|
|
|
|
inline void resetCullingMask()
|
|
{
|
|
_frustum.setResultMask(_frustum.getCurrentMask());
|
|
}
|
|
|
|
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
|