Determining Yaw, Pitch and Roll

from

Up and Forward Vectors

by

J. L. Doty

Copyright (c) 2009 by J. L. Doty

jldoty.com

## Basics

In 3D programming the conventional wisdom is that one should avoid Yaw, Pitch and Roll (YPR) at all costs and use 3D rotation matrices and/or the Up and Forward (UF) vectors of a first-person camera. But the fact remains that coding the UF vectors of a first-person camera requires frame-to-frame incremental adjustment of YPR, making it nearly impossible to avoid YPR. Hence, the ever present need to convert between UF and YPR, or between a rotation matrix and YPR. And, as will be shown in this article, the conversion algorithms are quite robust. That said, the one real problem with YPR is singularities.

This article is not going to teach anyone the basics of vectors. If you don’t understand the basics of vectors and 3D coordinate space, go away and learn them before reading this article. Furthermore, this article limits itself to the 3D conventions established in the DirectX^{(r)} programming environment:

· The x-y-z coordinate system is left-handed,

· Yaw, Pitch and Roll are rotations about the y, x and z axes respectively, meaning

_{}, _{} and _{}, and

· given a set of YPR values, the order of rotation is Roll first, followed by Pitch, then Yaw.

· zero YPR results in a Forward vector coincident with the z-axis, and an Up vector coincident with the y-axis.

However, converting to a right-handed coordinate system, OpenGL or any other geometry is relatively straightforward.

## Notational Conventions

The vector notational conventions used in this article are:

· _{} is a scalar quantity with magnitude, but no direction.

· _{}is an arbitrary vector, with arbitrary direction and length.

· _{}is the magnitude, or length, of arbitrary vector _{}, a scalar quantity.

· _{}is an arbitrary vector that has been normalized, with arbitrary direction and unit length.

Hence, the relationship: _{} eq. 1

_{}are orthonormal basis vectors that define a 3D coordinate system. Orthonormal means that all three vectors are of unit length, and all three are perpendicular to each other. We define an arbitrary vector as a sum of scalars and the orthonormal basis vectors:

_{} and _{} eq. 2

The Forward and Up vectors simply define a local x-y-z coordinate system in the frame of reference of the camera. To complete that local coordinate system we’ll define a Right vector to go along with the Forward and Up vectors such that when _{}, then

_{}, _{}, and _{}.

## Determining Yaw and Pitch

The first two quantities, Yaw and Pitch, are relatively easy to determine. Referring to figure 1, which illustrates the orientation of the Up and Forward vectors within the x-y-z coordinate system. Pitch is the angle between the forward vector and its projection on the x-z plane, and Yaw is the angle between that projection and the z-axis. If the normalized Forward vector is defined as:

_{} eq. 3

then Pitch and Yaw are computed in the following way:

_{} eq. 4

_{} eq. 5

When coding equation 5 the Atan2(y, x) function should be used, which will handle Yaw in all four quadrants, and it prevents a divide-by-zero exception when_{}.

## Determining Roll

Roll is more problematic, and I’ve seen a number of articles on the internet that just plain get it wrong. At this stage they usually propose dividing a couple of numbers and using an inverse trigonometric function, a solution that is not always correct. I use a much more robust algorithm.

Many first-person cameras don’t maintain proper orthonormal Up and Forward vectors. This algorithm assumes that the Up and Forward vectors are orthonormal. If they are not, then they must be orthonormalized in the following way:

1. Normalize the Forward vector using equations 1 and 2.

2. Compute the Right vector by taking the cross product of the Up and Forward vectors: _{}

3. Normalize the Right vector using equations 1 and 2

4. Compute the orthonormal Up vector by taking the cross product of the Forward and Right vectors:_{}.

This produces a complete set of basis vectors in the local reference frame of the camera.

Now consider figure 2, which illustrates the geometry for rotation of the x and y axes about the z-axis, where _{} and _{} are the basis vectors before rotation, and _{} and _{} are the basis vectors after a rotation of _{}. Keep in mind that these are local basis vectors that are defined in terms of our world basis vectors in the following way:

_{} eq. 6

_{} eq. 7

_{} eq. 8

_{} eq. 9

and it can be shown that the relationship between the two sets of basis vectors is:

_{} eq. 10

_{} eq. 11

These basis vectors, however, are in the frame of reference of the camera, looking down the camera’s z-axis, which is the Forward vector. _{} and _{}are the Right and Up vectors with Yaw and Pitch, but no Roll, while _{} and _{} are the Right and Up vectors with Yaw, Pitch and Roll. Furthermore, since _{}is the Up vector with no roll, we know that_{}. However, while _{}is normalized, it is not orthonormal in the frame of reference of the camera, meaning it is not perpendicular to the Up and Forward vectors. So we must determine orthonormalized Right and Up vectors (_{} and _{}) in the following way:

1. _{}

2. then normalize _{} using equations 1 and 2, and

3. _{}

At this point we have computed_{}, the Up vector for zero Roll, and we know_{}, the present Up vector. Now we can simply determine _{}from:

_{} eq. 12

_{} eq. 13

However, equation 12 always results in a positive_{}, even when the actual value is negative. So to remove the +/- ambiguity, invert equation 11 to produce

_{} eq. 14

and into equation 14 substitute equations 6, 7 and 9. The result yields a rather long vector equation with _{}components on both sides. However, for the right and left sides of the vector equation to be equal, each of the scalar values for the individual _{} components must be equal, resulting in the following three equations:

_{} eq. 15

_{} eq. 16

_{} eq. 17

All three of these equations hold true, and, using equation 12 to compute _{}, we can use any of the above three equations to compute _{}, and therefore _{}, without the +/- ambiguity. All three will yield the same result, but for accuracy, and to prevent a divide-by-zero exception, test_{}, _{} and _{}, and use the equation that has the greatest absolute value in the denominator. Furthermore, there is no need to specifically test to prevent a divide-by-zero exception since, by definition, at least one of the three denominators will be finite and non-zero.

## Singularities

One singularity must be accounted for, and that is the case where _{}and _{}, resulting in

_{} eq. 18

_{} eq. 19

In most programming languages the Atan2(0, 0) function will return 0 for Yaw, when in fact Yaw is undefined under these circumstances. However, a decision must made as to how this singularity will be handled:

1. Set Yaw to 0 and attribute the remaining object attitude to Roll, or

2. Set Roll to 0 and attribute the remaining object attitude to Yaw

More often than not, scenario 1 is adopted, and the Roll computation is carried out using

_{}, _{}, _{}

or

_{}, _{}, _{}

both of which result in

_{} eq. 20

One artifact of this singularity is that YPR values of (90°, 90°, 0) produce the same orientation as (0, 90°, -90°), and an object may occasionally experience a sudden flip from one to the other.