diff --git a/examples/osgkeyboardmouse/osgkeyboardmouse.cpp b/examples/osgkeyboardmouse/osgkeyboardmouse.cpp index 423d4efdf..3954a864c 100644 --- a/examples/osgkeyboardmouse/osgkeyboardmouse.cpp +++ b/examples/osgkeyboardmouse/osgkeyboardmouse.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -187,7 +188,62 @@ public: float mx = _sceneView->getViewport()->x() + (int)((float)_sceneView->getViewport()->width()*(ea.getXnormalized()*0.5f+0.5f)); float my = _sceneView->getViewport()->y() + (int)((float)_sceneView->getViewport()->height()*(ea.getYnormalized()*0.5f+0.5f)); - + +#if 1 + + osgUtil::LineSegmentIntersector* picker = new osgUtil::LineSegmentIntersector(osg::Vec3d(mx,my,0.0), osg::Vec3d(mx,my,1.0) ); + picker->setCoordinateFrame(osgUtil::Intersector::WINDOW); + + osgUtil::IntersectionVisitor iv(picker); + + _sceneView->getCamera()->accept(iv); + + osg::notify(osg::NOTICE)<<"Done pick, "<containsIntersections()<containsIntersections()) + { + osgUtil::LineSegmentIntersector::Intersection intersection = picker->getFirstIntersection(); + osg::notify(osg::NOTICE)<<"Picking "<=1)?nodePath[nodePath.size()-1]:0; + osg::Group* parent = (nodePath.size()>=2)?dynamic_cast(nodePath[nodePath.size()-2]):0; + + if (node) std::cout<<" Hits "<className()<<" nodePath size"<className()<(parent); + if (!parentAsScribe) + { + // node not already picked, so highlight it with an osgFX::Scribe + osgFX::Scribe* scribe = new osgFX::Scribe(); + scribe->addChild(node); + parent->replaceChild(node,scribe); + } + else + { + // node already picked so we want to remove scribe to unpick it. + osg::Node::ParentList parentList = parentAsScribe->getParents(); + for(osg::Node::ParentList::iterator itr=parentList.begin(); + itr!=parentList.end(); + ++itr) + { + (*itr)->replaceChild(parentAsScribe,node); + } + } + } + + } + + +#else + // do the pick traversal. osgUtil::PickVisitor pick(_sceneView->getViewport(), _sceneView->getProjectionMatrix(), @@ -239,6 +295,8 @@ public: } } +#endif + } void saveSelectedModel() diff --git a/include/osgUtil/IntersectionVisitor b/include/osgUtil/IntersectionVisitor index 2bd23a134..530ab56d9 100644 --- a/include/osgUtil/IntersectionVisitor +++ b/include/osgUtil/IntersectionVisitor @@ -34,9 +34,23 @@ class Intersector : public osg::Referenced { public: + enum CoordinateFrame + { + WINDOW, + PROJECTION, + VIEW, + MODEL + }; + Intersector(): + _coordinateFrame(MODEL), _disabledCount(0) {} + void setCoordinateFrame(CoordinateFrame cf) { _coordinateFrame = cf; } + + CoordinateFrame getCoordinateFrame() const { return _coordinateFrame; } + + virtual Intersector* clone(osgUtil::IntersectionVisitor& iv) = 0; virtual bool enter(const osg::Node& node) = 0; @@ -57,6 +71,7 @@ class Intersector : public osg::Referenced protected: + CoordinateFrame _coordinateFrame; unsigned int _disabledCount; }; @@ -68,9 +83,13 @@ class OSGUTIL_EXPORT LineSegmentIntersector : public Intersector public: LineSegmentIntersector(const osg::Vec3d& start, const osg::Vec3d& end, LineSegmentIntersector* parent=0); - + struct Intersection { + Intersection(): + ratio(-1.0), + primitiveIndex(0) {} + bool operator < (const Intersection& rhs) const { return ratio < rhs.ratio; } typedef std::vector IndexList; @@ -90,7 +109,8 @@ class OSGUTIL_EXPORT LineSegmentIntersector : public Intersector inline void insertIntersection(const Intersection& intersection) { getIntersections().insert(intersection); } inline Intersections& getIntersections() { return _parent ? _parent->_intersections : _intersections; } - + + inline Intersection getFirstIntersection() { Intersections& intersections = getIntersections(); return intersections.empty() ? Intersection() : *(intersections.begin()); } public: @@ -199,12 +219,24 @@ class OSGUTIL_EXPORT IntersectionVisitor : public osg::NodeVisitor /** Get the const read callback.*/ const ReadCallback* getReadCallback() const { return _readCallback.get(); } - + + + void pushWindowMatrix(osg::RefMatrix* matrix) { _windowStack.push_back(matrix); } + void pushWindowMatrix(osg::Viewport* viewport) { _windowStack.push_back(new osg::RefMatrix( viewport->computeWindowMatrix()) ); } + void popWindowMatrix() { _windowStack.pop_back(); } osg::RefMatrix* getWindowMatrix() { return _windowStack.empty() ? 0 : _windowStack.back().get(); } - osg::RefMatrix* getProjectionMatrix() { return _projectionStack.empty() ? 0 : _projectionStack.back().get(); } - osg::RefMatrix* getViewMatrix() { return _viewStack.empty() ? 0 : _viewStack.back().get(); } - osg::RefMatrix* getModelMatrix() { return _modelStack.empty() ? 0 : _modelStack.back().get(); } + void pushProjectionMatrix(osg::RefMatrix* matrix) { _projectionStack.push_back(matrix); } + void popProjectionMatrix() { _projectionStack.pop_back(); } + osg::RefMatrix* getProjectionMatrix() { return _projectionStack.empty() ? 0 : _projectionStack.back().get(); } + + void pushViewMatrix(osg::RefMatrix* matrix) { _viewStack.push_back(matrix); } + void popViewMatrix() { _viewStack.pop_back(); } + osg::RefMatrix* getViewMatrix() { return _viewStack.empty() ? 0 : _viewStack.back().get(); } + + void pushModelMatrix(osg::RefMatrix* matrix) { _modelStack.push_back(matrix); } + void popModelMatrix() { _modelStack.pop_back(); } + osg::RefMatrix* getModelMatrix() { return _modelStack.empty() ? 0 : _modelStack.back().get(); } public: diff --git a/src/osgUtil/IntersectionVisitor.cpp b/src/osgUtil/IntersectionVisitor.cpp index 6e15c52e2..9cbf88f4d 100644 --- a/src/osgUtil/IntersectionVisitor.cpp +++ b/src/osgUtil/IntersectionVisitor.cpp @@ -219,18 +219,40 @@ LineSegmentIntersector::LineSegmentIntersector(const osg::Vec3d& start, const os Intersector* LineSegmentIntersector::clone(osgUtil::IntersectionVisitor& iv) { - osg::RefMatrix* model= iv.getModelMatrix(); - if (model) - { - osg::Matrix inverse; - inverse.invert(*model); - - return new LineSegmentIntersector(_start * inverse, _end * inverse, this); - } - else + if (_coordinateFrame==MODEL && iv.getModelMatrix()==0) { return new LineSegmentIntersector(_start, _end, this); } + + // compute the matrix that takes this Intersector from its CoordinateFrame into the local MODEL coordinate frame + // that geometry in the scene graph will always be in. + osg::Matrix matrix; + switch (_coordinateFrame) + { + case(WINDOW): + if (iv.getWindowMatrix()) matrix.preMult( *iv.getWindowMatrix() ); + if (iv.getProjectionMatrix()) matrix.preMult( *iv.getProjectionMatrix() ); + if (iv.getViewMatrix()) matrix.preMult( *iv.getViewMatrix() ); + if (iv.getModelMatrix()) matrix.preMult( *iv.getModelMatrix() ); + break; + case(PROJECTION): + if (iv.getProjectionMatrix()) matrix.preMult( *iv.getProjectionMatrix() ); + if (iv.getViewMatrix()) matrix.preMult( *iv.getViewMatrix() ); + if (iv.getModelMatrix()) matrix.preMult( *iv.getModelMatrix() ); + break; + case(VIEW): + if (iv.getViewMatrix()) matrix.preMult( *iv.getViewMatrix() ); + if (iv.getModelMatrix()) matrix.preMult( *iv.getModelMatrix() ); + break; + case(MODEL): + if (iv.getModelMatrix()) matrix = *iv.getModelMatrix(); + break; + } + + osg::Matrix inverse; + inverse.invert(matrix); + + return new LineSegmentIntersector(_start * inverse, _end * inverse, this); } bool LineSegmentIntersector::enter(const osg::Node& node) @@ -615,8 +637,12 @@ void IntersectionVisitor::reset() void IntersectionVisitor::apply(osg::Node& node) { + osg::notify(osg::NOTICE)<<"apply(Node&)"< matrix = _modelStack.empty() ? new osg::RefMatrix() : new osg::RefMatrix(*_modelStack.back()); transform.computeLocalToWorldMatrix(*matrix,this); - _modelStack.push_back(matrix); + pushModelMatrix(matrix.get()); // now push an new intersector clone transform to the new local coordinates push_clone(); @@ -709,7 +739,7 @@ void IntersectionVisitor::apply(osg::Transform& transform) // pop the clone. pop_clone(); - _modelStack.pop_back(); + popModelMatrix(); // tidy up an cached cull variabes in the current intersector. leave(); @@ -720,7 +750,17 @@ void IntersectionVisitor::apply(osg::Projection& projection) { if (!enter(projection)) return; + pushProjectionMatrix(new osg::RefMatrix(projection.getMatrix()) ); + + // now push an new intersector clone transform to the new local coordinates + push_clone(); + traverse(projection); + + // pop the clone. + pop_clone(); + + popProjectionMatrix(); leave(); } @@ -728,9 +768,29 @@ void IntersectionVisitor::apply(osg::Projection& projection) void IntersectionVisitor::apply(osg::CameraNode& camera) { - if (!enter(camera)) return; + osg::notify(osg::NOTICE)<<"apply(CameraNode&)"<