OSG坐标问题

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平面的。
<think>根据用户需求,用户希望了解在osgEarth中如何进行坐标转换。结合提供的引用内容,我将整理一个清晰的回答,包括世界坐标、经纬度坐标、投影坐标之间的转换方法,并给出相关代码示例。 回答结构: 1. 介绍osgEarth坐标系统的基本概念 2. 详细说明各种坐标转换方法(世界坐标转经纬度、经纬度转世界坐标、不同投影坐标系之间的转换) 3. 提供代码示例 4. 注意事项(如高程模式) 最后生成相关问题</think>### osgEarth 坐标转换详解 在 osgEarth 中,坐标转换主要涉及三种类型:**世界坐标(XYZ)**、**经纬度高程(Lon/Lat/Alt)** 和 **投影坐标(如UTM)**。以下是核心方法及代码示例: --- #### **1. 世界坐标 ↔ 经纬度高程(WGS84)** **原理**:通过椭球模型(`osg::EllipsoidModel`)进行转换,需注意角度/弧度转换。 **代码实现**: ```cpp #include <osg/CoordinateSystemNode> // 世界坐标转经纬度高程 (XYZ → Lon/Lat/Alt) osg::Vec3d WorldToLonLatAlt(const osg::Vec3d& world) { osg::EllipsoidModel em; double lat, lon, alt; em.convertXYZToLatLongHeight(world.x(), world.y(), world.z(), lat, lon, alt); return osg::Vec3d(osg::RadiansToDegrees(lon), osg::RadiansToDegrees(lat), alt); } // 经纬度高程转世界坐标 (Lon/Lat/Alt → XYZ) osg::Vec3d LonLatAltToWorld(const osg::Vec3d& lonLatAlt) { osg::EllipsoidModel em; double x, y, z; em.convertLatLongHeightToXYZ( osg::DegreesToRadians(lonLatAlt.y()), // Lat osg::DegreesToRadians(lonLatAlt.x()), // Lon lonLatAlt.z(), // Alt x, y, z ); return osg::Vec3d(x, y, z); } ``` --- #### **2. 不同投影坐标系转换(如WGS84 ↔ UTM)** **原理**:使用 `SpatialReference` 定义坐标系,通过 `GeoPoint::transform()` 转换。 **代码示例**: ```cpp #include <osgEarth/SpatialReference> // WGS84经纬度 → UTM投影坐标 const SpatialReference* wgs84 = SpatialReference::get("wgs84"); const SpatialReference* utm15 = SpatialReference::get("+proj=utm +zone=15 +ellps=GRS80 +units=m"); // UTM 15N GeoPoint wgsPoint(wgs84, -93.0, 34.0); // 经度-93°, 纬度34° GeoPoint utmPoint = wgsPoint.transform(utm15); // 转换到UTM15N投影坐标 // 带高程的转换(ALTMODE_ABSOLUTE表示绝对高程) GeoPoint pointWithAlt(wgs84, -93.0, 34.0, 100.0, ALTMODE_ABSOLUTE); GeoPoint utmWithAlt = pointWithAlt.transform(utm15); ``` --- #### **3. 世界坐标 ↔ 屏幕坐标** **原理**:结合相机视图矩阵、投影矩阵和视口矩阵计算。 **代码示例**: ```cpp osg::Vec3d WorldToScreen(const osg::Vec3d& world, osg::Camera* camera) { osg::Matrix VPW = camera->getViewMatrix() * camera->getProjectionMatrix() * camera->getViewport()->computeWindowMatrix(); return world * VPW; // 返回屏幕坐标 (x, y, depth) } ``` --- #### **关键注意事项**: 1. **高程模式**: - `ALTMODE_ABSOLUTE`:高程基于椭球体(如WGS84椭球)。 - `ALTMODE_RELATIVE`:高程基于当地地形表面(需加载地形数据)。 2. **性能优化**: - 频繁转换时复用 `SpatialReference` 和 `EllipsoidModel` 对象,避免重复创建。 3. **依赖项**: - 投影转换需链接 PROJ 库(osgEarth 默认集成)[^1][^4]。 --- ### 相关问题 1. 如何在不同高程模式(绝对/相对)间正确转换坐标? 2. osgEarth 中如何自定义非标准投影坐标系(如地方坐标系)? 3. 坐标转换时出现偏移可能是什么原因?如何调试? 4. 在实时渲染中优化大规模坐标转换性能的方法有哪些? [^1]: GIS / osgearth :坐标系统。即时投影可根据不同坐标系统显示其数据集。 [^2]: osgEarth世界坐标转屏幕坐标的实现依赖相机矩阵。 [^3]: 世界坐标与经纬度高程转换需通过椭球模型计算。 [^4]: 投影坐标系转换需明确定义源和目标SRS,并注意高程模式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值