OSG物体随鼠标移动(即点移动)
一.流程图:

二.点移动过程详解:
如下图所示:
可让物体移动平面D与显示器窗口平面M平行.
鼠标只在显示器窗口M上移动,当鼠标点到A点时,会看到物体的A’点被选中,当鼠标点从A移动到B时,实际的物体的移动也是只有平面D,此时对应物体实际点就为D平面上的B’.其中AB与A’B’两线是平行的.其实这归根到底还是基本的视锥体问题.平面D可由点A’和该平面的法线n确定:A’可由pointer.getLocalIntersectPoint()获得,是世界坐标系;n即为视线方向: pointer.getEyeDir().然后设置拖动的投影面为平面D即可,表示物体在平面D内移动: _projector->setPlane( *pplnPTPush);.

代码如下:
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osgManipulator/Command>
#include <osgManipulator/CommandManager>
#include <osgManipulator/Translate2DDragger>
#include <osgText/Text>
#include <iostream>
#include <string>
#include <osg/ShapeDrawable>
#pragma comment( lib, "osgd.lib"); //此库用于Debug版本下
#pragma comment( lib, "osgDBd.lib");
#pragma comment( lib, "osgViewerd.lib");
#pragma comment( lib, "osgmanipulatord.lib");
#pragma comment( lib, "osgTextd.lib");
#pragma comment( lib, "osgGAd.lib");
using namespace std;
using namespace osgManipulator;
osg::ref_ptr< osg::Group > g_pRoot= new osg::Group();
class CDraggerPoint: public osgManipulator::Translate2DDragger
{
public:
void setupDefaultGeometry()
{
osg::ref_ptr< osg::Geometry > pGeom= new osg::Geometry();
osg::ref_ptr< osg::Geode > pGeoSphere= new osg::Geode();
osg::ref_ptr< osg::Vec3Array > pVertices= new osg::Vec3Array( 3);
int t= 2;
(*pVertices)[ 0].set( 0, 0+ t, 0);
(*pVertices)[ 1].set( 0, 0+ t, -2);
(*pVertices)[ 2].set( 2, 0+ t, 0);
pGeom->setVertexArray( pVertices.get() );
osg::ref_ptr< osg::DrawElementsUInt> pTri= new osg::DrawElementsUInt( osg::PrimitiveSet::TRIANGLES , 0);
pTri->push_back( 0);
pTri->push_back( 1);
pTri->push_back( 2);
pGeom->addPrimitiveSet( pTri.get());
pGeoSphere->addDrawable( pGeom.get());
addChild( pGeoSphere.get());
}
virtual bool handle(const PointerInfo& pointer, const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
// Check if the dragger node is in the nodepath.
if (!pointer.contains(this)) return false;
switch (ea.getEventType())
{
// Pick start.
case (osgGA::GUIEventAdapter::PUSH):
{
// Get the LocalToWorld matrix for this node and set it for the projector.
osg::NodePath nodePathToRoot;
computeNodePathToRoot(*this,nodePathToRoot);
osg::Matrix localToWorld = osg::computeLocalToWorld(nodePathToRoot);
_projector->setLocalToWorld(localToWorld);
//设置点移动平面,点即鼠标与物体交点(世界坐标系),法线为//视线方向
osg::Plane* pplnPTPush= new osg::Plane( pointer.getEyeDir(), pointer.getLocalIntersectPoint()/** _projector->getLocalToWorld()*/);
_projector->setPlane( *pplnPTPush);
if (_projector->project(pointer, _startProjectedPoint))
{
// Generate the motion command.
osg::ref_ptr<TranslateInPlaneCommand> cmd = new TranslateInPlaneCommand(_projector->getPlane());
cmd->setStage(MotionCommand::START);
cmd->setReferencePoint(_startProjectedPoint);
cmd->setLocalToWorldAndWorldToLocal(_projector->getLocalToWorld(),_projector->getWorldToLocal());
// Dispatch command.
if (_commandManager)
{
_commandManager->addSelectionsToCommand(*cmd, *getParentDragger());
_commandManager->dispatch(*cmd);
}
//在该点处添加一个球
osg::ref_ptr< osg::Shape> sphere = new osg::Sphere( _startProjectedPoint* _projector->getLocalToWorld(), 0.08f);
osg::ref_ptr<osg::ShapeDrawable> sphereDrawable = new osg::ShapeDrawable(sphere);
osg::ref_ptr<osg::Geode> sphereGeode = new osg::Geode();
sphereGeode->addDrawable(sphereDrawable);
g_pRoot->addChild( sphereGeode);
// Set color to pick color.
setMaterialColor(_pickColor,*this);
getOrCreateStateSet()->setAttributeAndModes(_polygonOffset.get(), osg::StateAttribute::ON);
aa.requestRedraw();
}
return true;
}
// Pick move.
case (osgGA::GUIEventAdapter::DRAG):
{
osg::Vec3d projectedPoint;
if (_projector->project(pointer, projectedPoint))
{
// Generate the motion command.
osg::ref_ptr<TranslateInPlaneCommand> cmd = new TranslateInPlaneCommand(_projector->getPlane());
cmd->setStage(MotionCommand::MOVE);
cmd->setLocalToWorldAndWorldToLocal(_projector->getLocalToWorld(),_projector->getWorldToLocal());
cmd->setTranslation(projectedPoint - _startProjectedPoint);
cmd->setReferencePoint(_startProjectedPoint);
// Dispatch command.
if (_commandManager)
{
_commandManager->addSelectionsToCommand(*cmd, *getParentDragger());
_commandManager->dispatch(*cmd);
}
osg::ref_ptr< osg::Shape> sphere = new osg::Sphere( projectedPoint* _projector->getLocalToWorld(), 0.08f);
osg::ref_ptr<osg::ShapeDrawable> sphereDrawable = new osg::ShapeDrawable(sphere);
osg::ref_ptr<osg::Geode> sphereGeode = new osg::Geode();
sphereGeode->addDrawable(sphereDrawable);
g_pRoot->addChild( sphereGeode);
aa.requestRedraw();
}
return true;
}
// Pick finish.
case (osgGA::GUIEventAdapter::RELEASE):
{
osg::ref_ptr<TranslateInPlaneCommand> cmd = new TranslateInPlaneCommand(_projector->getPlane());
cmd->setStage(MotionCommand::FINISH);
cmd->setReferencePoint(_startProjectedPoint);
cmd->setLocalToWorldAndWorldToLocal(_projector->getLocalToWorld(),_projector->getWorldToLocal());
// Dispatch command.
if (_commandManager)
{
_commandManager->addSelectionsToCommand(*cmd, *getParentDragger());
_commandManager->dispatch(*cmd);
}
// Reset color.
setMaterialColor(_color,*this);
getOrCreateStateSet()->removeAttribute(_polygonOffset.get());
aa.requestRedraw();
return true;
}
default:
return false;
}
}
};
class PickModeHandler : public osgGA::GUIEventHandler
{
public:
enum Modes
{
VIEW = 0,
PICK
};
PickModeHandler():
_mode(VIEW),
_activeDragger(0)
{
}
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa,
osg::Object*, osg::NodeVisitor*)
{
osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
if (!view) return false;
if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Tab &&
ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN &&
_activeDragger == 0)
{
_mode = ! _mode;
}
if (VIEW == _mode) return false;
switch (ea.getEventType())
{
case osgGA::GUIEventAdapter::PUSH:
{
osgUtil::LineSegmentIntersector::Intersections intersections;
_pointer.reset();
if (view->computeIntersections(ea.getX(),ea.getY(),intersections))
{
_pointer.setCamera(view->getCamera());
_pointer.setMousePosition(ea.getX(), ea.getY());
for(osgUtil::LineSegmentIntersector::Intersections::iterator hitr = intersections.begin();
hitr != intersections.end(); ++hitr)
{
_pointer.addIntersection(hitr->nodePath, hitr->getLocalIntersectPoint());
}
for (osg::NodePath::iterator itr = _pointer._hitList.front().first.begin();
itr != _pointer._hitList.front().first.end();
++itr)
{
osgManipulator::Dragger* dragger = dynamic_cast<osgManipulator::Dragger*>(*itr);
if (dragger)
{
dragger->handle(_pointer, ea, aa);
_activeDragger = dragger;
break;
}
}
}
}
case osgGA::GUIEventAdapter::DRAG:
case osgGA::GUIEventAdapter::RELEASE:
{
if (_activeDragger)
{
_pointer._hitIter = _pointer._hitList.begin();
_pointer.setCamera(view->getCamera());
_pointer.setMousePosition(ea.getX(), ea.getY());
_activeDragger->handle(_pointer, ea, aa);
}
break;
}
default:
break;
}
if (ea.getEventType() == osgGA::GUIEventAdapter::RELEASE)
{
_activeDragger = 0;
_pointer.reset();
}
return true;
}
private:
unsigned int _mode;
osgManipulator::Dragger* _activeDragger;
osgManipulator::PointerInfo _pointer;
};
osgManipulator::Dragger* createDragger(const std::string& name)
{
osgManipulator::Dragger* dragger = 0;
CDraggerPoint* d = new CDraggerPoint();
d->setupDefaultGeometry();
dragger = d;
return dragger;
}
osg::Node* addDraggerToScene(osg::Node* scene, osgManipulator::CommandManager* cmdMgr, const std::string& name)
{
scene->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON);
osgManipulator::Selection* selection = new osgManipulator::Selection;
selection->addChild(scene);
osgManipulator::Dragger* dragger = createDragger(name);
dragger->setName( name);
osg::Group* root = new osg::Group;
root->addChild(dragger);
root->addChild(selection);
cmdMgr->connect(*dragger, *selection);
return root;
}
int main()
{
osg::ref_ptr< osg::Geode > pGeoSphere= new osg::Geode();
osg::ref_ptr< osg::Geometry > pGeom= new osg::Geometry();
osg::ref_ptr< osg::Vec3Array > pVertices= new osg::Vec3Array( 3);
(*pVertices)[ 0].set( 0+ 2, 0- 2, 0);
(*pVertices)[ 1].set( 0 , 0- 2, 2);
(*pVertices)[ 2].set( 0, 0- 2, 0);
pGeom->setVertexArray( pVertices.get() );
osg::ref_ptr< osg::DrawElementsUInt> pTri= new osg::DrawElementsUInt( osg::PrimitiveSet::TRIANGLES , 0);
pTri->push_back( 0);
pTri->push_back( 1);
pTri->push_back( 2);
pGeom->addPrimitiveSet( pTri.get());
pGeoSphere->addDrawable( pGeom.get());
//g_pRoot->addChild( pGeoSphere.get());//将非dragger的物体加入
osgViewer::Viewer viewer;
//cmdManager
osg::ref_ptr<osgManipulator::CommandManager> cmdMgr = new osgManipulator::CommandManager;
osg::ref_ptr< osg::Geode > pGeoSphereDragger= new osg::Geode();
g_pRoot->addChild(addDraggerToScene( pGeoSphereDragger.get(),cmdMgr,"Translate2DDragger") );
viewer.setSceneData( g_pRoot);
viewer.addEventHandler(new PickModeHandler());
return viewer.run();
}
本文详细介绍了如何在OSG(OpenSceneGraph)中实现物体随鼠标点击进行移动的操作。通过设置点移动平面和平面法线,利用Translate2DDragger类和PointerInfo对象,监听鼠标的PUSH、DRAG和RELEASE事件,动态更新物体位置,实现了物体在特定平面上的移动效果。同时,文章提供了一段完整的源代码示例。
1374

被折叠的 条评论
为什么被折叠?



