From 0ebe473eb598bb69b199bfc0b2541aed741d234a Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 13 Jun 2002 16:21:00 +0000 Subject: [PATCH] Further work on Occlusion Culling. Most of work is complete, just debugging required now. --- Make/makedefs | 9 +- include/osg/CollectOccludersVisitor | 9 +- include/osg/CullStack | 19 ++- include/osg/CullingSet | 17 +-- include/osg/Plane | 7 + include/osg/Polytope | 12 ++ include/osg/ShadowVolumeOccluder | 50 ++++--- src/osg/CollectOccludersVisitor.cpp | 20 ++- src/osg/CullStack.cpp | 19 ++- src/osg/CullingSet.cpp | 18 +++ src/osg/ShadowVolumeOccluder.cpp | 199 +++++++++++++++++++++++++++- src/osgUtil/CullVisitor.cpp | 2 +- src/osgUtil/SceneView.cpp | 9 +- 13 files changed, 335 insertions(+), 55 deletions(-) diff --git a/Make/makedefs b/Make/makedefs index a8ecc0401..c15592541 100644 --- a/Make/makedefs +++ b/Make/makedefs @@ -235,14 +235,15 @@ ifeq ($(OS),Darwin) LIB_EXT = dylib QUICKTIME_LIB = -framework QuickTime TIFF_LIB = -ltiff - SRC_DIRS = osg osgGA osgUtil osgDB osgGLUT osgParticle \ + SRC_DIRS = osg osgUtil osgDB osgGA osgGLUT osgParticle \ osgPlugins Demos PLUGIN_DIRS = osg rgb lib3ds flt obj lwo txp bmp pic tga \ osgtgz tgz zip DEMOS_DIRS = hangglide osgbillboard osgcluster osgconv osgcopy \ - osgcube osgimpostor osgreflect osgscribe \ - osgstereoimage osgtexture osgviews osgversion \ - sgv osgparticle + osgcube osgcallback osgclip osgimpostor osgoccluder \ + osgreflect osgscribe osgstereoimage osgtexture \ + osgviews osgversion sgv osgparticle + endif #### Cygwin/Mingw specific definitions diff --git a/include/osg/CollectOccludersVisitor b/include/osg/CollectOccludersVisitor index 43b6eb185..e5e98c739 100644 --- a/include/osg/CollectOccludersVisitor +++ b/include/osg/CollectOccludersVisitor @@ -30,10 +30,9 @@ class SG_EXPORT CollectOccludersVisitor : public osg::NodeVisitor, public osg::C virtual void apply(osg::LOD& node); virtual void apply(osg::OccluderNode& node); - typedef std::vector OccluderList; - - OccluderList& getOccluderList() { return _occluderList; } - const OccluderList& getOccluderList() const { return _occluderList; } + void setCollectedOcculderList(const ShadowVolumeOccluderList& svol) { _occluderList = svol; } + ShadowVolumeOccluderList& getCollectedOccluderList() { return _occluderList; } + const ShadowVolumeOccluderList& getCollectedOccluderList() const { return _occluderList; } protected: @@ -44,7 +43,7 @@ class SG_EXPORT CollectOccludersVisitor : public osg::NodeVisitor, public osg::C /** prevent unwanted copy operator.*/ CollectOccludersVisitor& operator = (const CollectOccludersVisitor&) { return *this; } - OccluderList _occluderList; + ShadowVolumeOccluderList _collectedOccluderList; }; diff --git a/include/osg/CullStack b/include/osg/CullStack index e67c86ef4..ad815ccb0 100644 --- a/include/osg/CullStack +++ b/include/osg/CullStack @@ -44,6 +44,10 @@ class SG_EXPORT CullStack CullingMode getCullingMode() const { return _cullingMode; } void reset(); + + void setOccluderList(const ShadowVolumeOccluderList& svol) { _occluderList = svol; } + ShadowVolumeOccluderList& getOccluderList() { return _occluderList; } + const ShadowVolumeOccluderList& getOccluderList() const { return _occluderList; } void pushViewport(osg::Viewport* viewport); void popViewport(); @@ -110,6 +114,17 @@ class SG_EXPORT CullStack } + typedef fast_back_stack > CullingStack; + + CullingStack& getClipSpaceCullingStack() { return _clipspaceCullingStack; } + + CullingStack& getProjectionCullingStack() { return _projectionCullingStack; } + + CullingStack& getModelViewCullingStack() { return _modelviewCullingStack; } + + CullingSet& getCurrentCullingSet() { return *_modelviewCullingStack.back(); } + + inline osg::Viewport* getViewport(); inline osg::Matrix& getModelViewMatrix(); inline osg::Matrix& getProjectionMatrix(); @@ -139,6 +154,9 @@ class SG_EXPORT CullStack float _LODBias; float _smallFeatureCullingPixelSize; + // base set of shadow volume occluder to use in culling. + ShadowVolumeOccluderList _occluderList; + typedef fast_back_stack< ref_ptr > MatrixStack; MatrixStack _projectionStack; @@ -152,7 +170,6 @@ class SG_EXPORT CullStack typedef fast_back_stack EyePointStack; EyePointStack _eyePointStack; - typedef fast_back_stack > CullingStack; CullingStack _clipspaceCullingStack; CullingStack _projectionCullingStack; CullingStack _modelviewCullingStack; diff --git a/include/osg/CullingSet b/include/osg/CullingSet index 1ca83ccb2..2b4f592db 100644 --- a/include/osg/CullingSet +++ b/include/osg/CullingSet @@ -77,22 +77,7 @@ class SG_EXPORT CullingSet : public Referenced /** Compute the pixel of an bounding sphere.*/ float pixelSize(const BoundingSphere& bs) const { return bs.radius()/(bs.center()*_pixelSizeVector); } - inline void disableOccluder(NodePath& nodePath) - { - for(OccluderList::iterator itr=_occluderList.begin(); - itr!=_occluderList.end(); - ++itr) - { - if (itr->getNodePath()==nodePath) - { - // we have trapped for the case an occlude potentially occluding itself, - // to prevent this we disable the results mask so that no subsequnt - // when the next pushCurrentMask calls happens this occluder is switched off. - itr->disableResultMasks(); - } - } - } - + void disableOccluder(NodePath& nodePath); inline bool isCulled(const std::vector& vertices) { diff --git a/include/osg/Plane b/include/osg/Plane index 4890a07ac..1dc69909f 100644 --- a/include/osg/Plane +++ b/include/osg/Plane @@ -50,6 +50,13 @@ class SG_EXPORT Plane _fv.set(norm[0],norm[1],norm[2],-(v1*norm)); calculateUpperLowerBBCorners(); } + + /** flip/reverse the orientation of the plane.*/ + inline void flip() + { + _fv = -_fv; + calculateUpperLowerBBCorners(); + } inline void makeUnitLength() diff --git a/include/osg/Polytope b/include/osg/Polytope index 310cc1275..0df4af41f 100644 --- a/include/osg/Polytope +++ b/include/osg/Polytope @@ -70,6 +70,18 @@ class SG_EXPORT Polytope inline void add(const osg::Plane& pl) { _planeList.push_back(pl); setupMask(); } + /** flip/reverse the orientation of all the planes.*/ + inline void flip() + { + for(PlaneList::iterator itr=_planeList.begin(); + itr!=_planeList.end(); + ++itr) + { + itr->flip(); + } + } + + inline PlaneList& getPlaneList() { return _planeList; } inline const PlaneList& getPlaneList() const { return _planeList; } diff --git a/include/osg/ShadowVolumeOccluder b/include/osg/ShadowVolumeOccluder index 7dde421c2..14a552e2a 100644 --- a/include/osg/ShadowVolumeOccluder +++ b/include/osg/ShadowVolumeOccluder @@ -12,6 +12,8 @@ namespace osg { +class CullStack; + /** ShadowVolumeOccluder is a helper class for implementating shadow occlusion culling. */ class SG_EXPORT ShadowVolumeOccluder { @@ -21,25 +23,35 @@ class SG_EXPORT ShadowVolumeOccluder typedef std::vector HoleList; - ShadowVolumeOccluder(const ShadowVolumeOccluder& soc): - _quality(soc._quality), - _nodePath(soc._nodePath), - _occluderVolume(soc._occluderVolume), - _holeList(soc._holeList) {} + ShadowVolumeOccluder(const ShadowVolumeOccluder& svo): + _volume(svo._volume), + _nodePath(svo._nodePath), + _projectionMatrix(svo._projectionMatrix), + _occluderVolume(svo._occluderVolume), + _holeList(svo._holeList) {} + + ShadowVolumeOccluder(): + _volume(0.0f) {} - ShadowVolumeOccluder(const NodePath& nodePath,const ConvexPlanerOccluder& occluder,const Matrix& MV,const Matrix& P) - { - computeOccluder(nodePath,occluder,MV,P); - } /** compute the shadow volume occluder. */ - void computeOccluder(const NodePath& nodePath,const ConvexPlanerOccluder& occluder,const Matrix& MV,const Matrix& P); + bool computeOccluder(const NodePath& nodePath,const ConvexPlanerOccluder& occluder,CullStack& cullStack); inline void disableResultMasks(); inline void pushCurrentMask(); inline void popCurrentMask(); + + + /** return true if the matrix passed in matches the projection matrix that this ShaowVolumeOccluder is + * associated with.*/ + bool matchProjectionMatrix(const osg::Matrix& matrix) const + { + if (_projectionMatrix.valid()) return matrix==*_projectionMatrix; + else return false; + } + /** Set the NodePath which describes the which node in the scene graph * that this occluder was attached to.*/ @@ -47,7 +59,9 @@ class SG_EXPORT ShadowVolumeOccluder inline NodePath& getNodePath() { return _nodePath; } inline const NodePath& getNodePath() const { return _nodePath; } - float quality() { return _quality; } + float volume() { return _volume; } + + /** return true if the specified vertex list is contaned entirely * within this shadow occluder volume.*/ @@ -75,12 +89,18 @@ class SG_EXPORT ShadowVolumeOccluder protected: - float _quality; - NodePath _nodePath; - Polytope _occluderVolume; - HoleList _holeList; + float _volume; + NodePath _nodePath; + ref_ptr _projectionMatrix; + Polytope _occluderVolume; + HoleList _holeList; }; + +/** A list of ShadowVolumeOccluder, used by CollectOccluderVisitor and CullVistor's.*/ +typedef std::vector ShadowVolumeOccluderList; + + inline void ShadowVolumeOccluder::disableResultMasks() { _occluderVolume.setResultMask(0); diff --git a/src/osg/CollectOccludersVisitor.cpp b/src/osg/CollectOccludersVisitor.cpp index 604b51b17..f6775d1c0 100644 --- a/src/osg/CollectOccludersVisitor.cpp +++ b/src/osg/CollectOccludersVisitor.cpp @@ -103,18 +103,26 @@ void CollectOccludersVisitor::apply(osg::OccluderNode& node) if (isCulled(node)) return; - std::cout<<"CollectOccludersVisitor:: We have found an Occlusion node in frustum"<<&node<getOccluder().getVertexList())) + if (node.getOccluder()) { - - // need to test occluder against view frustum. - std::cout << " adding in Occluder"<getFrustum().setToUnitFrustumWithoutNearFar(); cullingSet->getFrustum().transformProvidingInverse(*matrix); + + // set the small feature culling. cullingSet->setSmallFeatureCullingPixelSize(_smallFeatureCullingPixelSize); - _projectionCullingStack.push_back(cullingSet); + // set up the relevant occluders which a related to this projection. + for(ShadowVolumeOccluderList::iterator itr=_occluderList.begin(); + itr!=_occluderList.end(); + ++itr) + { + //std::cout << " ** testing occluder"<matchProjectionMatrix(*matrix)) + { + //std::cout << " ** activating occluder"<addOccluder(*itr); + } + } - //_projectionCullingStack.push_back(osgNew osg::CullingSet(*_clipspaceCullingStack.back(),*matrix)); + + _projectionCullingStack.push_back(cullingSet); pushCullingSet(); diff --git a/src/osg/CullingSet.cpp b/src/osg/CullingSet.cpp index c23d71dc0..367f0bf23 100644 --- a/src/osg/CullingSet.cpp +++ b/src/osg/CullingSet.cpp @@ -12,3 +12,21 @@ CullingSet::CullingSet() CullingSet::~CullingSet() { } + +void CullingSet::disableOccluder(NodePath& nodePath) +{ + //std::cout<<" trying to disable occluder"<getNodePath()==nodePath) + { + //std::cout<<" ++ disabling occluder"<disableResultMasks(); + } + } +} diff --git a/src/osg/ShadowVolumeOccluder.cpp b/src/osg/ShadowVolumeOccluder.cpp index fcb4f1ed9..310b4c6f7 100644 --- a/src/osg/ShadowVolumeOccluder.cpp +++ b/src/osg/ShadowVolumeOccluder.cpp @@ -1,11 +1,161 @@ #include +#include using namespace osg; -void ShadowVolumeOccluder::computeOccluder(const NodePath& nodePath,const ConvexPlanerOccluder& occluder,const Matrix& MV,const Matrix& P) + +typedef std::pair Point; // bool=true signifies a newly created point, false indicates original point. +typedef std::vector PointList; +typedef std::vector VertexList; + + +// convert a vector for Vec3 into a vector of Point's. +void convert(const VertexList& in,PointList& out) { - std::cout<<" Computing Occluder"< distance; + distance.reserve(in.size()); + for(PointList::const_iterator itr=in.begin(); + itr!=in.end(); + ++itr) + { + distance.push_back(plane.distance(itr->second)); + } + + out.clear(); + + for(unsigned int i=0;i=0.0f) + { + out.push_back(in[i]); + + if (distance[i_1]<0.0f) + { + float r = distance[i_1]/(distance[i_1]-distance[i]); + out.push_back(Point(true,in[i].second*r+in[i_1].second*(1.0f-r))); + } + + } + else if (distance[i_1]>0.0f) + { + float r = distance[i_1]/(distance[i_1]-distance[i]); + out.push_back(Point(true,in[i].second*r+in[i_1].second*(1.0f-r))); + } + } + + return out.size(); +} + +// clip the convex hull 'in' to planeList to generate a clipped convex hull 'out' +// return true if points remain after clipping. +unsigned int clip(const Polytope::PlaneList& planeList,const VertexList& vin,PointList& out) +{ + PointList in; + convert(vin,in); + + for(Polytope::PlaneList::const_iterator itr=planeList.begin(); + itr!=planeList.end(); + ++itr) + { + if (!clip(*itr,in,out)) return false; + in.swap(out); + } + + in.swap(out); + + return out.size(); +} + +void transform(PointList& points,const osg::Matrix& matrix) +{ + for(PointList::iterator itr=points.begin(); + itr!=points.end(); + ++itr) + { + itr->second = itr->second*matrix; + } +} + +void transform(const PointList& in,PointList& out,const osg::Matrix& matrix) +{ + for(PointList::const_iterator itr=in.begin(); + itr!=in.end(); + ++itr) + { + out.push_back(Point(itr->first,itr->second * matrix)); + } +} + +void pushToFarPlane(PointList& points) +{ + for(PointList::iterator itr=points.begin(); + itr!=points.end(); + ++itr) + { + itr->second.z()=-1.0f; + } +} + +void computePlanes(const PointList& front, const PointList& back, Polytope::PlaneList& planeList) +{ + for(unsigned int i=0;i=3) + { + // compute the points on the far plane. + PointList farPoints; + farPoints.reserve(points.size()); + transform(points,farPoints,MVP); + pushToFarPlane(farPoints); + transform(farPoints,invP); + + // move the occlude points into projection space. + transform(points,MV); + + // create the sides of the occluder + computePlanes(points,farPoints,_occluderVolume.getPlaneList()); + + // create the front face of the occluder + Plane occludePlane = computeFrontPlane(points); + _occluderVolume.add(occludePlane); + + // if the front face is pointing away from the eye point flip the whole polytope. + if (occludePlane[3]>0.0f) + { +// std::cout << " flipping polytope"<& vertices) diff --git a/src/osgUtil/CullVisitor.cpp b/src/osgUtil/CullVisitor.cpp index 3671ea059..1a7030e37 100644 --- a/src/osgUtil/CullVisitor.cpp +++ b/src/osgUtil/CullVisitor.cpp @@ -546,7 +546,7 @@ void CullVisitor::apply(osg::OccluderNode& node) // list, if so disable the appropriate ShadowOccluderVolume disableOccluder(_nodePath); - std::cout<<"CullVisitor:: We are in an Occlusion node"<<&node<containsOccluderNodes()) { - std::cout << "Scene graph contains occluder nodes, searching for them"<setOccluderList(cov.getCollectedOccluderList()); }