OSG坐标问题

来源:互联网 发布:淘宝商城女打底衫 编辑:程序博客网 时间:2024/06/07 10:02
v->push_back( osg::Vec3( -1.f, 0.f, -1.f ) );
v->push_back( osg::Vec3( 1.f, 0.f, -1.f ) );
v->push_back( osg::Vec3( 1.f, 0.f, 1.f ) );
v->push_back( osg::Vec3( -1.f, 0.f, 1.f ) );
这是一个快速入门上面第一个例子的部分代码,将其中的顶点坐标取值和OpenGL中的相应顶点取值比较可以猜测OSG的
坐标系统是X向右,Y向屏幕外,Z向上,也就是说OSG的坐标系统与OpenGL中的Y,Z互换了,不知道是不是这样的,我问一些网友说是这样的,但是我始终找不到官方的资料说这坐标问题,所以很疑惑。
今天看快速入门最后一章一个例子时又产生了疑惑,代码如下
osgViewer::Viewer viewer;
viewer.setSceneData( osgDB::readNodeFile( "cow.osg" ) );
viewer.getCamera()->setProjectionMatrixAsPerspective( 40., 1., 1., 100. );
// 创建矩阵,指定到视点的距离。
osg::Matrix trans;
trans.makeTranslate( 0., 0., -12. );
// 旋转一定角度(弧度值)。
double angle( 0. );
while (!viewer.done())
{
  // 创建旋转矩阵。
  osg::Matrix rot;
  rot.makeRotate( angle, osg::Vec3( 1., 0., 0. ) );
  angle += 0.01;
  // 设置视口矩阵(旋转矩阵和平移矩阵连乘)。
  viewer.getCamera()->setViewMatrix( rot * trans );
  // 绘制下一帧
  viewer.frame();
}
这里感到疑惑之一是trans.makeTranslate( 0., 0., -12. );
为什么这里改变Z的坐标,那么按照我上面的OSG坐标来说的话,这里是将相机向下移动了12个单位吧,为什么不是改变Y的坐标呢,难道视点不是指向Y的吗?
rot.makeRotate( angle, osg::Vec3( 1., 0., 0. ) );
这里也是,当我改为rot.makeRotate( angle, osg::Vec3( 0.,1., 0. ) );时牛不是沿Y旋转而是沿Z旋转
所以我现在得出的结论是写顶点坐标时,OSG的Y,Z坐标和OpenGL相反,而写矩阵时又和OpenGL一致,我想应该不至于这样吧,但是一直找不到相关的资料,希望高手解惑!!!
 
首先,OSG的坐标系是这样的:X向右,Y向屏幕里,Z向上,因此它符合右手坐标系;与OpenGL相比,它的坐标系相当于绕X轴正向逆时针旋转了90度。这一点在OSGQSG中有叙述,您可以再仔细找一下。


至于您遇到的困惑,我想主要是您混淆了三维世界和观察矩阵的概念~~如果您希望牛能够向下移动12个单位,同时绕X轴旋转的话,可以给它一个MatrixTransform的父节点,并且将变换矩阵传递给这个MatrixTransform节点。
但是在您的程序中,rot*trans的矩阵连乘操作是针对场景的主摄像机,即:
viewer.getCamera()->setViewMatrix( rot * trans );
那么也就是说,您修改的是摄像机的观察矩阵:即,在摄像机坐标系中,三维世界相对于摄像机的位置。
摄像机坐标系是由setProjectionMatrixAsPerspective决定的,也就是说,您的摄像机采用透视投影的方式,因此它面向XY平面,视野夹角40度,原点与世界原点暂时是重合的。(此时如果直接运行程序,可以看到一片黑,因为摄像机完全在牛模型的体内)
然后,三维世界沿着Z负方向移动了12个单元,此时您可以看见牛了。
之后,您选择沿X方向旋转三维世界(此处也就是旋转牛),由于摄像机面对着XY平面(Y向上),所以模型相当于横着滚动。此时请不要再用世界坐标系来理解您看到的景象了,因为有透视投影的关系,摄像机本身已经是面对XY平面的~~OSG的世界坐标系并没有发生任何变化
 
 
Y的方向是向里的,这一点您可以做实验来验证。三维仿真系统的坐标系和真实世界一样,都是右手坐标系。除此之外,请一定相信OSG和OpenGL的矩阵运算方法之间没有任何矛盾之处,这个坐标系的偏差也不会对场景的运算产生任何影响。因此请不要单纯地用Y/Z互换来解释您看到的现象,最起码来说,OSG和OpenGL的坐标系Y/Z轴是不能互换的,两者相差了90度!


这里关键的问题是setViewMatrix函数到底做了什么:它的作用并非是让摄像机运动!而是让整个三维世界·按照摄像机坐标系(而非绝对坐标系)·实现运动
那么,摄像机坐标系是由谁来定义的呢?显然它不应当与世界坐标系重合。我的理解是视点的变换改变了摄像机坐标系的旋转姿态,就如同自然世界中的我们不改动相机三脚架位置,而仅仅是调整相机使其对准某个方向一样。所谓的透视投影矩阵,其作用同样是调整视点,对于OSG来说,也就是改变摄像机坐标系的旋向。
透视投影矩阵和正交矩阵的有关定义请参阅OpenGL红宝书的相关解释,在第四版的86页可以找到下面的语句:
“可以通过旋转和平移来改变函数gluPerspective创建的视景体的朝向,如果不进行这些变换,视点将位于原点,视线指向Z轴负方向”。
这也就是我为什么说“摄像机坐标系是由setProjectionMatrixAsPerspective决定的,它面向XY平面”的原因。


如果您能够同意我对于摄像机坐标系的诠释。那么后面的问题就迎刃而解了,请参阅我第一次回帖中的解释。
 
不论是OPENGL还是OSG,都采用是右手系,


opengl坐标系,即z轴正向朝外;y轴正向朝上;x轴正向朝右.
osg坐标系,即z轴正向朝上;y轴正向朝前;x轴正向朝右.




可以这么来说,将opengl坐标系沿x轴沿前下方旋转90度,即osg的默认坐标系.




这跟Directx是不一样的,Directx采用左手坐标系,即z轴正向朝里;y轴正向朝上;x轴正向朝右.


在viewer.getCamera()->setProjectionMatrixAsPerspective( 40., 1., 1., 100. );之前,
osg::Vec3 vecEye, vecCenter, vecUp;
采用viewer.getCamera()->getViewMatrixAsLookAt(vecEye, vecCenter, vecUp);
可以看到:
vecEye = {0.0, 0.0, 0.0};
vecCenter = {0.0, 0.0, -1.0};
vecUp = { 0.0, 1.0, 0.0 };
由此可以看出在设置透视之前,镜头是对准XOY平面的。
0 0
原创粉丝点击