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

@ -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;
};

View File

@ -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:

View File

@ -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:

View File

@ -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:

View File

@ -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<LineSegmentIntersector> 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<LineSegmentIntersector> 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<LineSegmentIntersectorUtils::TriangleIntersector> 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;
}

View File

@ -359,13 +359,15 @@ namespace PlaneIntersectorUtils
osg::ref_ptr<osg::RefMatrix> _matrix;
bool _recordHeightsAsAttributes;
osg::ref_ptr<osg::EllipsoidModel> _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<PlaneIntersector> 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<PlaneIntersector> 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)"<<std::endl;
if (reachedLimit()) return;
if ( _plane.intersect( drawable->getBound() )!=0 ) return;
if ( !_polytope.contains( drawable->getBound() ) ) return;
@ -657,6 +665,7 @@ void PlaneIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable
osg::TriangleFunctor<PlaneIntersectorUtils::TriangleIntersector> 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();

View File

@ -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<PolytopeIntersector> 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<PolytopeIntersector> 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<PolytopeIntersectorUtils::PolytopePrimitiveIntersector> func;
func.setPolytope( _polytope, _referencePlane );
func.setDimensionMask( _dimensionMask );
func.setLimitOneIntersection( _intersectionLimit == LIMIT_ONE_PER_DRAWABLE || _intersectionLimit == LIMIT_ONE );
drawable->accept(func);