【问题标题】:how do you prevent gimbal lock using glm quat [duplicate]你如何使用glm quat防止万向节锁定[重复]
【发布时间】:2023-12-29 20:35:01
【问题描述】:

我正在尝试实现一个 opengl 相机,它可以围绕指定的世界坐标旋转相机的位置。我正在尝试使用 glm 数学库来做到这一点;我的代码如下

void Camera::dolly(double angle_x, double angle_y, const double& loc_x, const double& loc_y, const double& loc_z, const double& dt) {

  glm::vec3 target = glm::vec3(loc_x,loc_y,loc_z);

  glm::quat Q;glm::vec3 axis0(0.0f,1.0f,0.0f);
  glm::quat R;glm::vec3 axis1(1.0f,0.0f,0.0f);

  position = position - target;

  //glm::normalize(axis0);
  glm::normalize(axis1);

  Q = glm::gtx::quaternion::angleAxis( float(angle_x ), axis0 );;
  R = glm::gtx::quaternion::angleAxis( float(andl_y ), axis1 );;

  glm::quat final =  R*Q;

  position =  final * position;

  position = position + target;
  cout << "\tPosition: " << position.x << " " << position.y << " " << position.z <<endl;
}

当我测试代码时,使用 quat Q 的旋转可以正常工作,但 quat R 会导致“不稳定”的旋转。我做错了什么?

【问题讨论】:

  • 1) AFAIK,dolly 表示沿直线移动相机。 2) 你说的波涛汹涌是什么意思? xy 来自哪里?完全不清楚代码是如何产生你想要的结果的。
  • 1) 原谅未命名函数名; 2)断断续续的意思是当我使用 Q = glm::gtx::quaternion::angleAxis( float(angle_x ), axis0 ); 旋转位置时围绕轴(0,1,0)的旋转是完美的圆形并继续,但是当我去添加旋转轴(1,0,0)时,突然从这个轴旋转会导致相机位置以意想不到的方式出现。

标签: opengl camera locking quaternions glm-math


【解决方案1】:

注意:复制自my answer here

您所做的只是用四元数有效地实现欧拉角。这没有帮助。

欧拉角的问题在于,当您计算矩阵时,每个角度都相对于它之前的矩阵的旋转。您想要的是获取对象的当前方向,并沿某个轴应用旋转,从而产生新的方向。

你不能用欧拉角来做到这一点。您可以使用矩阵,也可以使用四元数(因为它们只是矩阵的旋转部分)。但是你不能通过假装它们是欧拉角来做到这一点。

这是通过不在所有处存储角度来完成的。相反,您只有一个代表对象当前方向的四元数。当您决定对其应用旋转(某个轴的某个角度)时,您构建了一个四元数,该四元数表示该旋转围绕该轴的某个角度。然后你将该四元数与当前方向四元数右乘,产生一个新的当前方向。

当您渲染对象时,您使用当前方向作为...方向。

【讨论】:

  • 感谢您的回答。我现在的问题是:如果我将所有方向表示为四元数并使用新的方向角和方向轴应用新方向,然后将其应用于先前的方向以获得新的方向(对不起,长句),我可以转换我的四元数到 mat4 并且仍然没有万向节锁?
  • @ukaku:这是一个新问题,所以您应该使用“提问”按钮来提问。这也是您在询问我们之前应该尝试实施的一项。
【解决方案2】:

从问题中复制:

EDIT 05/26/2013 我是如何解决这个问题的:

我的代码的问题在于渲染我使用的场景:

    matrix = glm::lookAt(position,looking_at, upDirection);

然后我使用这个矩阵将场景放入相机的视角/基本上是渲染相机。但是,当我调用我的“Camera::dolly”(实际上不应该称为 dolly,因为我的目标是旋转相机)功能时,我旋转了相机位置而不旋转/更新 upDirection(初始化为(0, 1,0) 变量。这导致了我所描述的“不稳定”问题,因为按轴(1,0,0)旋转会改变 upDirection 指向的方向。新的 代码如下:

glm::quat orient = glm::gtx::quaternion::angleAxis(float(0),0.0f, 0.0f, 1.0f);

void Camera::rotate(double angle_x, double angle_y, const double& loc_x, const double& loc_y, const double& loc_z, const double& dt) { glm::vec3 目标 = glm::vec3(loc_x,loc_y,loc_z);

position = position - target;

angle_x *= dt;
angle_y *= dt;

glm::quat old_orient = orient;

glm::normalize(orient);
glm::quat q_x_axis = glm::gtx::quaternion::angleAxis(float(angle_y),1.0f, 0.0f, 0.0f) ;
glm::quat q_y_axis = glm::gtx::quaternion::angleAxis(float(angle_x), 0.0f, 1.0f, 0.0f);

orient = orient * q_x_axis * q_y_axis;

upDirection = upDirection * orient;
position = position * (orient);

orient = old_orient;

position = position + target;

【讨论】: