在osg里自己实现操作器,目标是实现绕某中心点旋转,能够支持平移视图,缩放视图。
现在记录一下缩放视图的实现方法。
首先操作器是从osg标准操作器osgGA::StandardManipulator继承下来的。然后透视方式是采用的平行投影。放大缩小视图就是修改投影矩阵的窗口大小,如果投影矩阵窗口很大,就相当与在很大的窗口来看,效果就是缩小视图,相反就是放大视图。在缩小放大视图的过程里,想让视图往当前鼠标位置上去放大和缩小,即鼠标在那里就去放大那里。
这个的实现方式就是在改变投影矩阵前计算一些当前鼠标位置对应的世界坐标值,在修改投影矩阵后又计算一下当前鼠标位置对应世界坐标值,这个时候,要做的就是平移视图,使得当前鼠标位置对应的还是修改投影矩阵前的位置就可以了。
下面给出关键函数代码。
void CMyMainpulator::zoomModel(const osgGA::GUIEventAdapter& ea, bool bUp )
{
osg::Vec3 ptWorldBefore, ptWorldAfter; // 修改投影矩阵前后鼠标位置对应的世界坐标点
float x1 = ea.getX(), y1 = ea.getY();
osg::Vec3 vecWindow1(x1, y1, 0.0);
{
// 计算修改投影矩阵前
// 获取当前运算矩阵
osg::Matrix VPW = m_pCamera->getViewMatrix() *
m_pCamera->getProjectionMatrix() *
(m_pCamera->getViewport())->computeWindowMatrix();
osg::Matrix inverseVPW;
inverseVPW.invert(VPW);
// 矩阵运算获得世界坐标
ptWorldBefore = vecWindow1 * inverseVPW;
}
double dFactor = 1;
if (bUp)
{
dFactor = 1.2;
}
else
{
dFactor = 0.8;
}
double dL, dR, dT, dB, dZ, dF;
m_pCamera->getProjectionMatrixAsOrtho(dL, dR, dB, dT, dZ, dF);
double width ,height ;
width = dR - dL;
height = dT - dB;
dR = width * dFactor;
dT = height * dFactor;
m_pCamera->setProjectionMatrixAsOrtho(-dR * 0.5, dR * 0.5, -dT * 0.5, dT * 0.5, dZ, dF);
{
// 计算修改投影矩阵后
// 获取当前运算矩阵
osg::Matrix VPW = m_pCamera->getViewMatrix() *
m_pCamera->getProjectionMatrix() *
(m_pCamera->getViewport())->computeWindowMatrix();
osg::Matrix inverseVPW;
inverseVPW.invert(VPW);
// 矩阵运算获得世界坐标
ptWorldAfter = vecWindow1 * inverseVPW;
}
osg::Vec3 vecMove = ptWorldBefore - ptWorldAfter;
panModel(vecMove.x(), vecMove.y(), vecMove.z());
}