Show
Ignore:
Timestamp:
05/23/07 13:05:59 (8 years ago)
Author:
robert
Message:

From Peter Hrenka, (note from Robert Osfield, renamed GenericPrimitiveFunctor? mention below to TemplatePrimitiveFunctor?).

"Since we desperately needed a means for picking Lines
and Points I implemented (hopefully!) proper geometrical tests
for the PolytopeIntersector?.

First of all I implemented a new "GenericPrimiteFunctor?"
which is basically an extended copy TriangleFunctor? which also
handles Points, Lines and Quads through suitable overloads of
operator(). I would have liked to call it "PrimitiveFunctor?"
but that name was already used...
I used a template method to remove redundancy in the
drawElements method overloads. If you know of platforms where
this will not work I can change it to the style used
in TriangleFunctor?.

In PolytopeIntersector?.cpp I implemented a
"PolytopePrimitiveIntersector?" which provides the needed
overloads for Points, Lines, Triangles and Quads to
the GenericPrimitiveFunctor?. This is then used in the
intersect method of PolytopeIntersector?.

Implementation summary:
- Points: Check distance to all planes
- Lines: Check distance of both ends against each plane.

If both are outside -> line is out
If both are in -> continue checking
One is in, one is out -> compute intersection point (candidate)
Then check all candidates against all other polytope
planes. The remaining candidates are the proper
intersection points of the line with the polytope.

- Triangles: Perform Line-Checks for all edges of the

triangle as above. If there is an proper intersection
-> done.
In the case where there are more than 2 polytope
plane to check against we have to check for the case
where the triangle encloses the polytope.
In that case the intersection lines of the polytope
planes are computed and checked against the triangle.

- Quads: handled as two triangles.

This is implementation is certainly not the fastest.
There are certainly ways and strategies to improve it.

I also enabled the code for PolytopeIntersector?
in osgkeyboardmouse and added keybindings to
switch the type of intersector ('p') and the picking
coordinate system ('c') on the fly. Since the
PolytopeIntersector? does not have a canonical
ordering for its intersections (as opposed to
the LineSegementIntersector?) I chaged the
implementation to toggle all hit geometries.

I tested the functionality with osgkeyboardmouse
and several models and it seems to work for
polygonal models. Special nodes such as billboards
do not work.

The next thing on my todo-list is to implement
a an improved Intersection-Structure for the
PolytopeIntersector?. We need to know
which primitives where hit (and where).

"

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • OpenSceneGraph/trunk/examples/osgkeyboardmouse/osgkeyboardmouse.cpp

    r6462 r6734  
    144144 
    145145    PickHandler(): 
    146         _mx(0.0),_my(0.0) {} 
     146        _mx(0.0),_my(0.0), 
     147        _usePolytopeIntersector(false), 
     148        _useWindowCoordinates(false) {} 
    147149 
    148150    ~PickHandler() {} 
     
    165167                    osg::notify(osg::NOTICE)<<"Saved model to file 'saved_model.osg'"<<std::endl; 
    166168                    osgDB::writeNodeFile(*(viewer->getSceneData()), "saved_model.osg"); 
     169                } 
     170                else if (ea.getKey()=='p') 
     171                { 
     172                    _usePolytopeIntersector = !_usePolytopeIntersector; 
     173                    if (_usePolytopeIntersector) 
     174                    { 
     175                        osg::notify(osg::NOTICE)<<"Using PolytopeIntersector"<<std::endl; 
     176                    } else { 
     177                        osg::notify(osg::NOTICE)<<"Using LineSegmentIntersector"<<std::endl; 
     178                    } 
     179                } 
     180                else if (ea.getKey()=='c') 
     181                { 
     182                    _useWindowCoordinates = !_useWindowCoordinates; 
     183                    if (_useWindowCoordinates) 
     184                    { 
     185                        osg::notify(osg::NOTICE)<<"Using window coordinates for picking"<<std::endl; 
     186                    } else { 
     187                        osg::notify(osg::NOTICE)<<"Using projection coordiates for picking"<<std::endl; 
     188                    } 
    167189                } 
    168190                else if (ea.getKey()==osgGA::GUIEventAdapter::KEY_Delete || ea.getKey()==osgGA::GUIEventAdapter::KEY_BackSpace) 
     
    207229        osg::Group* parent = 0; 
    208230 
    209         bool usePolytopePicking = false; 
    210         if (usePolytopePicking) 
    211         { 
    212  
    213 #if 0 
    214             // use window coordinates 
    215             // remap the mouse x,y into viewport coordinates. 
    216             osg::Viewport* viewport = viewer->getCamera()->getViewport(); 
    217             double mx = viewport->x() + (int)((double )viewport->width()*(ea.getXnormalized()*0.5+0.5)); 
    218             double my = viewport->y() + (int)((double )viewport->height()*(ea.getYnormalized()*0.5+0.5)); 
    219  
    220             // half width, height. 
    221             double w = 5.0f; 
    222             double h = 5.0f; 
    223             osgUtil::PolytopeIntersector* picker = new osgUtil::PolytopeIntersector( osgUtil::Intersector::WINDOW, mx-w, my-h, mx+w, my+h ); 
    224 #else 
    225             double mx = ea.getXnormalized(); 
    226             double my = ea.getYnormalized(); 
    227             double w = 0.05; 
    228             double h = 0.05; 
    229             osgUtil::PolytopeIntersector* picker = new osgUtil::PolytopeIntersector( osgUtil::Intersector::PROJECTION, mx-w, my-h, mx+w, my+h ); 
    230 #endif 
     231        if (_usePolytopeIntersector) 
     232        { 
     233            osgUtil::PolytopeIntersector* picker; 
     234            if (_useWindowCoordinates) 
     235            { 
     236                // use window coordinates 
     237                // remap the mouse x,y into viewport coordinates. 
     238                osg::Viewport* viewport = viewer->getCamera()->getViewport(); 
     239                double mx = viewport->x() + (int)((double )viewport->width()*(ea.getXnormalized()*0.5+0.5)); 
     240                double my = viewport->y() + (int)((double )viewport->height()*(ea.getYnormalized()*0.5+0.5)); 
     241 
     242                // half width, height. 
     243                double w = 5.0f; 
     244                double h = 5.0f; 
     245                picker = new osgUtil::PolytopeIntersector( osgUtil::Intersector::WINDOW, mx-w, my-h, mx+w, my+h ); 
     246            } else { 
     247                double mx = ea.getXnormalized(); 
     248                double my = ea.getYnormalized(); 
     249                double w = 0.05; 
     250                double h = 0.05; 
     251                picker = new osgUtil::PolytopeIntersector( osgUtil::Intersector::PROJECTION, mx-w, my-h, mx+w, my+h ); 
     252            } 
    231253            osgUtil::IntersectionVisitor iv(picker); 
    232254 
     
    235257            if (picker->containsIntersections()) 
    236258            { 
    237                 osgUtil::PolytopeIntersector::Intersection intersection = picker->getFirstIntersection(); 
     259                osgUtil::PolytopeIntersector::Intersections& intersections = picker->getIntersections(); 
     260 
     261                for (osgUtil::PolytopeIntersector::Intersections::iterator it=intersections.begin(); 
     262                     it!=intersections.end(); ++it) { 
     263                    osgUtil::PolytopeIntersector::Intersection intersection=*it; 
     264 
     265                    osg::NodePath& nodePath = intersection.nodePath; 
     266                    node = (nodePath.size()>=1)?nodePath[nodePath.size()-1]:0; 
     267                    parent = (nodePath.size()>=2)?dynamic_cast<osg::Group*>(nodePath[nodePath.size()-2]):0; 
     268 
     269                    if (node) std::cout<<"  Hits "<<node->className()<<" nodePath size"<<nodePath.size()<<std::endl; 
     270                    toggleScribe(parent, node); 
     271                } 
     272 
     273            } 
     274 
     275        } 
     276        else 
     277        { 
     278            osgUtil::LineSegmentIntersector* picker; 
     279            if (!_useWindowCoordinates) 
     280            { 
     281                // use non dimensional coordinates - in projection/clip space 
     282                picker = new osgUtil::LineSegmentIntersector( osgUtil::Intersector::PROJECTION, ea.getXnormalized(),ea.getYnormalized() ); 
     283            } else { 
     284                // use window coordinates 
     285                // remap the mouse x,y into viewport coordinates. 
     286                osg::Viewport* viewport = viewer->getCamera()->getViewport(); 
     287                float mx = viewport->x() + (int)((float)viewport->width()*(ea.getXnormalized()*0.5f+0.5f)); 
     288                float my = viewport->y() + (int)((float)viewport->height()*(ea.getYnormalized()*0.5f+0.5f)); 
     289                picker = new osgUtil::LineSegmentIntersector( osgUtil::Intersector::WINDOW, mx, my ); 
     290            } 
     291            osgUtil::IntersectionVisitor iv(picker); 
     292 
     293            viewer->getCamera()->accept(iv); 
     294 
     295            if (picker->containsIntersections()) 
     296            { 
     297                osgUtil::LineSegmentIntersector::Intersection intersection = picker->getFirstIntersection(); 
     298                osg::notify(osg::NOTICE)<<"Picked "<<intersection.localIntersectionPoint<<std::endl; 
    238299 
    239300                osg::NodePath& nodePath = intersection.nodePath; 
     
    242303 
    243304                if (node) std::cout<<"  Hits "<<node->className()<<" nodePath size"<<nodePath.size()<<std::endl; 
    244  
    245             } 
    246  
     305                toggleScribe(parent, node); 
     306            } 
     307        }         
     308 
     309        // now we try to decorate the hit node by the osgFX::Scribe to show that its been "picked" 
     310    } 
     311 
     312    void toggleScribe(osg::Group* parent, osg::Node* node) { 
     313        if (!parent || !node) return; 
     314 
     315        std::cout<<"  parent "<<parent->className()<<std::endl; 
     316 
     317        osgFX::Scribe* parentAsScribe = dynamic_cast<osgFX::Scribe*>(parent); 
     318        if (!parentAsScribe) 
     319        { 
     320            // node not already picked, so highlight it with an osgFX::Scribe 
     321            osgFX::Scribe* scribe = new osgFX::Scribe(); 
     322            scribe->addChild(node); 
     323            parent->replaceChild(node,scribe); 
    247324        } 
    248325        else 
    249326        { 
    250  
    251             #if 0 
    252             // use non dimensional coordinates - in projection/clip space 
    253             osgUtil::LineSegmentIntersector* picker = new osgUtil::LineSegmentIntersector( osgUtil::Intersector::PROJECTION, ea.getXnormalized(),ea.getYnormalized() ); 
    254             #else 
    255             // use window coordinates 
    256             // remap the mouse x,y into viewport coordinates. 
    257             osg::Viewport* viewport = viewer->getCamera()->getViewport(); 
    258             float mx = viewport->x() + (int)((float)viewport->width()*(ea.getXnormalized()*0.5f+0.5f)); 
    259             float my = viewport->y() + (int)((float)viewport->height()*(ea.getYnormalized()*0.5f+0.5f)); 
    260             osgUtil::LineSegmentIntersector* picker = new osgUtil::LineSegmentIntersector( osgUtil::Intersector::WINDOW, mx, my ); 
    261             #endif 
    262  
    263             osgUtil::IntersectionVisitor iv(picker); 
    264  
    265             viewer->getCamera()->accept(iv); 
    266  
    267             if (picker->containsIntersections()) 
    268             { 
    269                 osgUtil::LineSegmentIntersector::Intersection intersection = picker->getFirstIntersection(); 
    270                 osg::notify(osg::NOTICE)<<"Picked "<<intersection.localIntersectionPoint<<std::endl; 
    271  
    272                 osg::NodePath& nodePath = intersection.nodePath; 
    273                 node = (nodePath.size()>=1)?nodePath[nodePath.size()-1]:0; 
    274                 parent = (nodePath.size()>=2)?dynamic_cast<osg::Group*>(nodePath[nodePath.size()-2]):0; 
    275  
    276                 if (node) std::cout<<"  Hits "<<node->className()<<" nodePath size"<<nodePath.size()<<std::endl; 
    277  
    278             } 
    279         }         
    280  
    281         // now we try to decorate the hit node by the osgFX::Scribe to show that its been "picked" 
    282         if (parent && node) 
    283         { 
    284  
    285             std::cout<<"  parent "<<parent->className()<<std::endl; 
    286  
    287             osgFX::Scribe* parentAsScribe = dynamic_cast<osgFX::Scribe*>(parent); 
    288             if (!parentAsScribe) 
    289             { 
    290                 // node not already picked, so highlight it with an osgFX::Scribe 
    291                 osgFX::Scribe* scribe = new osgFX::Scribe(); 
    292                 scribe->addChild(node); 
    293                 parent->replaceChild(node,scribe); 
    294             } 
    295             else 
    296             { 
    297                 // node already picked so we want to remove scribe to unpick it. 
    298                 osg::Node::ParentList parentList = parentAsScribe->getParents(); 
    299                 for(osg::Node::ParentList::iterator itr=parentList.begin(); 
    300                     itr!=parentList.end(); 
    301                     ++itr) 
    302                 { 
    303                     (*itr)->replaceChild(parentAsScribe,node); 
    304                 } 
    305             } 
    306         } 
     327            // node already picked so we want to remove scribe to unpick it. 
     328            osg::Node::ParentList parentList = parentAsScribe->getParents(); 
     329            for(osg::Node::ParentList::iterator itr=parentList.begin(); 
     330                itr!=parentList.end(); 
     331                ++itr) 
     332            { 
     333                (*itr)->replaceChild(parentAsScribe,node); 
     334            } 
     335        } 
     336 
    307337    } 
    308338 
     
    324354 
    325355    float _mx,_my; 
     356    bool _usePolytopeIntersector; 
     357    bool _useWindowCoordinates; 
    326358}; 
    327359