OSG以鼠标为中心缩放

针对透视投影和正交投影的两种不同缩放。

我对场景的缩放操作是写在自定义的漫游器中的,重写handle方法来实现

透视投影

透视投影下缩放采用的方式是原有的handleMouseWheel(ea, us)方法,也就是修改_distance的值,因此要以鼠标为中心的话,需要对缩放前后的_distance做记录,并与角度一起计算需要对中心平移的向量,下图是一个计算时画的简图,向后缩放也是类似的:
在这里插入图片描述

以鼠标中心做缩放,eye移动的方向需要沿着与鼠标的方向向量v1,但是因为不打算更改漫游器默认的getInverseMatrix函数,所以为了保证eye看的方向还是朝前,可以移动_center来让视线方向不变,绿色部分就是是需要计算的移动向量,也就是本来eye的位置 eye’ 到 实际eye的位置 eye2 的移动向量,ɵ可以通过v1和eye与模型中心的向量v2的余弦值计算:

			//通过变换矩阵获取屏幕上的鼠标点转换到世界坐标下的三维点
			osg::Camera* camera = m_pViewer->getCamera();
			osg::Matrix mvpw = camera->getViewMatrix() * camera->getProjectionMatrix() * camera->getViewport()->computeWindowMatrix();

			osg::Matrix inverseMVPW = osg::Matrix::inverse(mvpw);
			osg::Vec3 mouseWorld = osg::Vec3(ea.getX(), ea.getY(), 0) * inverseMVPW;

			//获取当前视点到中心的方向向量
			osg::Vec3 eye, center, up;
			camera->getViewMatrixAsLookAt(eye, center, up);
			_direction = center - eye;
			_direction.normalize();

			//获取视点到鼠标点的方向向量
			osg::Vec3 direction = mouseWorld - eye;
			direction.normalize();

			//记录缩放前的_distance
			double old_dis = _distance;

			//默认缩放操作
			handleMouseWheel(ea, us);

			//记录缩放后的_disance
			double new_dis = _distance;
			if (new_dis == old_dis)
			{
				return false;
			}

			//因为是单位向量,所以余弦值等于两向量的点积
			double res_dot = direction.x() * _direction.x() +
				direction.y() * _direction.y() +
				direction.z() * _direction.z();

			//两次_distance之差
			double d = old_dis - new_dis;
			//沿鼠标点方向移动的距离
			double diff = (old_dis - new_dis) / res_dot;
			//沿鼠标点方向移动后的点
			osg::Vec3 new_eye = eye + osg::Vec3(direction.x() * diff, direction.y() * diff, direction.z() * diff);
			//沿中心方向移动后的点
			osg::Vec3 s = eye + osg::Vec3(_direction.x() * d, _direction.y() * d, _direction.z() * d);
			//位移向量
			osg::Vec3 pan = new_eye - s;
			//对_center做位移变换
			_center += pan * osg::Matrix::inverse(m_rotationMat);

m_rotationMat是我自定义的旋转矩阵,是做别的事情时定义的,没有需要替换为默认的_rotation就行。

正交投影

正交投影下采用的方式是用 setProjectionMatrixAsOrtho 修改投影矩阵,修改后的投影矩阵不同会造成两次鼠标点转换到世界坐标中的点不同,这里的差异就是需要位移的部分:

			osg::Vec3 ptWorldBefore, ptWorldAfter;
			osg::Camera* camera = m_pViewer->getCamera();
			//计算缩放前的变换矩阵
			{
				osg::Matrix mvpw = camera->getViewMatrix() * camera->getProjectionMatrix() * camera->getViewport()->computeWindowMatrix();
				osg::Matrix inverseMVPW = osg::Matrix::inverse(mvpw);
				ptWorldBefore = osg::Vec3(ea.getX(), ea.getY(), 0) * inverseMVPW;
			}

			double dFactor = 1.0;
			osgGA::GUIEventAdapter::ScrollingMotion sm = ea.getScrollingMotion();
			if (sm == osgGA::GUIEventAdapter::SCROLL_UP)
			{
				dFactor = 1.2;
			}
			else if (sm == osgGA::GUIEventAdapter::SCROLL_DOWN)
			{
				dFactor = 0.8;
			}

			double dL, dR, dT, dB, dZ, dF;
			camera->getProjectionMatrixAsOrtho(dL, dR, dB, dT, dZ, dF);
			double width, height;

			width = dR - dL;
			height = dT - dB;

			dR = width * dFactor;
			dT = height * dFactor;
			//这里就完成了缩放
			camera->setProjectionMatrixAsOrtho(-dR * 0.5, dR * 0.5, -dT * 0.5, dT * 0.5, dZ, dF);

			//计算缩放后的变换矩阵
			{
				osg::Matrix mvpw = camera->getViewMatrix() * camera->getProjectionMatrix() * camera->getViewport()->computeWindowMatrix();
				osg::Matrix inverseMVPW = osg::Matrix::inverse(mvpw);
				ptWorldAfter = osg::Vec3(ea.getX(), ea.getY(), 0) * inverseMVPW;
			}
			osg::Vec3 vecMove = ptWorldBefore - ptWorldAfter;

			//平移_center
			_center += vecMove * osg::Matrix::inverse(m_rotationMat);
### 实现 OSG 中的鼠标缩放功能 在 OpenSceneGraph (OSG) 应用程序中实现鼠标缩放功能通常涉及处理鼠标的滚轮事件或者通过拖拽动作来改变相机的位置或焦距。下面是一个基于 C++ 的简单示例,展示了如何捕捉鼠标滚动事件并据此调整摄像机的距离。 #### 处理鼠标滚轮事件以实现缩放效果 为了响应用户的输入,在 `Viewer` 或者自定义的手势处理器类里重载相应的回调函数可以捕获这些事件: ```cpp #include <osgGA/GUIEventHandler> #include <osg/MatrixTransform> class MouseWheelZoomHandler : public osgGA::GUIEventHandler { public: bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter&) override { if(ea.getEventType() == osgGA::GUIEventAdapter::SCROLL){ float delta = ea.getScrollingMotion() == osgGA::GUIEventAdapter::SCROLL_UP ? 0.1f : -0.1f; // 获取当前视图矩阵,并对其进行平移变换模拟放大缩小的效果 osg::ref_ptr<osg::Camera> camera = dynamic_cast<osg::Camera*>(ea.getWindow()); if(camera.valid()){ osg::Vec3d eye, center, up; camera->getViewMatrixAsLookAt(eye, center, up); // 计算新的眼睛位置 osg::Vec3d direction = center - eye; direction.normalize(); eye += direction * delta; // 更新查看矩阵 camera->setViewMatrixAsLookAt(eye, center, up); } return true; // 表明已经处理了此事件 } return false; // 对其他类型的事件不做任何处理 } }; ``` 上述代码片段实现了基本的鼠标滚轮缩放逻辑[^1]。每当检测到用户滚动鼠标滚轮时,就会相应地增加或减少观察点与目标之间的距离,从而达到视觉上的放大和缩小效果。 另外一种常见的做法是在双击或其他特定手势下进入交互模式,允许用户按住某个键的同时移动鼠标来进行连续性的缩放操作。这可以通过监听键盘组合按键以及持续跟踪鼠标的位移变化来完成。 对于更复杂的场景管理需求,比如支持多点触控设备上的捏合手势等高级特性,则可能需要用到第三方库或是深入研究 OSG 提供的相关接口。 #### 关联问题探讨
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值