2014-10-24 1 views
3

Я пытался выяснить это в течение нескольких часов, и я просто не могу найти решение для этого: То, что я пытаюсь достичь, - это преобразование вектора ориентации в 3 glm::rotation звонки.Yaw, Pitch и roll to glm :: rotate

У меня есть цилиндр, расположенный в (0, 0, 0) с определенным радиусом и высотой. С Leap Motion SDK Я выполнения отслеживания инструмент, который дает мне положение наконечника и направление вектора (что выражается как единичный вектор в том же направлении, что и наконечник):

enter image description here Источник: https://developer.leapmotion.com/documentation/skeletal/java/api/Leap.Pointable.html

Кроме того, yaw, pitch и roll могут быть извлечены формы этого вектора, используя следующие функции SDK:

/// The yaw angle in radians. 
/// 
/// Yaw is the angle between the negative z-axis and the projection of 
/// the vector onto the x-z plane. In other words, yaw represents rotation 
/// around the y-axis. If the vector points to the right of the negative z-axis, 
/// then the returned angle is between 0 and pi radians (180 degrees); 
/// if it points to the left, the angle is between 0 and -pi radians. 
/// 
/// \image html images/Math_Yaw_Angle.png 
/// 
/// @returns The angle of this vector to the right or left of the negative z-axis. 
float yaw() const 
{ 
    return std::atan2(x, -z); 
} 

/// The pitch angle in radians. 
/// 
/// Pitch is the angle between the negative z-axis and the projection of 
/// the vector onto the y-z plane. In other words, pitch represents rotation 
/// around the x-axis. 
/// If the vector points upward, the returned angle is between 0 and pi radians 
/// (180 degrees); if it points downward, the angle is between 0 and -pi radians. 
/// 
/// \image html images/Math_Pitch_Angle.png 
/// 
/// @returns The angle of this vector above or below the horizon (x-z plane). 
float pitch() const { 
    return std::atan2(y, -z); 
} 

/// The roll angle in radians. 
/// 
/// Roll is the angle between the negative y-axis and the projection of 
/// the vector onto the x-y plane. In other words, roll represents rotation 
/// around the z-axis. If the vector points to the left of the negative y-axis, 
/// then the returned angle is between 0 and pi radians (180 degrees); 
/// if it points to the right, the angle is between 0 and -pi radians. 
/// 
/// \image html images/Math_Roll_Angle.png 
/// 
/// Use this function to get roll angle of the plane to which this vector is a 
/// normal. For example, if this vector represents the normal to the palm, 
/// then this function returns the tilt or roll of the palm plane compared 
/// to the horizontal (x-z) plane. 
/// 
/// @returns The angle of this vector to the right or left of the y-axis. 
float roll() const { 
    return std::atan2(x, -y); 
} 

В моем OpenGL цикла рендеринга, я извлекая положение наконечника, а также в направлении против каждого кадра. Я передаю матрицу модели в качестве единой переменной моих шейдеров следующим образом:

cylinder->ResetModelMatrix(); // Set model matrix to identity 
glm::vec3 translation = glm::vec3(toolTipPosition.x, toolTipPosition.y, toolTipPosition.z); 
cylinder->TranslateModel(translation); 
cylinderProgram->SetUniform("modelMatrix", cylinder->GetModelMatrix()); 

Только с переводом, это хорошо работает и выглядит примерно так (с цилиндр всегда направлен вверх): enter image description here

Проблема возникает, когда я пытаюсь повернуть цилиндр в соответствии с ориентацией инструмента Leap. У меня есть следующий код:

yaw = toolDirection.yaw() * Leap::RAD_TO_DEG; 
// similarly for pitch and roll 

cylinder->Rotate(yaw, glm::vec3(0.0f, 1.0f, 0.0f)); 
// pitch around (1, 0, 0) and roll around (0, 0, 1) 

Однако, я не получаю правильные ориентиры и цилиндр «мерцающий» и прыгает между множеством ориентаций, когда я пытаюсь применить это.


важные функции преобразования находятся в интерфейсе, из которого наследует мой класс цилиндр ...

void Drawable::ResetModelMatrix() 
{ 
    this->modelMatrix = glm::mat4(1.0f); 
} 

void Drawable::TranslateModel(glm::vec3 translationVector) 
{ 
    this->modelMatrix = glm::translate(this->modelMatrix, translationVector); 
} 

void Drawable::RotateModel(float angle_in_degrees, glm::vec3 axisOfRotation) 
{ 
    this->modelMatrix = glm::rotate(this->modelMatrix, angle_in_degrees, axisOfRotation); 
} 

