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.

"
This commit is contained in:
Robert Osfield 2011-03-14 10:07:15 +00:00
parent 76dea3d0f4
commit 7cd74f0282
7 changed files with 75 additions and 10 deletions

View File

@ -42,8 +42,17 @@ class Intersector : public osg::Referenced
MODEL MODEL
}; };
enum IntersectionLimit
{
NO_LIMIT,
LIMIT_ONE_PER_DRAWABLE,
LIMIT_ONE,
LIMIT_NEAREST
};
Intersector(CoordinateFrame cf=MODEL): Intersector(CoordinateFrame cf=MODEL):
_coordinateFrame(cf), _coordinateFrame(cf),
_intersectionLimit(NO_LIMIT),
_disabledCount(0) {} _disabledCount(0) {}
@ -51,6 +60,9 @@ class Intersector : public osg::Referenced
CoordinateFrame getCoordinateFrame() const { return _coordinateFrame; } CoordinateFrame getCoordinateFrame() const { return _coordinateFrame; }
void setIntersectionLimit(IntersectionLimit limit) { _intersectionLimit = limit; }
IntersectionLimit getIntersectionLimit() const { return _intersectionLimit; }
virtual Intersector* clone(osgUtil::IntersectionVisitor& iv) = 0; virtual Intersector* clone(osgUtil::IntersectionVisitor& iv) = 0;
@ -70,9 +82,12 @@ class Intersector : public osg::Referenced
inline void decrementDisabledCount() { if (_disabledCount>0) --_disabledCount; } inline void decrementDisabledCount() { if (_disabledCount>0) --_disabledCount; }
inline bool reachedLimit() { return _intersectionLimit == LIMIT_ONE && containsIntersections(); }
protected: protected:
CoordinateFrame _coordinateFrame; CoordinateFrame _coordinateFrame;
IntersectionLimit _intersectionLimit;
unsigned int _disabledCount; unsigned int _disabledCount;
}; };

View File

@ -91,7 +91,7 @@ class OSGUTIL_EXPORT LineSegmentIntersector : public Intersector
virtual void reset(); virtual void reset();
virtual bool containsIntersections() { return !_intersections.empty(); } virtual bool containsIntersections() { return !getIntersections().empty(); }
protected: protected:

View File

@ -86,7 +86,7 @@ class OSGUTIL_EXPORT PlaneIntersector : public Intersector
virtual void reset(); virtual void reset();
virtual bool containsIntersections() { return !_intersections.empty(); } virtual bool containsIntersections() { return !getIntersections().empty(); }
protected: protected:

View File

@ -109,7 +109,7 @@ class OSGUTIL_EXPORT PolytopeIntersector : public Intersector
virtual void reset(); virtual void reset();
virtual bool containsIntersections() { return !_intersections.empty(); } virtual bool containsIntersections() { return !getIntersections().empty(); }
protected: protected:

View File

