OSG鼠標選擇求交
////求交方法一:(用WINDOW座標值,在相機下求交)
//osg::ref_ptr< osgUtil::LineSegmentIntersector > picker = new osgUtil::LineSegmentIntersector(
// osgUtil::Intersector::WINDOW, ea.getX(), ea.getY());
//osgUtil::IntersectionVisitor iv( picker.get());
//cameraMaster->accept( iv);//(從相機往下遍歷)
//求交方法二:(直接用view求交)
//view->computeIntersections( x, y, intersections);
//求交方法三:(用世界座標值,既可在某個節點node下求交,也可在相機下求交。但需注意,在某個節點node下求交時,需要把該node的有矩陣變換的父節點都用上,比如根節點->MT節點->cow模型節點,則可用MT節點->accept( iv)或根節點->accept( iv)。求交時是根據執行accept( iv)的節點向下遍歷,求出節點的真實世界座標。而如果用cow->accept( iv) ,則會忽略父節點的MT節點,導致求不出真正的世界座標值,這樣求交會產生錯誤)
osg::ref_ptr< osgUtil::LineSegmentIntersector > picker =new osgUtil::LineSegmentIntersector(
nearPoint, farPoint);//線段(真實的世界座標)
osgUtil::IntersectionVisitor iv( picker.get());
g_grpMouse->getParent( 0)->getChild( 0)->asGroup()->getChild( 0)->accept( iv);//模型求交
//求最前交點 方法一:
if (picker->containsIntersections())
{ //獲取最前的交點。
osg::Vec3 ptWorldIntersectPointFirst= picker->getFirstIntersection().getWorldIntersectPoint();
cout<<"world coords vertex("<< ptWorldIntersectPointFirst.x()<<","
<< ptWorldIntersectPointFirst.y()<< ","<< ptWorldIntersectPointFirst.z()<<")"<< std::endl;
}
/*下面方法也可以計算求出最前的交點:*/
//求最前交點 方法二:
/*double dLen2Shortest= DBL_MAX, dLenTmp; osgUtil::LineSegmentIntersector::Intersections::iterator hitrShortest;
osgUtil::LineSegmentIntersector::Intersections intersections= picker->getIntersections();
for( osgUtil::LineSegmentIntersector::Intersections::iterator hitr = intersections.begin();
hitr != intersections.end();
++hitr)
{
//求離視點最近的點,即鼠標選擇的最前面的點
dLenTmp= ( ptEye.x()- hitr->getWorldIntersectPoint().x())*
( ptEye.x()- hitr->getWorldIntersectPoint().x())+
( ptEye.y()- hitr->getWorldIntersectPoint().y())*
( ptEye.y()- hitr->getWorldIntersectPoint().y())+
( ptEye.z()- hitr->getWorldIntersectPoint().z())*
( ptEye.z()- hitr->getWorldIntersectPoint().z());
if ( dLen2Shortest> dLenTmp)
{
dLen2Shortest= dLenTmp;
hitrShortest= hitr;
}
}
其中ptEye爲視點的世界座標值:
osg::Matrix _inverseMV;
_inverseMV.invert( cameraMaster->getViewMatrix());
osg::Vec3 ptEye= osg::Vec3( 0, 0, 0) * _inverseMV;
*/
參考代碼如下:
/*OSG中的HUD實時顯示視點座標*/
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osg/Geode>
#include <osg/Depth>
#include <osg/CameraNode>
#include <osgText/Text>
#include <osgGA/TrackballManipulator>
#include <osg/LineWidth>
#include <osg/Point>
#include <osg/ShapeDrawable>
#include <osg/MatrixTransform>
#include <iostream>
#include <sstream>
#pragma comment( lib, "osgd.lib"); //.在Debug版本下的庫名都加d,如"osgd.lib"
#pragma comment( lib, "osgDBd.lib")
#pragma comment( lib, "osgViewerd.lib");
#pragma comment( lib, "osgTextd.lib");
#pragma comment( lib, "osgGAd.lib");
#pragma comment( lib, "osgUtild.lib");
osg::ref_ptr<osg::Group> g_grpMouse;
using namespace std;
//事件類
class CHUD_viewPoint: public osgGA::GUIEventHandler
{
public:
/**構造函數*/
CHUD_viewPoint(osgText::Text* updateText):
m_text(updateText) {}
~CHUD_viewPoint(){}
virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa);
void UpdateText(osgViewer::Viewer* viewer,const osgGA::GUIEventAdapter&);
/**LABEL*/
void setLabel(const std::string& name)
{
if ( m_text.get())
{
m_text->setText(name);
}
}
protected:
osg::Vec2 m_vPosWindowMouse;//鼠標單擊處的窗口座標
osg::ref_ptr<osgText::Text> m_text;//視點信息,會動態改變
};
bool CHUD_viewPoint::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa)
{
switch(ea.getEventType())
{
//case(osgGA::GUIEventAdapter::FRAME):
// {
// osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
// if (viewer)
// {
// osg::Vec3 vCenter, vUp;
// viewer->getCamera()->getViewMatrixAsLookAt( m_vPosEye, vCenter, vUp);//獲取視點信息
// UpdateText( viewer, ea);//更新文字信息
// }
// return true;
// }
case( osgGA::GUIEventAdapter::PUSH):
{
m_vPosWindowMouse.set( ea.getX(), ea.getY());//鼠標單擊處的窗口座標
osgViewer::Viewer* viewer = dynamic_cast< osgViewer::Viewer*>( &aa);
if (viewer)
{
UpdateText( viewer, ea);//更新文字信息
//主相機
osg::ref_ptr<osg::Camera> cameraMaster = viewer->getCamera();
osg::Matrix mvpw = cameraMaster->getViewMatrix() * cameraMaster->getProjectionMatrix();
if ( cameraMaster->getViewport()) mvpw.postMult( cameraMaster->getViewport()->computeWindowMatrix());
osg::Matrix _inverseMVPW;
_inverseMVPW.invert( mvpw);
osg::Vec3d nearPoint = osg::Vec3d( ea.getX(), ea.getY(), 0.0)* _inverseMVPW;//透視投影中Znear平面的交點
osg::Vec3d farPoint = osg::Vec3d( ea.getX(), ea.getY(), 1.0)* _inverseMVPW;//透視投影中Zfar平面的交點
osg::Vec3 vPosEye, vCenter, vUp;
cameraMaster->getViewMatrixAsLookAt( vPosEye, vCenter, vUp);//獲取視點信息
osg::Matrix _inverseMV;
_inverseMV.invert( cameraMaster->getViewMatrix());
osg::Vec3 ptEye= osg::Vec3( 0, 0, 0) * _inverseMV;//獲取視點座標
osg::Vec3d deltaEye= ptEye- vPosEye;
if ( deltaEye.length()< 1e-8)
{
cout<< "yes,eye\n";
}
else
{
cout<< "no,eye\n";
}
osg::Vec3d dir1= farPoint- nearPoint;
dir1.normalize();
osg::Vec3d dir2= farPoint- vPosEye;
dir2.normalize();
osg::Vec3d delta= dir1- dir2;
//看視點、Znear平面的交點、Zfar平面的交點是否在同一直線上。經驗證,確定在同一直線上
if ( delta.length()< 1e-8)
{
cout<< "yes,line\n";
}
else
{
cout<< "no,line\n";
}
osg::Geode* geode= new osg::Geode();
osg::Geometry* pyramidGeometry = new osg::Geometry();
geode->addDrawable( pyramidGeometry);
osg::Vec3Array* pyramidVertices = new osg::Vec3Array;
pyramidVertices->push_back( nearPoint);
pyramidVertices->push_back( farPoint);
pyramidGeometry->setVertexArray( pyramidVertices );
//顏色
osg::Vec4Array* colors = new osg::Vec4Array;
colors->push_back( osg::Vec4( 1.0f, 0.0f, 0.0f, 1.0f) );//紅色
pyramidGeometry->setColorArray( colors);
pyramidGeometry->setColorBinding( osg::Geometry::BIND_OVERALL);
//紅點表示透視投影中Znear平面的交點
pyramidGeometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::POINTS, 0, 1/*3*/));
//紅線表示鼠標點擊的線,其起點爲Znear平面交點,終點爲Zfar平面交點。
pyramidGeometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINES, 0, 2));/**/
////設置線寬
//osg::ref_ptr <osg::LineWidth> LineSize = new osg::LineWidth;
//LineSize ->setWidth( 12.0) ;
//geode->getOrCreateStateSet()->setAttributeAndModes( LineSize.get (),osg::StateAttribute::ON);
//設置點大小
osg::ref_ptr <osg::Point> ptSize = new osg::Point;
ptSize->setSize( 12.0) ;
geode->getOrCreateStateSet()->setAttributeAndModes( ptSize.get (),osg::StateAttribute::ON);
/*當只有一個點時,包圍球半徑爲,所以可能看不到這個點,故需要重新設置包圍球大小,可把包圍球半徑設大點。
如對glider、cow等小模型,半徑取.1可以,對fountain.osg則.1太小。爲統一,可大些,如*/
osg::Vec3d ptCnt= geode->getBound().center();
double dRadius= geode->getBound().radius();
//重新設置包圍球的半徑(可調用setInitialBound())
osg::BoundingSphere bs( ptCnt, 100);
geode->setInitialBound( bs);
g_grpMouse->removeChildren( 0, g_grpMouse->getNumChildren());
g_grpMouse->addChild( geode);
//獲取從根節點到當前節點的路徑向量
osg::NodePathList parentNodePaths = geode->getParentalNodePaths();
if ( !parentNodePaths.empty())
{
osg::Matrixd mt= computeWorldToLocal( parentNodePaths[ 0]);
}
////求交
//osg::ref_ptr< osgUtil::LineSegmentIntersector > picker = new osgUtil::LineSegmentIntersector(
// osgUtil::Intersector::WINDOW, ea.getX(), ea.getY());
//osgUtil::IntersectionVisitor iv( picker.get());
////g_grpMouse->getParent( 0)->getChild( 0)->accept( iv);//模型求交
//cameraMaster->accept( iv);//模型求交(從相機往下遍歷)
//求交
osg::ref_ptr< osgUtil::LineSegmentIntersector > picker =new osgUtil::LineSegmentIntersector(
nearPoint, farPoint);//線段(真實的世界座標)
osgUtil::IntersectionVisitor iv( picker.get());
//g_grpMouse->getParent( 0)->getChild( 0)->accept( iv);//模型求交/**/
g_grpMouse->getParent( 0)->getChild( 0)->/*asGroup()->getChild( 0)->*/accept( iv);//模型求交/**/
// 根節點 cow的MT節點
//cameraMaster->accept( iv);//模型求交(從相機往下遍歷)
//if (picker->containsIntersections())
//{
// double dLen2Shortest= DBL_MAX, dLenTmp;
// osgUtil::LineSegmentIntersector::Intersections::iterator hitrShortest;
// osgUtil::LineSegmentIntersector::Intersections intersections= picker->getIntersections();
// for( osgUtil::LineSegmentIntersector::Intersections::iterator hitr = intersections.begin();
// hitr != intersections.end();
// ++hitr)
// {
// //求離視點最近的點,即鼠標選擇的最前面的點
// dLenTmp= ( ptEye.x()- hitr->getWorldIntersectPoint().x())*
// ( ptEye.x()- hitr->getWorldIntersectPoint().x())+
// ( ptEye.y()- hitr->getWorldIntersectPoint().y())*
// ( ptEye.y()- hitr->getWorldIntersectPoint().y())+
// ( ptEye.z()- hitr->getWorldIntersectPoint().z())*
// ( ptEye.z()- hitr->getWorldIntersectPoint().z());
// if ( dLen2Shortest> dLenTmp)
// {
// dLen2Shortest= dLenTmp;
// hitrShortest= hitr;
// }
// }
//
// //輸出
// if ( dLen2Shortest != DBL_MAX)
// {
// cout<<"world coords vertex("<< hitrShortest->getWorldIntersectPoint().x()<<","
// << hitrShortest->getWorldIntersectPoint().y()<<","
// << hitrShortest->getWorldIntersectPoint().z()<<")"<<std::endl;
// //高亮此點
// double dPointRadius= 15.0f;
// osg::ShapeDrawable* pShd= new osg::ShapeDrawable(
// new osg::Sphere( hitrShortest->getWorldIntersectPoint(), dPointRadius));//繪製交點的球
// pShd->setColor( osg::Vec4( 0, 1, 0, 1));
// geode->addDrawable( pShd);
//
// }
//}
if (picker->containsIntersections())
{
osg::Vec3 ptWorldIntersectPointFirst= picker->getFirstIntersection().getWorldIntersectPoint();
cout<<"world coords vertex("<< ptWorldIntersectPointFirst.x()<<","
<< ptWorldIntersectPointFirst.y()<< ","<< ptWorldIntersectPointFirst.z()<<")"<< std::endl;
//高亮此點
double dPointRadius= 15.0f;
osg::ShapeDrawable* pShd= new osg::ShapeDrawable(
new osg::Sphere( ptWorldIntersectPointFirst, dPointRadius));
pShd->setColor( osg::Vec4( 0, 1, 0, 1));
geode->addDrawable( pShd);
}
}
return true;
}
default:
return false;
}
}
void CHUD_viewPoint::UpdateText(osgViewer::Viewer* viewer,const osgGA::GUIEventAdapter&)
{
std::string gdlist="";
std::ostringstream os;
os<<"MousePos(X: "<< m_vPosWindowMouse.x()<<",Y: "<< m_vPosWindowMouse.y()<<")";//座標
gdlist = os.str();
setLabel(gdlist);
}
osg::Node* createHUD_viewPoint( osgText::Text* text)
{
//設置字體
std::string font("fonts/arial.TTF");//此處設置的是漢字字體 "fonts/STCAIYUN.TTF"
text->setFont( font);
//設置文字顯示的位置(左下爲(0,0),X正向朝右,Y正向朝上)
osg::Vec3 position( 100.0f, 10.0f,0.0f);
text->setPosition(position);
text->setColor( osg::Vec4( 1, 1, 0, 1));
text->setText(L"");//設置顯示的文字
text->setCharacterSize(15);
text->setDataVariance(osg::Object::DYNAMIC);//一定要設置字體爲動態,否則程序會卡住,死在那裏。(參照osgcatch)
//幾何體節點
osg::Geode* geode = new osg::Geode();
geode->addDrawable( text );//將文字Text作這drawable加入到Geode節點中
//設置狀態
osg::StateSet* stateset = geode->getOrCreateStateSet();
stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);//關閉燈光
stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);//關閉深度測試
//打開GL_BLEND混合模式(以保證Alpha紋理正確)
stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
//相機
osg::Camera* camera = new osg::Camera;
//設置透視矩陣
camera->setProjectionMatrix(osg::Matrix::ortho2D(0,600,0,600));//正交投影
//設置絕對參考座標系,確保視圖矩陣不會被上級節點的變換矩陣影響
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
//視圖矩陣爲默認的
camera->setViewMatrix(osg::Matrix::identity());
//設置背景爲透明,否則的話可以設置ClearColor
camera->setClearMask(GL_DEPTH_BUFFER_BIT);
camera->setAllowEventFocus( false);//不響應事件,始終得不到焦點
//設置渲染順序,必須在最後渲染
camera->setRenderOrder(osg::CameraNode::POST_RENDER);
camera->addChild(geode);//將要顯示的Geode節點加入到相機
return camera;
};
int main( int argc, char **argv )
{
osgViewer::Viewer viewer;
osg::ref_ptr< osg::Node> model = osgDB::readNodeFile("fountain.osg");// glider nathan
osg::Matrix m;
m.setTrans( 200, 0, 0);
osg::ref_ptr< osg::MatrixTransform> pmt= new osg::MatrixTransform();
pmt->setMatrix( m);
pmt->addChild( model.get());
osg::ref_ptr<osg::Group> root= new osg::Group;
//root->addChild( model.get());//加入某個模型
root->addChild( pmt.get());//加入某個模型
osgText::Text* text = new osgText::Text;
root->addChild( createHUD_viewPoint( text));//加入HUD文字
osg::ref_ptr< CHUD_viewPoint> pHUD= new CHUD_viewPoint( text);
viewer.addEventHandler( pHUD.get());
//GraphicsContext設備上下文關鍵參數
osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits ;
traits->x = 200;
traits->y = 200;
traits->width = 600;
traits->height = 600;
traits->windowDecoration = true;
traits->doubleBuffer = true;
traits->sharedContext = 0;
osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
//gc->setClearColor( osg::Vec4f( 0.2f,0.2f,0.2f,1.0f));
gc->setClearColor( osg::Vec4f( 0.0f, 1.0f, 0.0f, 1.0f)); //設置整個windows窗口顏色
gc->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//主相機
osg::ref_ptr<osg::Camera> cameraMaster = viewer.getCamera();
cameraMaster->setGraphicsContext(gc.get());//設置GraphicsContext設備上下文
//相機視口設置
cameraMaster->setViewport(new osg::Viewport( 100, 100, traits->width, traits->height));/**/
g_grpMouse= new osg::Group();
//設置狀態
osg::StateSet* stateset = g_grpMouse->getOrCreateStateSet();
stateset->setMode( GL_LIGHTING,osg::StateAttribute::OFF);//關閉燈光
//stateset->setMode( GL_DEPTH_TEST,osg::StateAttribute::OFF);//關閉深度測試
root->addChild( g_grpMouse.get());
//viewer.setUpViewInWindow( 0, 0, 600, 600);//設置窗口大小
viewer.setSceneData( root.get());
viewer.realize();
viewer.run() ;
return 0;
}