void Drawable::ScaleModel(glm::vec3 scalingVector) 
{ 
    this->modelMatrix = glm::scale(this->modelMatrix, scalingVector); 
} 

... с modelMatrix неоспоримым переменной-члена.

Я просмотрел много похожих вопросов по теме вращения в OpenGL и вообще, но я не совсем уверен, что именно проблема с моим кодом здесь.

+0

Для поворота вы должны сначала перевести свой цилиндр в начало координат и выполнить свое вращение и перевести назад. [Функция вращения работает корректно, когда ваша опорная точка является источником.] –

+0

Фактически, то же самое происходит, когда цилиндр центрирован в начале координат без какого-либо перевода. – Schnigges

+0

Я предполагаю, что красная линия на изображении - ваш цилиндр. Если вы хотите повернуть его вокруг зеленого шара, сначала вы должны применить перевод на свой цилиндр так, чтобы ваш зеленый шар был на месте. Чем вы можете применить поворот к вашему цилиндру, и, наконец, вы сможете перевести назад свой цилиндр. [Здесь вам нужно, чтобы нижний край цилиндра находился в начале координат, а не в центре цилиндра) –

ответ

4

Я предполагаю, что есть некоторые непонимание того, что у нас есть и что мы хотим получить.

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

Вращения о происхождении имеют три степени свободы. Это означает, что вам нужно три независимых параметра, чтобы однозначно указать ориентацию тела. Точно три, не больше не меньше. Не имеет значения, каковы они до тех пор, пока ни один из них не может быть выражен в терминах других. Трехмерное вращение может быть задано несколькими способами. Наиболее обычными методами являются:

  • Угол Эйлера. Три независимых параметра.
  • Территории Таит-Брайан (рыскание, смола и рулон).Также три независимых параметра. Не путайте с углами Эйлера, они не то же самое!
  • Axis-угол представления. Определяет поворот на единичный вектор и угол. Вы можете утверждать, что для этого случая есть четыре параметра. Однако это не так, потому что эти параметры не являются независимыми. Действительно, существует ограничение на длину единичного вектора. Или вы можете рассматривать это, поскольку длина вектора не влияет на вращение. Таким образом, опять же, существует три независимых параметра.
  • Ориентация кватерниона. Как и предыдущий метод, четыре параметра, которые зависят. Как правило, ориентационный кватернион можно рассматривать как способ кодирования представления по оси. Длина кватерниона не влияет на вращение, и обычно считается, что кватернион имеет единичную длину. Таким образом, у нас есть четыре параметра и одно ограничение, что означает, что мы имеем три независимые степени свободы.

Давайте подробнее рассмотрим вашу проблему. У вас есть вектор направления, и вы хотите использовать его для определения ориентации цилиндра. По сути, у вас есть только два независимых параметра, потому что длина вектора направления не имеет значения (пусть это будет единичный вектор для простоты). Таким образом, вы не можете просто получить поворот от вектора направления, потому что будет один произвольный параметр.

Из входных данных, которые содержат только два независимых параметра, невозможно получить три неизвестных независимых параметра. Существует необходимость в дополнительном ограничении. Обычно это Вверх-вектор. Дополнительное ограничение преобразует три неизвестных независимых параметра в зависимые параметры.

Я бы посоветовал использовать функцию glm::orientation, которая строит матрицу ориентации от ввода вектора направления и вектора вверх.

Что касается углов поворота, угла наклона и наклона, которые вы получаете от указанных функций SDK. Эти функции не работают так, как вы пытаетесь их использовать. Вы должны указать вверх-вектор. Например, рассмотрим, что верхним вектором является направление оси y. Это означает, что угол поворота будет всегда равен нулю. Вы должны рассчитать угол рыскания, как и раньше. Итак:

float yaw = std::atan2(x, -z); 

Угол наклона будет станд :: atan2 (у, -z), но в повернутом кадре, а не в оригинале. Вы должны учитывать угол тангажа в виде дугового касания отношения длины проекции вектора направления к плоскости x-z и ее проекции на ось y. Я имею в виду:

float projectionLength = std::sqrt(x * x + z * z); 
float pitch = std::atan2(y, projectionLength); 

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

См this для получения дополнительной информации о Тейт-Bryan углы

Кроме того, вы должны быть осведомлены о том,, что повороты не являются коммутативными. Это означает, что вы должны выполнять вращения в строгой последовательности. Существует шесть возможностей выбора осей вращения для углов Тейт-Брайана, которые называются условностями. Эти соглашения зависят от осей, по которым выполняются вращения.

+0

Отличный ответ !!! Особая благодарность за указание функции «glm :: orientation», понятия не имела, что она существует !!! – Schnigges