将 OpenGL 坐标系统转换为自定义并返回

Convert OpenGL coord system to custom and back

本文关键字:自定义 返回 转换 系统 OpenGL 坐标 坐标系      更新时间:2023-10-16

我有一个任务,使用OpenGL在地面上绘制3D对象。我使用 OpenGL 左手坐标系统,其中 Y 轴向上。但是3D物体和相机轨道物体应使用具有以下属性的不同坐标系:

  • XY平面是接地平面;
  • Z 轴向上;
  • Y 轴为"北";
  • X 轴为"东";
  • 方位角(或水平角(为 [0, 360] 度;
  • 仰角(或垂直(角度与 XY 平面成 [0, 90] 度。 最终用户使用方位角和仰角围绕某个中心旋转摄像机。所以我制作了以下代码来从球面坐标转换为四元数:
//polar: x - radius, y - horizontal angle, z - vertical 
QQuaternion CoordinateSystemGround::fromPolarToQuat(const QVector3D& polar) const {
QQuaternion dest = QQuaternion::fromEulerAngles({0, polar.y(), polar.z()});
//convert user coord system back to OpenGL by rotation around X-axis
QQuaternion orig = QQuaternion::fromAxisAndAngle(1, 0, 0, -90);
return dest * orig;
}

和返回:

QVector3D CoordinateSystemGround::fromQuatToPolar(const QQuaternion& q) const {
//convert OpenGL coord system to destination by rotation around X-axis
QQuaternion dest = QQuaternion::fromAxisAndAngle(1, 0, 0, 90);
QQuaternion out = q * dest;
QVector3D euler = out.toEulerAngles();
float hor = euler.y();
if(hor < 0.0f)
hor += 360.0f;
float ver = euler.z();
if(ver > 90.0f)
ver = 90.0f;
else if(ver < 0.0f)
ver = 0.0f;
//x changes later
return QVector3D(0, hor, ver);
}

但它不能正常工作。我想从 PolarToQuat 转换在某处有错误,我不明白在哪里。

似乎我找到了解决方案。因此,要从四元数获得极角:

QVector3D CoordinateSystemGround::fromQuatToPolar(const QQuaternion& q) const {
QQuaternion coord1 = QQuaternion::fromAxisAndAngle(0, 1, 0, -180);
QQuaternion coord2 = QQuaternion::fromAxisAndAngle(1, 0, 0, -90);
QQuaternion out = orig1 * orig2 * q;
QVector3D euler = out.toEulerAngles();
float hor = euler.y();
if(hor < 0.0f)
hor += 360.0f;
float ver = euler.x();
return QVector3D(0, hor, -ver);
}

然后返回:

QQuaternion CoordinateSystemGround::fromPolarToQuat(const QVector3D& polar) const {
QQuaternion dest = QQuaternion::fromEulerAngles({-polar.z(), polar.y(), 0});
QQuaternion coord1 = QQuaternion::fromAxisAndAngle(1, 0, 0, 90);
QQuaternion coord2 = QQuaternion::fromAxisAndAngle(0, 1, 0, 180);
return coord1 * coord2 * dest;
}

不确定这是一个最佳解决方案,但它可以正常工作。

编辑

经过一些研究,我发现了一些错误,并进行了优化并希望正确的转换版本:

QVector3D CoordinateSystemGround::fromQuatToPolar(const QQuaternion& q) const {
// back to OpenGL coord system: just multiplication on inverted destination coord system
QQuaternion dest = QQuaternion::fromAxes({-1, 0, 0}, {0, 0, 1}, {0, 1, 0}).inverted();
QVector3D euler = (dest * q).toEulerAngles();
float hor = euler.y();
if(hor < 0.0f)
hor += 360.0f;
float ver = euler.x();
return QVector3D(0, hor, -ver);
}

然后返回:

QQuaternion CoordinateSystemGround::fromPolarToQuat(const QVector3D& polar) const {
//just rotate if we were in OpenGL coord system
QQuaternion orig = QQuaternion::fromEulerAngles({-polar.z(), polar.y(), 0});
//and then multiply on destination coord system
QQuaternion dest = QQuaternion::fromAxes({-1, 0, 0}, {0, 0, 1}, {0, 1, 0});
return dest * orig;
}