鼠标单击点在世界坐标系中的射线 计算原理
来源:互联网 发布:app软件著作权范本 编辑:程序博客网 时间:2024/04/28 06:31
鼠标单击点在世界坐标系中的射线 计算原理
参考osgManipulator/Dragger.cpp:
求鼠标单击射线在世界坐标系中Znear、Zfar的交点:
bool PointerInfo::projectWindowXYIntoObject(const osg::Vec2d& windowCoord, osg::Vec3d& nearPoint, osg::Vec3d& farPoint)const
{ nearPoint = osg::Vec3d(windowCoord.x(),windowCoord.y(),0.0)*_inverseMVPW;
farPoint = osg::Vec3d(windowCoord.x(),windowCoord.y(),1.0)*_inverseMVPW;
return true;
}
窗口坐标值(winx,winy,深度值)=世界坐标点 * 视图矩阵 *投影矩阵 * 视口矩阵=V世界 * VM * PM * WM。故V世界=(winx,winy,深度值)* (VM * PM * WM)的逆
Znear对应的深度值为0,Zfar对应的深度值为1,故:
Znear对应点坐标为(winx,winy,0)* (VM * PM * WM)的逆,
Zfar对应点坐标为(winx,winy,1)* (VM * PM * WM)的逆。
获取(VM * PM * WM)的逆的代码如下:
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中的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 <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");
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::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";
}
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);
}
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::ref_ptr<osg::Group> root= new osg::Group;
root->addChild( model.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;
}
- 鼠标单击点在世界坐标系中的射线 计算原理
- 在SceneControl中通过鼠标单击获得三维射线、产生三维的点
- opengl 获取鼠标在世界坐标系中的坐标
- 空间射线在普吕克坐标系中的表示
- 解决Unity鼠标坐标点转成世界坐标系坐标点
- 射线检测,单击鼠标是否单击到一个物体上
- 计算脸部部位在坐标系中的位置
- 获取鼠标在世界中的位置
- Unity射线检测的方向是 世界坐标系还是自身坐标系
- 如何通过旋转坐标轴计算坐标系A中的点到坐标系B中的点的变换T
- 世界坐标系与像素坐标系的点互相转换
- 计算机视觉:相机成像原理:世界坐标系、相机坐标系、图像坐标系、像素坐标系之间的转换
- 计算机视觉:相机成像原理:世界坐标系、相机坐标系、图像坐标系、像素坐标系之间的转换
- 计算机视觉:相机成像原理:世界坐标系、相机坐标系、图像坐标系、像素坐标系之间的转换
- 计算机视觉:相机成像原理:世界坐标系、相机坐标系、图像坐标系、像素坐标系之间的转换
- 计算机视觉:相机成像原理:世界坐标系、相机坐标系、图像坐标系、像素坐标系之间的转换
- 使用射线法判断echarts上地图中的点是否在地图范围中
- flash中的世界坐标系和stage3D坐标系的关系
- C语言入门教程 (十七) 指针函数和函数指针
- ruby线程控制,线程同步
- 如何学习C语言(4)-----讲座稿
- C语言入门教程 (十八) 结构体
- Notification使用详解之四:由后台服务向Activity发送进度信息
- 鼠标单击点在世界坐标系中的射线 计算原理
- Hadoop重启需要格式化的问题
- RHEL5笔记(以前的)
- 进程间通信
- 线程
- C语言入门教程 (十九) 联合和枚举
- 网络编程
- 产生随机数之srandom()与random()的应用
- ARM伪指令