From 7fb8dfe5ed9920c84c2f28e903d5ce528590deaa Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 10 Feb 2005 21:18:04 +0000 Subject: [PATCH] From Chris Xennon, add support for billboard intersections + fix to addLineSegments. Small addition from Robert Osfield of setLODSelectionMode(..) to control the LOD selection behavior. --- include/osgUtil/IntersectVisitor | 25 ++++++++++++++++ src/osgUtil/IntersectVisitor.cpp | 49 ++++++++++++++++++++++++++++++-- 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/include/osgUtil/IntersectVisitor b/include/osgUtil/IntersectVisitor index 518307496..3464693d0 100644 --- a/include/osgUtil/IntersectVisitor +++ b/include/osgUtil/IntersectVisitor @@ -110,6 +110,28 @@ class OSGUTIL_EXPORT IntersectVisitor : public osg::NodeVisitor bool hits(); + enum LODSelectionMode + { + USE_HEIGHEST_LEVEL_OF_DETAIL, + USE_SEGMENT_START_POINT_AS_EYE_POINT_FOR_LOD_LEVEL_SELECTION + }; + + void setLODSelectionMode(LODSelectionMode mode) { _lodSelectionMode = mode; } + LODSelectionMode getLODSelectionMode() const { return _lodSelectionMode; } + + /** Set the eye point in local coordinates. + * This is a pseudo-EyePoint for billboarding and LOD purposes. + * It is copied from the Start point of the most-recently-added segment + * of the intersection ray set (IntersectState::_segList). */ + void setEyePoint(const osg::Vec3& eye) { _pseudoEyePoint = eye; } + + virtual osg::Vec3 getEyePoint() const { return _pseudoEyePoint; } + + + /** Get the distance from a point to the eye point, distance value in local coordinate system. + * This is calculated using the pseudo-EyePoint (above) when doing LOD calculcations. */ + virtual float getDistanceToEyePoint(const osg::Vec3& pos, bool withLODScale) const; + virtual void apply(osg::Node&); virtual void apply(osg::Geode& node); virtual void apply(osg::Billboard& node); @@ -166,6 +188,9 @@ class OSGUTIL_EXPORT IntersectVisitor : public osg::NodeVisitor osg::NodePath _nodePath; LineSegmentHitListMap _segHitList; + + LODSelectionMode _lodSelectionMode; + osg::Vec3 _pseudoEyePoint; }; } diff --git a/src/osgUtil/IntersectVisitor.cpp b/src/osgUtil/IntersectVisitor.cpp index dead506a1..e7aed945a 100644 --- a/src/osgUtil/IntersectVisitor.cpp +++ b/src/osgUtil/IntersectVisitor.cpp @@ -150,8 +150,15 @@ bool IntersectVisitor::IntersectState::isCulled(const BoundingBox& bb,LineSegmen IntersectVisitor::IntersectVisitor() { + // overide the default node visitor mode. setTraversalMode(NodeVisitor::TRAVERSE_ACTIVE_CHILDREN); + + // Initialize eyepoint to 0,0,0 + setEyePoint(Vec3(0.0f,0.0f,0.0f)); + + setLODSelectionMode(USE_HEIGHEST_LEVEL_OF_DETAIL); // orignal IntersectVisitor behavior + //setLODSelectionMode(USE_SEGMENT_START_POINT_AS_EYE_POINT_FOR_LOD_LEVEL_SELECTION); reset(); } @@ -174,6 +181,21 @@ void IntersectVisitor::reset() } +float IntersectVisitor::getDistanceToEyePoint(const Vec3& pos, bool /*withLODScale*/) const +{ + if (_lodSelectionMode==USE_SEGMENT_START_POINT_AS_EYE_POINT_FOR_LOD_LEVEL_SELECTION) + { + // LODScale is not available to IntersectVisitor, so we ignore the withLODScale argument + //if (withLODScale) return (pos-getEyePoint()).length()*getLODScale(); + //else return (pos-getEyePoint()).length(); + return (pos-getEyePoint()).length(); + } + else + { + return 0.0f; + } +} + bool IntersectVisitor::hits() { @@ -198,16 +220,19 @@ void IntersectVisitor::addLineSegment(LineSegment* seg) return; } + IntersectState* cis = _intersectStateStack.back().get(); + + setEyePoint(seg->start()); // set start of line segment to be pseudo EyePoint for billboarding and LOD purposes + // first check to see if segment has already been added. - for(LineSegmentHitListMap::iterator itr = _segHitList.begin(); - itr != _segHitList.end(); + for(IntersectState::LineSegmentList::iterator itr = cis->_segList.begin(); + itr != cis->_segList.end(); ++itr) { if (itr->first == seg) return; } // create a new segment transformed to local coordintes. - IntersectState* cis = _intersectStateStack.back().get(); LineSegment* ns = new LineSegment; if (cis->_inverse.valid()) ns->mult(*seg,*(cis->_inverse)); @@ -293,6 +318,7 @@ void IntersectVisitor::leaveNode() } + void IntersectVisitor::apply(Node& node) { if (!enterNode(node)) return; @@ -572,6 +598,23 @@ void IntersectVisitor::apply(Billboard& node) { if (!enterNode(node)) return; + // IntersectVisitor doesn't have getEyeLocal(), can we use NodeVisitor::getEyePoint()? + const Vec3& eye_local = getEyePoint(); + + for(unsigned int i = 0; i < node.getNumDrawables(); i++ ) + { + const Vec3& pos = node.getPosition(i); + osg::ref_ptr billboard_matrix = new RefMatrix; + node.computeMatrix(*billboard_matrix,eye_local,pos); + + pushMatrix(*billboard_matrix); + + intersect(*node.getDrawable(i)); + + popMatrix(); + + } + leaveNode(); }