Yaw, pitch and roll to glm :: rotate

I've been trying to figure this out for hours and I just can't seem to find a solution to this: What I'm trying to achieve is converting the orientation vector to 3 calls glm::rotation

.

I have a cylinder positioned at a point (0, 0, 0)

with a specific radius and height. With the Leap Motion SDK, I do tool tracking, which gives me the position of the tip and a direction vector (which is expressed as a unit vector pointing in the same direction as the tip):

enter image description here Source: https://developer.leapmotion.com/documentation/skeletal/java/api/Leap.Pointable.html

In addition, yaw

, pitch

and roll

they can be recovered from this vector using the following SDK functions:

/// 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);
}

      

In my OpenGL render loop, I extract the tip position as well as the direction vector for each frame. I pass the model matrix as a single variable for my shaders like this:

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());

      

Only with translation it works nicely and looks something like this (with the cylinder always pointing up): enter image description here

The problem occurs when I try to rotate the cylinder according to the orientation of the Leap tool. I have the following code:

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)

      

However, I am not getting the correct orientation and the cylinder "flickers" and jumps between many orientations when I try to apply this.


The important conversion functions are located in the interface from which my cylinder class inherits ...

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);
}

      

... with modelMatrix

being a member variable.

I've looked through a lot of similar questions about rotation in OpenGL and in general, but I'm not entirely sure what exactly the problem is with my code here.

+3


source to share


1 answer


I guess there is some misunderstanding of what we have and what we want.

The point is that the direction vector does not uniquely determine the orientation of the body in space. To make this statement clear, let's take a closer look at how rotations can be displayed in 3D space.

Rotations around the origin have three degrees of freedom. This means that you need three independent parameters to uniquely indicate the orientation of the body. Exactly three, no more, no less. It does not matter what they are as long as none of them can be expressed in terms of the others. Three-dimensional rotation can be specified in several ways. The most common methods are:

  • Euler angles. Three independent parameters.
  • Tite-Brian angles (yaw, step and throw). Also three independent parameters. Do not confuse with Euler angles, they are not the same!
  • Axial angular representation. Specifies rotation by a unit vector and angle. You can argue that there are four parameters for this case. However, this is not the case because these parameters are not independent. Indeed, there is a limitation on the length of the unit vector. Or you can consider this since the length of the vector does not affect the rotation. So, again, there are three independent parameters.
  • Quaternion orientation. Like the previous method, there are four parameters that depend on. Generally, an orientation quaternion can be thought of as a way of encoding a representation along an axis. The length of the quaternion does not affect rotation, and the quaternion is generally considered to be of unit length. Thus, we have four parameters and one constraint, which means that we have three independent degrees of freedom.

Let us take a closer look at your problem. You have a direction vector and you want to use it to determine the orientation of the cylinder. Basically, you only have two independent parameters, because the length of the direction vector doesn't matter (let's say it is a unit vector for simplicity). So you can't just get the rotation from the direction vector, because there will be one arbitrary parameter.

It is simply not possible to get three unknown independent parameters from an input that contains only two independent parameters. There is a need for additional restriction. This is usually the Up vector. An additional constraint converts three unknown independent parameters to dependent parameters.

I would advise using glm :: orientation , which builds an orientation matrix from the input of a direction vector and an up-vector.



As for the pivot angles, pitch and tilt angle you get from said SDK features. These features don't work the way you are trying to use them. You must point an upward vector. For example, consider that the top vector is the y-axis direction. This means that the angle of rotation will always be zero. You must calculate the yaw angle as before. So:

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

      

The pitch angle will be std :: atan2 (y, -z) , but in the rotated frame, not in the original. You must account for the pitch angle as the tangent arc of the ratio of the projected length of the direction vector to the xz plane and its projection onto the y-axis. I mean:

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

      

When you construct the transformation matrix, you must first apply the rotation corresponding to the pitch angle, then the rotation corresponding to the yaw rotation, and then the translation.

See this for more information on Tit-Brian angles

Also, you should be aware that rotations are not commutative. This means that you must perform the rotations in a strict sequence. There are six choices for the Tate-Brian angles of rotation, which are called conventions. These conventions depend on the axes around which rotations are performed.

+4


source







All Articles