实现目标:当鼠标向某个方向移动时,视角向其反方向移动,相当于对模型整体进行拖拽的感觉。
示意图:
如图,在屏幕平面上,鼠标从m_1位置移动到m_0位置,两个点坐标的x方向差值为dx,y方向差值为dy
在过相机位置(eye)且垂直于相机于y轴夹角方向向量(图中x-o-y平面紫色的向量)的平面中,要将屏幕上鼠标的移动对应到相机上,在图中鼠标是向屏幕左上方移动的,相机应该向右下方移动到目标位置,为了方便理解,我们先计算相机移动到左上方的目标反方向位置(点p):
假设相机移动步长为move_len, 那么相机z轴方向位移z_len为:move_len·sin(theta)
相机在平行于x-o-y面的移动距离xy_len为move_len·cos(theta)
如上图,在x-o-y面,相当于相机向左平移move_len · cos(theta)
则相机x轴方向平移距离:|move_len · cos(theta) · cos(theta_y)| theta_y为相机视角与y轴夹角
则相机y轴方向平移距离:|move_len·cos(theta)·sin(theta_y)|
那么若将相机移动到图1 p点 其移动可表示为:
eye += osg::Vec3f(-|move_len·cos(theta)·cos(theta_y)|,|move_len·cos(theta)·sin(theta_y)| ,move_len·sin(theta))
将相机移动到目标位置就是移动到点p的反方向:
eye += -osg::Vec3f(-|move_len·cos(theta)·cos(theta_y)|,|move_len·cos(theta)·sin(theta_y)| ,move_len*sin(theta))
附部分代码:
.h中定义两个临时事件指针
osg::ref_ptr< const osgGA::GUIEventAdapter > _ga_t1;//旧事件
osg::ref_ptr< const osgGA::GUIEventAdapter > _ga_t0;//新事件
//保存事件函数:
void addMouseEvent(const osgGA::GUIEventAdapter& ea)
_ga_t1 = _ga_t0;//上次事件
_ga_t0 = &ea;//最新事件
//handle处理按键事件
case osgGA::GUIEventAdapter::PUSH:
if (ea.getButton() == osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON)
addMouseEvent(ea);
return false;
//handle处理拖拽事件
case osgGA::GUIEventAdapter::DRAG:
if (_ga_t0 == NULL)
return false;
unsigned int buttonMask = _ga_t0->getButtonMask();
if(buttonMask == osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON)
addMouseEvent(ea);//添加事件
//计算x y偏移
int delX = _ga_t0->getX() - _ga_t1->getX();
int delY = _ga_t0->getY() - _ga_t1->getY();
//计算sin theta 及 cos theta
int abs_x = abs(delX);
int abs_y = abs(delY);
float sin_theta = abs_y / sqrt(abs_x*abs_x + abs_y * abs_y);
float cos_theta = abs_x / sqrt(abs_x*abs_x + abs_y * abs_y);
int range = 3;灵敏度
osg::Vec3f move(0, 0, node_radius * 0.05);//相机对应移动长度 此处设置为模型包围球半径*0.05
if (delY > 0 && delX >0 && abs_x > range && abs_y > range)
{//鼠标右上移动 视角左下移动
move.x() = -node_radius * 0.05*cos_theta*cosf(m_rotate[2]);//m_rotate[2]是相机与y轴夹角 正负号与该角度相关
move.y() = -node_radius * 0.05*cos_theta*sinf(m_rotate[2]);
move.z() = -move.z()*sin_theta;
m_Position += move;//m_Position为相机位置
else if (delY < 0 && delX < 0 && abs_x > range && abs_y > range)
{//鼠标 左下 视角 右上
move.x() = node_radius * 0.05*cos_theta*cosf(m_rotate[2]);
move.y() = node_radius * 0.05*cos_theta*sinf(m_rotate[2]);
move.z() = move.z()*sin_theta;
m_Position += move;
else if (delY < 0 && delX > 0 && abs_x > range && abs_y > range)
{//鼠标右下 视角 左上
move.x() = -node_radius * 0.05*cosf(m_rotate[2]);
move.y() = -node_radius * 0.05*sinf(m_rotate[2]);
move.z() = move.z()*sin_theta;
m_Position += move;
else if (delY > 0 && delX < 0 && abs_x > range && abs_y > range)
{//鼠标 左上 视角 右下
move.x() = node_radius * 0.05 * cosf(m_rotate[2]);
move.y() = node_radius * 0.05 * sinf(m_rotate[2]);
move.z() = -move.z()*sin_theta;
m_Position += move;
else if (delY > 0 && delX == 0)//abs_x < range)// && abs_y >= range)
{//鼠标向上 视角向下
//move.x() = move_step * 0.3*cosf(m_rotate[2]);
//move.y() = -move_step * 0.3*sinf(m_rotate[2]);
move.z() = -move.z();
m_Position += move;
else if (delY < 0 && delX == 0)// && abs_y >= range)
{//鼠标向下 视角向上
//move.x() = move_step * 0.3*cosf(m_rotate[2]);
//move.y() = -move_step * 0.3*sinf(m_rotate[2]);
//move.z() = -move.z();
m_Position += move;
else if (delX < 0 && delY == 0)// abs_y < range && abs_x >= range)
{//鼠标向左 视角向右移动
move.x() = node_radius * 0.05*cosf(m_rotate[2]);
move.y() = node_radius * 0.05*sinf(m_rotate[2]);
move.z() = 0;
m_Position += move;
else if (delX > 0 && delY == 0) //abs_y < range && abs_x >= range)
{//鼠标向右 视角向左移动
move.x() = -node_radius * 0.05*cosf(m_rotate[2]);
move.y() = -node_radius * 0.05*sinf(m_rotate[2]);
move.z() = 0;
m_Position += move;
break;
实现目标:当鼠标向某个方向移动时,视角向其反方向移动,相当于对模型整体进行拖拽的感觉。示意图:如图,在屏幕平面上,鼠标从m_1位置移动到m_0位置,两个点坐标的x方向差值为dx,y方向差值为dy在过相机位置(eye)且垂直于相机于y轴夹角方向向量(图中x-o-y平面紫色的向量)的平面中,要将屏幕上鼠标的移动对应到相机上,在图中鼠标是向屏幕左上方移动的,相机应该向右下方移动到目标位置,为了方...
点击鼠标实现对模型的移动,旋转功能,需要用到漫游器。在实现的过程中的需要用到osgGA模块的知识,
重写osgGA下的该函数virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us);可以实现对模型的操作。
1、模型的移动:
static Matrixd translate ...
1.创建两个模型,并且把这两个模型放到Group中,并且注册鼠标点击事件处理
void mousePick2() {
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
viewer->addEventHandler(new osgViewer...
首先介绍一下拖拽器:
(1):TabPlaneDragger平面拖拽器:其边、顶点上都有拖拽点,可以进行某个2D平面上的缩放;
(2):TabPlaneTrackballDragger平面轨迹球拖拽器:除了平面拖拽器的功能外,还多了个轨迹球拖拽功能;
(3):TrackballDragger轨迹球拖拽器:即旋转操纵器,没有缩放功能
(4):Transla...
viewer->getEventQueue()->mouseButtonPress(0,0,1);
viewer->getEventQueue()->mouseMotion(10,0);
以上代码模拟了
鼠标左键从窗口(0,0)拖拽到窗口坐标(10,0)
viewer->getEventQueue()->mouseScroll(
osgGA::GUIEventAdapter::SCROLL_DOWN);
以上代码模拟了向上滚动滚轮
移动和缩放以及旋转都是对矩阵进行操作,这些操作如果要叠加直接矩阵相乘就可以了。
下面的示例代码中,加入了四个bignathan,一个是默认加入在最中间,一个向上移2单位,一个是向下移2单位且缩放0.5倍,另一个是向右4单位,缩放0.5且平躺45度。
#include<osgDB\ReadFile>
#include<osgViewer\Viewer>
#includ...
OSG鼠标选择求交
////求交方法一:(用WINDOW坐标值,在相机下求交)
//osg::ref_ptr picker = new osgUtil::LineSegmentIntersector(
// osgUtil::Intersector::WINDOW, ea.getX(), ea.getY());
//osg
之前的一篇博文是有一篇对点选物体进行平移、缩放旋转。那一篇是很简单的调用了OSG中定义的一些dragger,但这些dragger都有坐标轴或者tapbox等在模型上,与我最近要做的事情的需求不同。网上也找了好久,最终还是自己一点一点,参考老师之前写的代码,然后在亲爱的童童师兄的帮助下,实现了这么一个小小的功能。虽然代码写的乱糟糟的。
这里就简单记录一下整个思路吧。
1、构造一个事件处理器,也就
在使用 OpenSceneGraph(简称OSG)库进行模型渲染时,我们可以通过鼠标点击来获取模型的方位角。方位角指的是模型在三维空间中相对于某个参考方向的角度。
要实现此功能,我们首先需要设置鼠标点击的事件,并在事件处理函数中编写相应的代码。当鼠标被点击时,可以通过使用 OSG 库提供的函数来获取点击位置的屏幕坐标。
然后,我们需要将屏幕坐标转换为世界坐标。为此,可以使用 OSG 提供的函数将屏幕坐标转换为射线,然后对射线进行相交测试,从而得到与模型相交的点的世界坐标。
接下来,我们可以使用模型的世界坐标和相机的位置来计算模型的方位角。可以使用 OSG 提供的几何计算函数来进行此计算。根据具体需求,比如计算相对于参考方向的水平角度或者垂直角度,可以选择合适的函数进行计算。
最后,可以根据具体的应用需求将方位角信息进行展示或者进一步应用,比如根据方位角实现模型的自动旋转或者相关约束等功能。
总而言之,使用 OSG 鼠标点击模型方位角的过程包括设置鼠标点击事件、将屏幕坐标转换为世界坐标、计算模型方位角,并根据实际需求进行后续处理。这个过程需要合理利用 OSG 提供的函数和工具,确保模型方位角的准确性和可靠性。