@ -63,6 +63,7 @@ namespace LineSegmentIntersectorUtils
int _index; int _index;
float _ratio; float _ratio;
bool _hit; bool _hit;
bool _limitOneIntersection;
TriangleIntersections _intersections; TriangleIntersections _intersections;
@ -72,6 +73,7 @@ namespace LineSegmentIntersectorUtils
_index = 0; _index = 0;
_ratio = 0.0f; _ratio = 0.0f;
_hit = false; _hit = false;
_limitOneIntersection = false;
} }
void set(const osg::Vec3d& start, osg::Vec3d& end, float ratio=FLT_MAX) void set(const osg::Vec3d& start, osg::Vec3d& end, float ratio=FLT_MAX)
@ -90,6 +92,8 @@ namespace LineSegmentIntersectorUtils
{ {
++_index; ++_index;
if (_limitOneIntersection && _hit) return;
if (v1==v2 || v2==v3 || v1==v3) return; if (v1==v2 || v2==v3 || v1==v3) return;
osg::Vec3 v12 = v2-v1; osg::Vec3 v12 = v2-v1;
@ -238,6 +242,7 @@ Intersector* LineSegmentIntersector::clone(osgUtil::IntersectionVisitor& iv)
{ {
osg::ref_ptr<LineSegmentIntersector> lsi = new LineSegmentIntersector(_start, _end); osg::ref_ptr<LineSegmentIntersector> lsi = new LineSegmentIntersector(_start, _end);
lsi->_parent = this; lsi->_parent = this;
lsi->_intersectionLimit = this->_intersectionLimit;
return lsi.release(); return lsi.release();
} }
@ -271,11 +276,13 @@ Intersector* LineSegmentIntersector::clone(osgUtil::IntersectionVisitor& iv)
osg::ref_ptr<LineSegmentIntersector> lsi = new LineSegmentIntersector(_start * inverse, _end * inverse); osg::ref_ptr<LineSegmentIntersector> lsi = new LineSegmentIntersector(_start * inverse, _end * inverse);
lsi->_parent = this; lsi->_parent = this;
lsi->_intersectionLimit = this->_intersectionLimit;
return lsi.release(); return lsi.release();
} }
bool LineSegmentIntersector::enter(const osg::Node& node) bool LineSegmentIntersector::enter(const osg::Node& node)
{ {
if (reachedLimit()) return false;
return !node.isCullingActive() || intersects( node.getBound() ); return !node.isCullingActive() || intersects( node.getBound() );
} }
@ -286,6 +293,8 @@ void LineSegmentIntersector::leave()
void LineSegmentIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable) void LineSegmentIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable)
{ {
if (reachedLimit()) return;
osg::Vec3d s(_start), e(_end); osg::Vec3d s(_start), e(_end);
if ( !intersectAndClip( s, e, drawable->getBound() ) ) return; if ( !intersectAndClip( s, e, drawable->getBound() ) ) return;
@ -354,6 +363,7 @@ void LineSegmentIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Dr
osg::TriangleFunctor<LineSegmentIntersectorUtils::TriangleIntersector> ti; osg::TriangleFunctor<LineSegmentIntersectorUtils::TriangleIntersector> ti;
ti.set(s,e); ti.set(s,e);
ti._limitOneIntersection = (_intersectionLimit == LIMIT_ONE_PER_DRAWABLE || _intersectionLimit == LIMIT_ONE);
drawable->accept(ti); drawable->accept(ti);
if (ti._hit) if (ti._hit)
@ -371,6 +381,14 @@ void LineSegmentIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Dr
// remap ratio into _start, _end range // remap ratio into _start, _end range
double remap_ratio = ((s-_start).length() + ratio * (e-s).length() )/(_end-_start).length(); 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; LineSegmentIntersectorUtils::TriangleIntersection& triHit = thitr->second;
Intersection hit; Intersection hit;
@ -450,6 +468,12 @@ bool LineSegmentIntersector::intersects(const osg::BoundingSphere& bs)
if (r1>=1.0 && r2>=1.0) return false; 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. // passed all the rejection tests so line must intersect bounding sphere, return true.
return true; return true;
} }

View File

