как предотвратить блокировку карданного подвеса с помощью glm quat

Я пытаюсь реализовать камеру 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 вызывает «прерывистое» вращение. Что я делаю неправильно?


person ukaku    schedule 25.05.2013    source источник
comment
1) Насколько я знаю, тележка означает перемещение камеры по прямой линии. 2) Что ты имеешь в виду под изменчивым? Откуда взялись x и y? Совершенно непонятно, как код не дает желаемых результатов.   -  person Andreas Haferburg    schedule 26.05.2013
comment
1) простить пропущенное имя названной функции; 2) под прерывистым я подразумеваю, что когда я поворачиваю позицию, используя Q = glm::gtx::quaternion::angleAxis(float(angle_x), axis0); вращение вокруг оси (0,1,0) является идеально круговым и продолжается, однако, когда я добавляю ось вращения (1,0,0), внезапно вращение от этой оси приводит к неожиданному изменению положения камеры.   -  person ukaku    schedule 26.05.2013


Ответы (2)


примечание: скопировано из мой ответ здесь.

Все, что вы сделали, это эффективно реализовали углы Эйлера с кватернионами. Это не помогает.

Проблема с углами Эйлера заключается в том, что при вычислении матриц каждый угол определяется относительно поворота предшествующей матрицы. Что вам нужно, так это взять текущую ориентацию объекта и применить поворот вдоль некоторой оси, создав новую ориентацию.

Вы не можете сделать это с углами Эйлера. Можно с матрицами, а можно с кватернионами (поскольку они всего лишь вращающаяся часть матрицы). Но вы не можете сделать это, притворяясь, что это углы Эйлера.

Это достигается за счет того, что углы не сохраняются все. Вместо этого у вас есть просто кватернион, который представляет текущую ориентацию объекта. Когда вы решаете применить к нему поворот (на некоторый угол по некоторой оси), вы создаете кватернион, который представляет этот поворот на угол вокруг этой оси. Затем вы умножаете этот кватернион вправо на кватернион текущей ориентации, создавая новую текущую ориентацию.

Когда вы визуализируете объект, вы используете текущую ориентацию как... ориентацию.

person Nicol Bolas    schedule 26.05.2013
comment
спасибо за этот ответ. теперь мой вопрос: если я представлю все свои ориентации в виде кватернионов и применю новую ориентацию, используя новый угол ориентации и ось ориентации, а затем применю ее к предыдущей ориентации, чтобы получить новую ориентацию (извините за длинное предложение), могу ли я затем преобразовать свой quaternion to mat4 и при этом быть свободным от карданного замка? - person ukaku; 26.05.2013
comment
@ukaku: Это новый вопрос, поэтому вы должны задать его с помощью кнопки «Задать вопрос». Это также то, что вы должны попробовать реализовать, прежде чем спрашивать нас. - person Nicol Bolas; 26.05.2013

Скопировано из вопроса:

РЕДАКТИРОВАТЬ 26.05.2013 Как я решил эту проблему:

Проблема с моим кодом заключалась в том, что когда дело дошло до рендеринга сцены, которую я использовал:

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

Затем я использовал эту матрицу, чтобы поместить сцену в перспективу камеры/в основном для рендеринга камеры. Однако, когда я вызвал свою функцию «Camera::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(двойной угол_x, двойной угол_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);

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;
person Community    schedule 23.05.2016