|
楼主 |
发表于 2010-7-30 18:20:15
|
显示全部楼层
我一直在试图使用正交投影的矩阵,来模拟透视的效果——仅仅只是模拟近大远小的效果而已,达到这个效果之后,用来模拟高空坠落的效果,即相机从10公里高空落下来,假设相机镜头始终朝向地面,那么应该可以看到地面逐渐接近,同时地物慢慢变大。这里的地物,其实就是一块贴了纹理的板子而已。
这个过程中,我相机的投影矩阵就是:
const double dblWidth = double(pViewport->width());
const double dblHeight = double(pViewport->height());
pCamera->setProjectionMatrixAsOrtho(-0.5 * dblWidth, 0.5 * dblWidth, -0.5 * dblHeight, 0.5 * dblHeight, -1e6, 1e6);
我的程序里面,做了一个osg:lane平面对象,平面的法线就是Z轴正方向。就是如下代码中的m_NavBasePlane,它就直接代表充当地面的那块板子。
下面是我在这种模式下的漫游器的getInverseMatrix里面的部分代码:
const osg::Vec3 vecCameraDir(0.0, 0.0, -1.0);
const osg::Vec3 ptCameraEye(0.0, 8765.0, 0.0); // 这里的Y值每一帧都会变小一点点
const osg::Vec3 vecUp(0.0, 1.0, 0.0);
osg::Matrixd mtxLookAt;
mtxLookAt.makeLookAt(ptCameraEye, ptCameraEye + vecCameraDir, vecUp);
const float fltCameraHeight = m_NavBasePlane.distance(ptCameraEye); // 相机距离地面还有多远
const float fltFovTheta = osg:egreesToRadians(30.0f * 0.5f); // 模拟透视投影下fov角度为30度的情况
const float fltCameraFovY = fltCameraHeight * tan(fltFovTheta) * 2.0f;
const osg::Viewport *pViewport = m_pCurrentCamera->getViewport();
const float fltCurViewHeight = pViewport->height();
const float fltScale = fltCurViewHeight / fltCameraFovY; // 求出一个模拟的缩放量,相机逐渐接近地面时,fltScale的值肯定会不断变大
const osg::Vec3 vecScaleView(fltScale, fltScale, fltScale);
osg::Matrixd mtxScale;
mtxScale.makeScale(vecScaleView);
return mtxScale * mtxLookAt; // 返回求出来的相机模型视图矩阵
上面的代码能够让我顺利的看到大地逐渐接近的过程中慢慢放大,放大的程度跟30度张角的透视投影基本上一致。
可惜的是,当上面的变量fltCameraHeight逐渐减小到160左右,我的地面(就那块贴了纹理的板子)就消失了。若我此时使用鼠标滚轮倒回来一点点,地面又可见;也就是说,160左右的值,其实是一个临界值了,相机继续往下,则地面会被剪裁掉,若返回来一点点,地面就不会剪裁掉了。
若我此时将相机的投影矩阵使用透视投影,30度张角,然后上面的代码无需计算缩放部分,仅仅需要mtxLookAt即可,则相机足以接近到地面并穿过地面。
事实上,我的程序可以随时切换投影矩阵,对比正交和透视下的效果。我的程序在切换矩阵的时候,视口中可见的地表幅面也一直是差不多的。
整体来说吧,感觉就是我这个情况,正交投影下OSG将在相机接近地面160距离的时候,地面会被剪裁掉。 |
|