@ -359,6 +359,7 @@ namespace PlaneIntersectorUtils
osg::ref_ptr<osg::RefMatrix> _matrix; osg::ref_ptr<osg::RefMatrix> _matrix;
bool _recordHeightsAsAttributes; bool _recordHeightsAsAttributes;
osg::ref_ptr<osg::EllipsoidModel> _em; osg::ref_ptr<osg::EllipsoidModel> _em;
bool _limitOneIntersection;
PolylineConnector _polylineConnector; PolylineConnector _polylineConnector;
@ -366,6 +367,7 @@ namespace PlaneIntersectorUtils
TriangleIntersector() TriangleIntersector()
{ {
_hit = false; _hit = false;
_limitOneIntersection = false;
} }
void set(const osg::Plane& plane, const osg::Polytope& polytope, osg::RefMatrix* matrix, bool recordHeightsAsAttributes, osg::EllipsoidModel* em) void set(const osg::Plane& plane, const osg::Polytope& polytope, osg::RefMatrix* matrix, bool recordHeightsAsAttributes, osg::EllipsoidModel* em)
@ -440,6 +442,8 @@ namespace PlaneIntersectorUtils
inline void operator () (const osg::Vec3& v1,const osg::Vec3& v2,const osg::Vec3& v3, bool) 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 d1 = _plane.distance(v1);
double d2 = _plane.distance(v2); double d2 = _plane.distance(v2);
double d3 = _plane.distance(v3); double d3 = _plane.distance(v3);
@ -590,6 +594,7 @@ Intersector* PlaneIntersector::clone(osgUtil::IntersectionVisitor& iv)
{ {
osg::ref_ptr<PlaneIntersector> pi = new PlaneIntersector(_plane, _polytope); osg::ref_ptr<PlaneIntersector> pi = new PlaneIntersector(_plane, _polytope);
pi->_parent = this; pi->_parent = this;
pi->_intersectionLimit = this->_intersectionLimit;
pi->_recordHeightsAsAttributes = _recordHeightsAsAttributes; pi->_recordHeightsAsAttributes = _recordHeightsAsAttributes;
pi->_em = _em; pi->_em = _em;
return pi.release(); return pi.release();
@ -628,6 +633,7 @@ Intersector* PlaneIntersector::clone(osgUtil::IntersectionVisitor& iv)
osg::ref_ptr<PlaneIntersector> pi = new PlaneIntersector(plane, transformedPolytope); osg::ref_ptr<PlaneIntersector> pi = new PlaneIntersector(plane, transformedPolytope);
pi->_parent = this; pi->_parent = this;
pi->_intersectionLimit = this->_intersectionLimit;
pi->_recordHeightsAsAttributes = _recordHeightsAsAttributes; pi->_recordHeightsAsAttributes = _recordHeightsAsAttributes;
pi->_em = _em; pi->_em = _em;
return pi.release(); return pi.release();
@ -635,6 +641,7 @@ Intersector* PlaneIntersector::clone(osgUtil::IntersectionVisitor& iv)
bool PlaneIntersector::enter(const osg::Node& node) bool PlaneIntersector::enter(const osg::Node& node)
{ {
if (reachedLimit()) return false;
return !node.isCullingActive() || return !node.isCullingActive() ||
( _plane.intersect(node.getBound())==0 && _polytope.contains(node.getBound()) ); ( _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)"<<std::endl; // OSG_NOTICE<<"PlaneIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable)"<<std::endl;
if (reachedLimit()) return;
if ( _plane.intersect( drawable->getBound() )!=0 ) return; if ( _plane.intersect( drawable->getBound() )!=0 ) return;
if ( !_polytope.contains( drawable->getBound() ) ) return; if ( !_polytope.contains( drawable->getBound() ) ) return;
@ -657,6 +665,7 @@ void PlaneIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable
osg::TriangleFunctor<PlaneIntersectorUtils::TriangleIntersector> ti; osg::TriangleFunctor<PlaneIntersectorUtils::TriangleIntersector> ti;
ti.set(_plane, _polytope, iv.getModelMatrix(), _recordHeightsAsAttributes, _em.get()); ti.set(_plane, _polytope, iv.getModelMatrix(), _recordHeightsAsAttributes, _em.get());
ti._limitOneIntersection = (_intersectionLimit == LIMIT_ONE_PER_DRAWABLE || _intersectionLimit == LIMIT_ONE);
drawable->accept(ti); drawable->accept(ti);
ti._polylineConnector.consolidatePolylineLists(); ti._polylineConnector.consolidatePolylineLists();

View File

@ -88,6 +88,7 @@ namespace PolytopeIntersectorUtils
PolytopePrimitiveIntersector() : PolytopePrimitiveIntersector() :
_index(0), _index(0),
_dimensionMask( PolytopeIntersector::AllDims ), _dimensionMask( PolytopeIntersector::AllDims ),
_limitOneIntersection( false ),
_candidates(20) {} _candidates(20) {}
void addIntersection(unsigned int index, const CandList_t& cands) { void addIntersection(unsigned int index, const CandList_t& cands) {
@ -130,6 +131,9 @@ namespace PolytopeIntersectorUtils
{ {
++_index; ++_index;
if ((_dimensionMask & PolytopeIntersector::DimZero) == 0) return; if ((_dimensionMask & PolytopeIntersector::DimZero) == 0) return;
if (_limitOneIntersection && !intersections.empty()) return;
for (PlaneList::const_iterator it=_planes.begin(); it!=_planes.end(); ++it) for (PlaneList::const_iterator it=_planes.begin(); it!=_planes.end(); ++it)
{ {
const osg::Plane& plane=*it; const osg::Plane& plane=*it;
@ -147,6 +151,8 @@ namespace PolytopeIntersectorUtils
++_index; ++_index;
if ((_dimensionMask & PolytopeIntersector::DimOne) == 0) return; if ((_dimensionMask & PolytopeIntersector::DimOne) == 0) return;
if (_limitOneIntersection && !intersections.empty()) return;
PlaneMask selector_mask = 0x1; PlaneMask selector_mask = 0x1;
PlaneMask inside_mask = 0x0; PlaneMask inside_mask = 0x0;
_candidates.clear(); _candidates.clear();
@ -210,6 +216,8 @@ namespace PolytopeIntersectorUtils
++_index; ++_index;
if ((_dimensionMask & PolytopeIntersector::DimTwo) == 0) return; if ((_dimensionMask & PolytopeIntersector::DimTwo) == 0) return;
if (_limitOneIntersection && !intersections.empty()) return;
PlaneMask selector_mask = 0x1; PlaneMask selector_mask = 0x1;
PlaneMask inside_mask = 0x0; PlaneMask inside_mask = 0x0;
_candidates.clear(); _candidates.clear();
@ -354,6 +362,8 @@ namespace PolytopeIntersectorUtils
void setDimensionMask(unsigned int dimensionMask) { _dimensionMask = dimensionMask; } void setDimensionMask(unsigned int dimensionMask) { _dimensionMask = dimensionMask; }
void setLimitOneIntersection(bool limit) { _limitOneIntersection = limit; }
void setPolytope(osg::Polytope& polytope, osg::Plane& referencePlane) void setPolytope(osg::Polytope& polytope, osg::Plane& referencePlane)
{ {
_referencePlane = referencePlane; _referencePlane = referencePlane;
@ -426,6 +436,7 @@ namespace PolytopeIntersectorUtils
unsigned int _index; unsigned int _index;
private: private:
bool _limitOneIntersection;
unsigned int _dimensionMask; unsigned int _dimensionMask;
PlaneList _planes; ///< active planes extracted from polytope PlaneList _planes; ///< active planes extracted from polytope
LinesList _lines; ///< all intersection lines of two polytope planes LinesList _lines; ///< all intersection lines of two polytope planes
@ -492,6 +503,7 @@ Intersector* PolytopeIntersector::clone(osgUtil::IntersectionVisitor& iv)
{ {
osg::ref_ptr<PolytopeIntersector> pi = new PolytopeIntersector(_polytope); osg::ref_ptr<PolytopeIntersector> pi = new PolytopeIntersector(_polytope);
pi->_parent = this; pi->_parent = this;
pi->_intersectionLimit = this->_intersectionLimit;
pi->_dimensionMask = this->_dimensionMask; pi->_dimensionMask = this->_dimensionMask;
pi->_referencePlane = this->_referencePlane; pi->_referencePlane = this->_referencePlane;
return pi.release(); return pi.release();
@ -527,6 +539,7 @@ Intersector* PolytopeIntersector::clone(osgUtil::IntersectionVisitor& iv)
osg::ref_ptr<PolytopeIntersector> pi = new PolytopeIntersector(transformedPolytope); osg::ref_ptr<PolytopeIntersector> pi = new PolytopeIntersector(transformedPolytope);
pi->_parent = this; pi->_parent = this;
pi->_intersectionLimit = this->_intersectionLimit;
pi->_dimensionMask = this->_dimensionMask; pi->_dimensionMask = this->_dimensionMask;
pi->_referencePlane = this->_referencePlane; pi->_referencePlane = this->_referencePlane;
pi->_referencePlane.transformProvidingInverse(matrix); pi->_referencePlane.transformProvidingInverse(matrix);
@ -535,6 +548,7 @@ Intersector* PolytopeIntersector::clone(osgUtil::IntersectionVisitor& iv)
bool PolytopeIntersector::enter(const osg::Node& node) bool PolytopeIntersector::enter(const osg::Node& node)
{ {
if (reachedLimit()) return false;
return !node.isCullingActive() || _polytope.contains( node.getBound() ); return !node.isCullingActive() || _polytope.contains( node.getBound() );
} }
@ -547,11 +561,14 @@ void PolytopeIntersector::leave()
void PolytopeIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable) void PolytopeIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable)
{ {
if (reachedLimit()) return;
if ( !_polytope.contains( drawable->getBound() ) ) return; if ( !_polytope.contains( drawable->getBound() ) ) return;
osg::TemplatePrimitiveFunctor<PolytopeIntersectorUtils::PolytopePrimitiveIntersector> func; osg::TemplatePrimitiveFunctor<PolytopeIntersectorUtils::PolytopePrimitiveIntersector> func;
func.setPolytope( _polytope, _referencePlane ); func.setPolytope( _polytope, _referencePlane );
func.setDimensionMask( _dimensionMask ); func.setDimensionMask( _dimensionMask );
func.setLimitOneIntersection( _intersectionLimit == LIMIT_ONE_PER_DRAWABLE || _intersectionLimit == LIMIT_ONE );
drawable->accept(func); drawable->accept(func);