osg透视投影与正交投影的切换

本文探讨如何在OSG中实现切换相机投影模式(透视到正交)时保持等距转换,解决因初始透视投影矩阵设置导致的问题,涉及计算与调整参数以适应不同场景需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主要是希望在切换的时候保持等距的转换,即使在发生缩放后。
首先osg中有获取与设置投影矩阵的方法,因此简单的转换如下:

	case osgGA::GUIEventAdapter::DOUBLECLICK:
	{
		if (m_isPerspective)
		{
			double left,right,bottom,top,zNear, zFar;
			m_pViewer->getCamera()->getProjectionMatrixAsFrustum(left, right, bottom, top, zNear, zFar);
			m_pViewer->getCamera()->setProjectionMatrixAsOrtho(left, right, bottom, top, zNear, zFar);
		}
		else
		{
			double left, right, bottom, top, zNear, zFar;
			m_pViewer->getCamera()->getProjectionMatrixAsOrtho(left, right, bottom, top, zNear, zFar);
			m_pViewer->getCamera()->setProjectionMatrixAsFrustum(left, right, bottom, top, zNear, zFar);
		}
		m_isPerspective = !m_isPerspective;
	}
	return false;

这部分写在了自定义的漫游器的handle方法中,在写demo测试的时候呈现的效果已经是等距的了,但是放到实际项目中却不行,发现实际项目中在创建camera的时候初始化了透视投影矩阵:

setProjectionMatrixAsPerspective(30.0f, double(traits->width) / double(traits->height), 1.0f, 1000.0f);

然后感觉 转换效果和 近平面与_distance的比值 有关 :
在这里插入图片描述
初始化时的近平面设置为了1.0,因此比值刚好是_distance,修改后的切换如下:

if (m_isPerspective)
	{
		m_pViewer->getCamera()->getProjectionMatrixAsFrustum(m_left, m_right, m_bottom, m_top, m_zNear, m_zFar);
		double v = _distance / m_zNear;
		m_pViewer->getCamera()->setProjectionMatrixAsOrtho(m_left * v, m_right * v, m_bottom * v, m_top * v, m_zNear, m_zFar);
	}
	else
	{
		double left, right, bottom, top, zNear, zFar;
		m_pViewer->getCamera()->getProjectionMatrixAsOrtho(left, right, bottom, top, zNear, zFar);
		double distance = left / m_left * zNear;
		m_pViewer->getCamera()->setProjectionMatrixAsFrustum(m_left, m_right, m_bottom, m_top, m_zNear, m_zFar);
		_distance = distance;
	}
	m_isPerspective = !m_isPerspective;

正交投影下的缩放我是通过修改投影矩阵的方式,没有去修改_distance,因此切换到透视投影的时候需要计算_distance并设置。

### OSG正交投影调整视角以实现CAD风格 为了使OSG正交投影更接近于CAD风格,可以通过以下方式调整视角参数: #### 1. 设置正交投影矩阵 在OSG中,可以使用`setProjectionMatrixAsOrtho`函数来设置正交投影矩阵。该函数允许指定视口边界以及近裁剪面和远裁剪面的位置[^1]。 ```cpp #include <osg/Camera> #include <osg/Matrix> // 定义正交投影参数 double left = -10.0; double right = 10.0; double bottom = -10.0; double top = 10.0; double nearPlane = 1.0; // 近裁剪面距离 double farPlane = 100.0; // 远裁剪面距离 // 创建相机并设置正交投影 osg::ref_ptr<osg::Camera> camera = new osg::Camera(); camera->setProjectionMatrix(osg::Matrix::ortho2D(left, right, bottom, top)); camera->setProjectionMatrix(osg::Matrix::ortho(left, right, bottom, top, nearPlane, farPlane)); ``` 此代码片段设置了正交投影矩阵,并指定了视口边界的范围以及裁剪平面的距离。这些参数可以根据实际需求进行调整,以便更好地匹配CAD样式[^3]。 #### 2. 平移缩放变换 为了让场景更加贴近CAD的视觉效果,通常需要执行两步操作: - **平移变换**:将视域体的中心点移动到坐标原点。 - **缩放变换**:通过非均匀缩放将长方体视域体转换为标准化立方体,从而确保所有物体的比例保持一致[^1]。 可以在OSG中通过矩阵运算实现这两种变换: ```cpp // 计算平移量 double centerX = (left + right) / 2.0; double centerY = (bottom + top) / 2.0; // 构造平移矩阵 osg::Matrix translateMatrix = osg::Matrix::translate(-centerX, -centerY, -(nearPlane + farPlane) / 2); // 缩放因子计算 double scaleX = 2.0 / (right - left); double scaleY = 2.0 / (top - bottom); double scaleZ = 2.0 / (farPlane - nearPlane); // 构造缩放矩阵 osg::Matrix scaleMatrix = osg::Matrix::scale(scaleX, scaleY, scaleZ); // 应用变换 camera->setViewMatrix(translateMatrix * scaleMatrix); ``` 这段代码实现了从原始视域体到规范化立方体的映射过程,这是正交投影的核心步骤之一。 #### 3. 鼠标滚轮控制缩放 为了模仿CAD中的交互行为,可以利用鼠标滚轮事件动态调整正交投影的尺寸。具体来说,可以通过更改`left`, `right`, `bottom`, 和 `top` 参数来实现放大或缩小的效果[^2]。 ```cpp void handleWheelEvent(int delta, double& left, double& right, double& bottom, double& top) { double zoomFactor = 0.1; // 放大倍率 if (delta > 0) { // 向前滚动 left *= (1 + zoomFactor); right *= (1 + zoomFactor); bottom *= (1 + zoomFactor); top *= (1 + zoomFactor); } else { // 向后滚动 left /= (1 + zoomFactor); right /= (1 + zoomFactor); bottom /= (1 + zoomFactor); top /= (1 + zoomFactor); } } ``` 每次触发鼠标滚轮事件时调用上述函数即可更新正交投影的边界值。 --- ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值