OSG實現鼠標拖拽物體

首先要具備射線拾取的基本知識和向量運算的基礎知識,屏幕點轉換爲三維點怎麼取轉換。
現在先看一下屏幕的點如何轉換爲三維點,代碼如下:

osg::Vec3 screenToWorld(osgViewer::Viewer* viewer,double dx,double dy)
{
	osg::Camera *camera = viewer->getCamera();
	osg::Matrix viewMat = camera->getViewMatrix(); //獲取當前視圖矩陣
	osg::Matrix projMat = camera->getProjectionMatrix();//獲取投影矩陣
	osg::Matrix windMat = camera->getViewport()->computeWindowMatrix();//獲取窗口矩陣
	osg::Matrix MVPW = viewMat * projMat *windMat;  //視圖-》投影-》窗口變換

	osg::Matrix inverseMVPW = osg::Matrix::inverse(MVPW);  
	osg::Vec3 mouseWorld = osg::Vec3(dx, dy, 0) * inverseMVPW;  
	return mouseWorld;
}

好了,上述代碼完成從屏幕的二維點變換到世界的三維點,接下來實現以下鼠標點拾取物體,代碼如下:

//參數說明:firstPos:是當前攝像機的位置。endPos:爲偏移座標值,eye + curRayLineDir*100
//curRayLineDir = mouseWorldPos(屏幕點轉三維點使用上面的函數) - eye;
//curRayLineDir.normallize();
void CIntersectEventHandler::rayLinePick(const osg::Vec3& firstPos,const osg::Vec3& endPos)
{
	osg::ref_ptr<osgUtil::LineSegmentIntersector> lineSegmentIntesector = \
		new osgUtil::LineSegmentIntersector(firstPos,endPos);
	osgUtil::IntersectionVisitor intersectionVisitor(lineSegmentIntesector);

	m_matNode->accept(intersectionVisitor);//m_matNode爲你拾取的物體

	osgUtil::LineSegmentIntersector::Intersections intersections;
	if (lineSegmentIntesector->containsIntersections())
	{
		intersections = lineSegmentIntesector->getIntersections();
		for(auto iter = intersections.begin(); iter != intersections.end(); ++iter)
		{
			osg::NodePath nodePath = iter->nodePath;
			m_pickPoint = iter->getWorldIntersectPoint();
			for(int i=0; i<nodePath.size(); ++i)
			{
				m_pickObj = dynamic_cast<osg::MatrixTransform*>(nodePath[i]);//拾取到的node
			}
		}
	}
}

最後我要計算當前的鼠標拾取到物體之後移動的位置。代碼走你:

//我是在osgGA::GUIEventAdapter::DRAG進行拖拽的功能
		    if(m_pickObj && m_bLeftMouseBtn)//這個布爾值就是曉得鼠標的左鍵是否按下了。
			{
				//獲取當前的攝像機的位置
				osg::Vec3 eye = viewer->getCamera()->getInverseViewMatrix().getTrans();
				//計算當前攝像機與pick到的模型之間的距離是多少
				osg::Vec3 offset = m_pickPoint - eye;
				int dist = offset.length();
				//計算當前的鼠標屏幕點映射到三維中的值
				osg::Vec3 mouseWorldPos = screenToWorld(viewer,ea.getX(),ea.getY());
				//計算當前鼠標三維點與攝像機的方向
				osg::Vec3 rayDir = mouseWorldPos - eye;
				rayDir.normalize();
				//最後計算物體拖拽時最終的世界位置
				osg::Vec3 curPos = eye + rayDir*dist;
				m_pickObj->setMatrix(osg::Matrix::translate(curPos));
			}

好了,拖拽功能完成,若有不足之處還請指出更正!
下面是演示效果:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章