From 91968a9bec07270fce917cc638409933bfd82fc2 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 15 Jan 2007 16:09:32 +0000 Subject: [PATCH] Improved handling of intersection computations on datasets with multiple cameras --- examples/osgcamera/osgcamera.cpp | 123 ++++++++++++++++++++++++++++++- include/osgViewer/View | 6 ++ src/osgViewer/View.cpp | 120 ++++++++++++++++++------------ 3 files changed, 198 insertions(+), 51 deletions(-) diff --git a/examples/osgcamera/osgcamera.cpp b/examples/osgcamera/osgcamera.cpp index ddaa00cc1..84b754cdb 100644 --- a/examples/osgcamera/osgcamera.cpp +++ b/examples/osgcamera/osgcamera.cpp @@ -6,6 +6,114 @@ #include #include +class ThreadingHandler : public osgGA::GUIEventHandler +{ +public: + + ThreadingHandler() {} + + bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) + { + osgViewer::Viewer* viewer = dynamic_cast(&aa); + if (!viewer) return false; + + switch(ea.getEventType()) + { + case(osgGA::GUIEventAdapter::KEYUP): + { + if (ea.getKey()=='m') + { + switch(viewer->getThreadingModel()) + { + case(osgViewer::Viewer::SingleThreaded): + viewer->setThreadingModel(osgViewer::Viewer::ThreadPerContext); + osg::notify(osg::NOTICE)<<"Threading model 'ThreadPerContext' selected."<setThreadingModel(osgViewer::Viewer::ThreadPerCamera); + osg::notify(osg::NOTICE)<<"Threading model 'ThreadPerCamera' selected."<setThreadingModel(osgViewer::Viewer::SingleThreaded); + osg::notify(osg::NOTICE)<<"Threading model 'SingleTheaded' selected."<getEndBarrierPosition()) + { + case(osgViewer::Viewer::BeforeSwapBuffers): + viewer->setEndBarrierPosition(osgViewer::Viewer::AfterSwapBuffers); + osg::notify(osg::NOTICE)<<"Threading model 'AfterSwapBuffers' selected."<setEndBarrierPosition(osgViewer::Viewer::BeforeSwapBuffers); + osg::notify(osg::NOTICE)<<"Threading model 'BeforeSwapBuffers' selected."< Filenames; + Filenames _filenames; + unsigned int _position; + + void add(const std::string& filename) { _filenames.push_back(filename); } + + bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) + { + osgViewer::Viewer* viewer = dynamic_cast(&aa); + if (!viewer) return false; + + if (_filenames.empty()) return false; + + switch(ea.getEventType()) + { + case(osgGA::GUIEventAdapter::KEYUP): + { + if (ea.getKey()=='l') + { + osg::ref_ptr model = osgDB::readNodeFile( _filenames[_position] ); + ++_position; + if (_position>=_filenames.size()) _position = 0; + + if (model.valid()) + { + viewer->setSceneData(model.get()); + } + + return true; + } + } + default: break; + } + + return false; + } + + bool _done; +}; + + void singleWindowMultipleCameras(osgViewer::Viewer& viewer) { osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface(); @@ -147,6 +255,18 @@ int main( int argc, char **argv ) if (apm.valid()) viewer.setCameraManipulator(apm.get()); else viewer.setCameraManipulator( new osgGA::TrackballManipulator() ); +#if 0 + + ModelHandler* modelHandler = new ModelHandler; + for(int i=1; iadd(arguments[i]); + } + + viewer.addEventHandler(modelHandler); + +#else + // load the scene. osg::ref_ptr loadedModel = osgDB::readNodeFiles(arguments); if (!loadedModel) @@ -156,8 +276,7 @@ int main( int argc, char **argv ) } viewer.setSceneData(loadedModel.get()); - - // viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded); +#endif viewer.realize(); diff --git a/include/osgViewer/View b/include/osgViewer/View index 4efc523fc..465333ce9 100644 --- a/include/osgViewer/View +++ b/include/osgViewer/View @@ -68,6 +68,10 @@ class OSGVIEWER_EXPORT View : public osg::View, public osgGA::GUIActionAdapter void setUpViewOnSingleScreen(unsigned int screenNum=0); + /** Get the camera which contains the pointer position x,y specified master cameras window/eye coords. + * Also passes back the local window coords for the graphics context associated with the camera passed back. */ + const osg::Camera* getCameraContainingPosition(float x, float y, float& local_x, float& local_y) const; + /** Compute intersections between a ray through the specified master cameras window/eye coords and a specified node. * Note, when a master cameras has slaves and no viewport itself its coordinate frame will be in clip space i.e. -1,-1 to 1,1, * while if its has a viewport the coordintates will be relative to its viewport dimensions. @@ -82,6 +86,8 @@ class OSGVIEWER_EXPORT View : public osg::View, public osgGA::GUIActionAdapter virtual void requestRedraw(); virtual void requestContinuousUpdate(bool needed=true); virtual void requestWarpPointer(float x,float y); + + public: diff --git a/src/osgViewer/View.cpp b/src/osgViewer/View.cpp index 571b0327d..4949614cd 100644 --- a/src/osgViewer/View.cpp +++ b/src/osgViewer/View.cpp @@ -311,26 +311,49 @@ void View::requestContinuousUpdate(bool) void View::requestWarpPointer(float x,float y) { - // osg::notify(osg::NOTICE)<<"View::requestWarpPointer("<getCurrentEventState(); - bool view_invert_y = eventState->getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS; - - getEventQueue()->mouseWarped(x,y); - - osgViewer::GraphicsWindow* gw = dynamic_cast(_camera->getGraphicsContext()); - if (gw) + float local_x, local_y; + const osg::Camera* camera = getCameraContainingPosition(x, y, local_x, local_y); + if (camera) { - bool gw_invert_y = gw->getEventQueue()->getCurrentEventState()->getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS; + const osgViewer::GraphicsWindow* gw = dynamic_cast(camera->getGraphicsContext()); + if (gw) + { + if (gw->getEventQueue()->getCurrentEventState()->getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS) + { + local_y = gw->getTraits()->height - local_y; + } + const_cast(gw)->requestWarpPointer(local_x, local_y); + } + } +} - x = x * float(gw->getTraits()->width) / (eventState->getXmax()-eventState->getXmin()); - y = y * float(gw->getTraits()->height) / (eventState->getYmax()-eventState->getYmin()); +const osg::Camera* View::getCameraContainingPosition(float x, float y, float& local_x, float& local_y) const +{ + const osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState(); + bool view_invert_y = eventState->getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS; + + double epsilon = 0.5; - if (view_invert_y != gw_invert_y) y = gw->getTraits()->height - y; + if (_camera->getGraphicsContext() && _camera->getViewport()) + { + const osg::Viewport* viewport = _camera->getViewport(); - gw->requestWarpPointer(x, y); + osg::Vec2d new_coord(x, y); - return; + osgViewer::GraphicsWindow* gw = dynamic_cast(_camera->getGraphicsContext()); + if (gw && gw->getEventQueue()->getCurrentEventState()->getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS) + { + new_coord.y() = gw->getTraits()->height - new_coord.y(); + } + + if (viewport && + new_coord.x() >= (viewport->x()-epsilon) && new_coord.y() >= (viewport->y()-epsilon) && + new_coord.x() < (viewport->x()+viewport->width()-1.0+epsilon) && new_coord.y() <= (viewport->y()+viewport->height()-1.0+epsilon) ) + { + local_x = new_coord.x(); + local_y = new_coord.y(); + return _camera.get(); + } } osg::Matrix masterCameraVPW = getCamera()->getViewMatrix() * getCamera()->getProjectionMatrix(); @@ -343,15 +366,14 @@ void View::requestWarpPointer(float x,float y) // osg::notify(osg::NOTICE)<<" remapped ("<(camera->getGraphicsContext()); - if (gw) - { - x = new_coord.x(); - y = new_coord.y(); - - bool gw_invert_y = gw->getEventQueue()->getCurrentEventState()->getMouseYOrientation()==osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS; - - if (gw_invert_y) y = gw->getTraits()->height - y; - - gw->requestWarpPointer(x, y); - - return; - } + return camera; } else { // osg::notify(osg::NOTICE)<<" not in viewport "<x()<<" "<<(viewport->x()+viewport->width())<getViewport() ? osgUtil::Intersector::WINDOW : osgUtil::Intersector::PROJECTION; - osgUtil::LineSegmentIntersector* picker = new osgUtil::LineSegmentIntersector(cf, x, y); - + osgUtil::LineSegmentIntersector::CoordinateFrame cf = camera->getViewport() ? osgUtil::Intersector::WINDOW : osgUtil::Intersector::PROJECTION; + osgUtil::LineSegmentIntersector* picker = new osgUtil::LineSegmentIntersector(cf, local_x, local_y); + osgUtil::IntersectionVisitor iv(picker); iv.setTraversalMask(traversalMask); - _camera->accept(iv); + const_cast(camera)->accept(iv); if (picker->containsIntersections()) { @@ -418,28 +434,34 @@ bool View::computeIntersections(float x,float y, osgUtil::LineSegmentIntersector intersections.clear(); return false; } + + return false; } bool View::computeIntersections(float x,float y, osg::NodePath& nodePath, osgUtil::LineSegmentIntersector::Intersections& intersections,osg::Node::NodeMask traversalMask) { if (!_camera.valid()) return false; - osg::Matrix matrix = osg::computeWorldToLocal(nodePath) * _camera->getViewMatrix() * _camera->getProjectionMatrix(); + float local_x, local_y = 0.0; + const osg::Camera* camera = getCameraContainingPosition(x, y, local_x, local_y); + if (!camera) camera = _camera.get(); + osg::Matrix matrix = osg::computeWorldToLocal(nodePath) * camera->getViewMatrix() * camera->getProjectionMatrix(); + double zNear = -1.0; double zFar = 1.0; - if (_camera->getViewport()) + if (camera->getViewport()) { - matrix.postMult(_camera->getViewport()->computeWindowMatrix()); + matrix.postMult(camera->getViewport()->computeWindowMatrix()); zNear = 0.0; zFar = 1.0; } - + osg::Matrix inverse; inverse.invert(matrix); - osg::Vec3d startVertex = osg::Vec3d(x,y,zNear) * inverse; - osg::Vec3d endVertex = osg::Vec3d(x,y,zFar) * inverse; + osg::Vec3d startVertex = osg::Vec3d(local_x,local_y,zNear) * inverse; + osg::Vec3d endVertex = osg::Vec3d(local_x,local_y,zFar) * inverse; osgUtil::LineSegmentIntersector* picker = new osgUtil::LineSegmentIntersector(osgUtil::Intersector::MODEL, startVertex, endVertex);