From 7cd74f028261b742ed6ca9222a5c3a52fd1eebb7 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 14 Mar 2011 10:07:15 +0000 Subject: [PATCH] From Farshid Lashkari, "Another update. I added a LIMIT_NEAREST enum which implements your previous suggestion of rejecting bounding volumes further from the nearest existing intersection. I only implemented this for LineSegmentIntersector. I'd appreciate it if you could double check the math I added to LineSegmentIntersector::intersects() for checking if the bounding sphere is further away. The results of this are promising. I'm getting noticeable performance increase for line intersections with scenes containing many drawables. " --- include/osgUtil/IntersectionVisitor | 21 ++++++++++++++++++--- include/osgUtil/LineSegmentIntersector | 2 +- include/osgUtil/PlaneIntersector | 2 +- include/osgUtil/PolytopeIntersector | 2 +- src/osgUtil/LineSegmentIntersector.cpp | 26 +++++++++++++++++++++++++- src/osgUtil/PlaneIntersector.cpp | 13 +++++++++++-- src/osgUtil/PolytopeIntersector.cpp | 19 ++++++++++++++++++- 7 files changed, 75 insertions(+), 10 deletions(-) diff --git a/include/osgUtil/IntersectionVisitor b/include/osgUtil/IntersectionVisitor index 6144d0a76..eb0a12c1b 100644 --- a/include/osgUtil/IntersectionVisitor +++ b/include/osgUtil/IntersectionVisitor @@ -41,17 +41,29 @@ class Intersector : public osg::Referenced VIEW, MODEL }; - + + enum IntersectionLimit + { + NO_LIMIT, + LIMIT_ONE_PER_DRAWABLE, + LIMIT_ONE, + LIMIT_NEAREST + }; + Intersector(CoordinateFrame cf=MODEL): _coordinateFrame(cf), + _intersectionLimit(NO_LIMIT), _disabledCount(0) {} void setCoordinateFrame(CoordinateFrame cf) { _coordinateFrame = cf; } CoordinateFrame getCoordinateFrame() const { return _coordinateFrame; } - - + + void setIntersectionLimit(IntersectionLimit limit) { _intersectionLimit = limit; } + + IntersectionLimit getIntersectionLimit() const { return _intersectionLimit; } + virtual Intersector* clone(osgUtil::IntersectionVisitor& iv) = 0; virtual bool enter(const osg::Node& node) = 0; @@ -70,9 +82,12 @@ class Intersector : public osg::Referenced inline void decrementDisabledCount() { if (_disabledCount>0) --_disabledCount; } + inline bool reachedLimit() { return _intersectionLimit == LIMIT_ONE && containsIntersections(); } + protected: CoordinateFrame _coordinateFrame; + IntersectionLimit _intersectionLimit; unsigned int _disabledCount; }; diff --git a/include/osgUtil/LineSegmentIntersector b/include/osgUtil/LineSegmentIntersector index f86fd1beb..5cfe2d04b 100644 --- a/include/osgUtil/LineSegmentIntersector +++ b/include/osgUtil/LineSegmentIntersector @@ -91,7 +91,7 @@ class OSGUTIL_EXPORT LineSegmentIntersector : public Intersector virtual void reset(); - virtual bool containsIntersections() { return !_intersections.empty(); } + virtual bool containsIntersections() { return !getIntersections().empty(); } protected: diff --git a/include/osgUtil/PlaneIntersector b/include/osgUtil/PlaneIntersector index d1a0c6e84..56db7f5cc 100644 --- a/include/osgUtil/PlaneIntersector +++ b/include/osgUtil/PlaneIntersector @@ -86,7 +86,7 @@ class OSGUTIL_EXPORT PlaneIntersector : public Intersector virtual void reset(); - virtual bool containsIntersections() { return !_intersections.empty(); } + virtual bool containsIntersections() { return !getIntersections().empty(); } protected: diff --git a/include/osgUtil/PolytopeIntersector b/include/osgUtil/PolytopeIntersector index 6fb5deef4..8c1357dff 100644 --- a/include/osgUtil/PolytopeIntersector +++ b/include/osgUtil/PolytopeIntersector @@ -109,7 +109,7 @@ class OSGUTIL_EXPORT PolytopeIntersector : public Intersector virtual void reset(); - virtual bool containsIntersections() { return !_intersections.empty(); } + virtual bool containsIntersections() { return !getIntersections().empty(); } protected: diff --git a/src/osgUtil/LineSegmentIntersector.cpp b/src/osgUtil/LineSegmentIntersector.cpp index 1c344b99f..5131449c1 100644 --- a/src/osgUtil/LineSegmentIntersector.cpp +++ b/src/osgUtil/LineSegmentIntersector.cpp @@ -63,6 +63,7 @@ namespace LineSegmentIntersectorUtils int _index; float _ratio; bool _hit; + bool _limitOneIntersection; TriangleIntersections _intersections; @@ -72,6 +73,7 @@ namespace LineSegmentIntersectorUtils _index = 0; _ratio = 0.0f; _hit = false; + _limitOneIntersection = false; } void set(const osg::Vec3d& start, osg::Vec3d& end, float ratio=FLT_MAX) @@ -90,6 +92,8 @@ namespace LineSegmentIntersectorUtils { ++_index; + if (_limitOneIntersection && _hit) return; + if (v1==v2 || v2==v3 || v1==v3) return; osg::Vec3 v12 = v2-v1; @@ -238,6 +242,7 @@ Intersector* LineSegmentIntersector::clone(osgUtil::IntersectionVisitor& iv) { osg::ref_ptr lsi = new LineSegmentIntersector(_start, _end); lsi->_parent = this; + lsi->_intersectionLimit = this->_intersectionLimit; return lsi.release(); } @@ -271,11 +276,13 @@ Intersector* LineSegmentIntersector::clone(osgUtil::IntersectionVisitor& iv) osg::ref_ptr lsi = new LineSegmentIntersector(_start * inverse, _end * inverse); lsi->_parent = this; + lsi->_intersectionLimit = this->_intersectionLimit; return lsi.release(); } bool LineSegmentIntersector::enter(const osg::Node& node) { + if (reachedLimit()) return false; return !node.isCullingActive() || intersects( node.getBound() ); } @@ -286,7 +293,9 @@ void LineSegmentIntersector::leave() void LineSegmentIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable) { - osg::Vec3d s(_start), e(_end); + if (reachedLimit()) return; + + osg::Vec3d s(_start), e(_end); if ( !intersectAndClip( s, e, drawable->getBound() ) ) return; if (iv.getDoDummyTraversal()) return; @@ -354,6 +363,7 @@ void LineSegmentIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Dr osg::TriangleFunctor ti; ti.set(s,e); + ti._limitOneIntersection = (_intersectionLimit == LIMIT_ONE_PER_DRAWABLE || _intersectionLimit == LIMIT_ONE); drawable->accept(ti); if (ti._hit) @@ -371,6 +381,14 @@ void LineSegmentIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Dr // remap ratio into _start, _end range double remap_ratio = ((s-_start).length() + ratio * (e-s).length() )/(_end-_start).length(); + if ( _intersectionLimit == LIMIT_NEAREST && !getIntersections().empty() ) + { + if (remap_ratio >= getIntersections().begin()->ratio ) + break; + else + getIntersections().clear(); + } + LineSegmentIntersectorUtils::TriangleIntersection& triHit = thitr->second; Intersection hit; @@ -450,6 +468,12 @@ bool LineSegmentIntersector::intersects(const osg::BoundingSphere& bs) if (r1>=1.0 && r2>=1.0) return false; + if (_intersectionLimit == LIMIT_NEAREST && !getIntersections().empty()) + { + double ratio = (sm.length() - bs._radius) / sqrt(a); + if (ratio >= getIntersections().begin()->ratio) return false; + } + // passed all the rejection tests so line must intersect bounding sphere, return true. return true; } diff --git a/src/osgUtil/PlaneIntersector.cpp b/src/osgUtil/PlaneIntersector.cpp index 29c14cff7..32a51d10f 100644 --- a/src/osgUtil/PlaneIntersector.cpp +++ b/src/osgUtil/PlaneIntersector.cpp @@ -359,13 +359,15 @@ namespace PlaneIntersectorUtils osg::ref_ptr _matrix; bool _recordHeightsAsAttributes; osg::ref_ptr _em; - + bool _limitOneIntersection; + PolylineConnector _polylineConnector; TriangleIntersector() { _hit = false; + _limitOneIntersection = false; } void set(const osg::Plane& plane, const osg::Polytope& polytope, osg::RefMatrix* matrix, bool recordHeightsAsAttributes, osg::EllipsoidModel* em) @@ -439,7 +441,9 @@ namespace PlaneIntersectorUtils inline void operator () (const osg::Vec3& v1,const osg::Vec3& v2,const osg::Vec3& v3, bool) { - + + if (_limitOneIntersection && _hit) return; + double d1 = _plane.distance(v1); double d2 = _plane.distance(v2); double d3 = _plane.distance(v3); @@ -590,6 +594,7 @@ Intersector* PlaneIntersector::clone(osgUtil::IntersectionVisitor& iv) { osg::ref_ptr pi = new PlaneIntersector(_plane, _polytope); pi->_parent = this; + pi->_intersectionLimit = this->_intersectionLimit; pi->_recordHeightsAsAttributes = _recordHeightsAsAttributes; pi->_em = _em; return pi.release(); @@ -628,6 +633,7 @@ Intersector* PlaneIntersector::clone(osgUtil::IntersectionVisitor& iv) osg::ref_ptr pi = new PlaneIntersector(plane, transformedPolytope); pi->_parent = this; + pi->_intersectionLimit = this->_intersectionLimit; pi->_recordHeightsAsAttributes = _recordHeightsAsAttributes; pi->_em = _em; return pi.release(); @@ -635,6 +641,7 @@ Intersector* PlaneIntersector::clone(osgUtil::IntersectionVisitor& iv) bool PlaneIntersector::enter(const osg::Node& node) { + if (reachedLimit()) return false; return !node.isCullingActive() || ( _plane.intersect(node.getBound())==0 && _polytope.contains(node.getBound()) ); } @@ -650,6 +657,7 @@ void PlaneIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable { // OSG_NOTICE<<"PlaneIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable)"<getBound() )!=0 ) return; if ( !_polytope.contains( drawable->getBound() ) ) return; @@ -657,6 +665,7 @@ void PlaneIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable osg::TriangleFunctor ti; ti.set(_plane, _polytope, iv.getModelMatrix(), _recordHeightsAsAttributes, _em.get()); + ti._limitOneIntersection = (_intersectionLimit == LIMIT_ONE_PER_DRAWABLE || _intersectionLimit == LIMIT_ONE); drawable->accept(ti); ti._polylineConnector.consolidatePolylineLists(); diff --git a/src/osgUtil/PolytopeIntersector.cpp b/src/osgUtil/PolytopeIntersector.cpp index de5497687..08455b07e 100644 --- a/src/osgUtil/PolytopeIntersector.cpp +++ b/src/osgUtil/PolytopeIntersector.cpp @@ -88,6 +88,7 @@ namespace PolytopeIntersectorUtils PolytopePrimitiveIntersector() : _index(0), _dimensionMask( PolytopeIntersector::AllDims ), + _limitOneIntersection( false ), _candidates(20) {} void addIntersection(unsigned int index, const CandList_t& cands) { @@ -130,6 +131,9 @@ namespace PolytopeIntersectorUtils { ++_index; if ((_dimensionMask & PolytopeIntersector::DimZero) == 0) return; + + if (_limitOneIntersection && !intersections.empty()) return; + for (PlaneList::const_iterator it=_planes.begin(); it!=_planes.end(); ++it) { const osg::Plane& plane=*it; @@ -146,7 +150,9 @@ namespace PolytopeIntersectorUtils { ++_index; if ((_dimensionMask & PolytopeIntersector::DimOne) == 0) return; - + + if (_limitOneIntersection && !intersections.empty()) return; + PlaneMask selector_mask = 0x1; PlaneMask inside_mask = 0x0; _candidates.clear(); @@ -210,6 +216,8 @@ namespace PolytopeIntersectorUtils ++_index; if ((_dimensionMask & PolytopeIntersector::DimTwo) == 0) return; + if (_limitOneIntersection && !intersections.empty()) return; + PlaneMask selector_mask = 0x1; PlaneMask inside_mask = 0x0; _candidates.clear(); @@ -354,6 +362,8 @@ namespace PolytopeIntersectorUtils void setDimensionMask(unsigned int dimensionMask) { _dimensionMask = dimensionMask; } + void setLimitOneIntersection(bool limit) { _limitOneIntersection = limit; } + void setPolytope(osg::Polytope& polytope, osg::Plane& referencePlane) { _referencePlane = referencePlane; @@ -426,6 +436,7 @@ namespace PolytopeIntersectorUtils unsigned int _index; private: + bool _limitOneIntersection; unsigned int _dimensionMask; PlaneList _planes; ///< active planes extracted from polytope LinesList _lines; ///< all intersection lines of two polytope planes @@ -492,6 +503,7 @@ Intersector* PolytopeIntersector::clone(osgUtil::IntersectionVisitor& iv) { osg::ref_ptr pi = new PolytopeIntersector(_polytope); pi->_parent = this; + pi->_intersectionLimit = this->_intersectionLimit; pi->_dimensionMask = this->_dimensionMask; pi->_referencePlane = this->_referencePlane; return pi.release(); @@ -527,6 +539,7 @@ Intersector* PolytopeIntersector::clone(osgUtil::IntersectionVisitor& iv) osg::ref_ptr pi = new PolytopeIntersector(transformedPolytope); pi->_parent = this; + pi->_intersectionLimit = this->_intersectionLimit; pi->_dimensionMask = this->_dimensionMask; pi->_referencePlane = this->_referencePlane; pi->_referencePlane.transformProvidingInverse(matrix); @@ -535,6 +548,7 @@ Intersector* PolytopeIntersector::clone(osgUtil::IntersectionVisitor& iv) bool PolytopeIntersector::enter(const osg::Node& node) { + if (reachedLimit()) return false; return !node.isCullingActive() || _polytope.contains( node.getBound() ); } @@ -547,11 +561,14 @@ void PolytopeIntersector::leave() void PolytopeIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable) { + if (reachedLimit()) return; + if ( !_polytope.contains( drawable->getBound() ) ) return; osg::TemplatePrimitiveFunctor func; func.setPolytope( _polytope, _referencePlane ); func.setDimensionMask( _dimensionMask ); + func.setLimitOneIntersection( _intersectionLimit == LIMIT_ONE_PER_DRAWABLE || _intersectionLimit == LIMIT_ONE ); drawable->accept(func);