The rotation angles directly affect the first 3 columns of OpenGL **GL_MODELVIEW** matrix, precisely *left*, *up* and *forward* axis elements. For example, if a unit vector along X axis, (1, 0, 0) is multiplied by an arbitrary 3x3 rotation matrix, then the result of the vector after multiplication is (m_{0}, m_{1}, m_{2});

It means the first column (m_{0}, m_{1}, m_{2}) of the rotation matrix represents the coordinates of the *left* axis after rotated. Similarly, the second column is the *up* axis and the third column is the *forward* axis.

This article describes how to contruct GL_MODELVIEW matrix with rotation angles.

First, we look at a rotation around each axis; +X, +Y and +Z. We project three axes onto a plane in 3 different ways, so the axis that we want to rotate is facing toward you. The positive rotation direction becomes counter clockwise (right hand rule).

Initial value of up(Y) and forward(Z) axes are (0, 1, 0) and (0, 0, 1). If left(X) axis rotates *A* degree, then new up(Y') axis becomes (0, cosA, sinA) and forward(Z') becomes (0, -sinA, cosA). The new axes are inserted as column components of the 3x3 rotation matrix. Then, the rotation matrix becomes;

Now, we rotate around up vector, which is facing toward you, with *B* angle . Left(X) axis is transformed from (1, 0, 0) to X' (cosB, 0, -sinB). And forward(Z) axis is from (0, 0, 1) to Z' (sinB, 0, cosB).

If we rotate forward(Z) axis with angle *C* degree, the original left(X) (1, 0, 0) axis becomes X' (cosC, sinC, 0), and up(Y) (0, 1, 0) axis becomes Y' (-sinC, cosC, 0).

We can combine these separate axis rotations into one matrix by multiplying the above 3 matrices together. Note that multiplication of matrices is not commutative, so a different order of matrix multiplication results in a different outcome. There are 6 different combinations are possible; R_{x}R_{y}R_{z}, R_{x}R_{z}R_{y}, R_{y}R_{x}R_{z}, R_{y}R_{z}R_{x}, R_{z}R_{x}R_{y} and R_{z}R_{y}R_{x}.

The left column of the combined rotation matrix is the *left* axis after rotated, the middle column is the *up* axis, and the right column is the *forward* axis.

Here is a C++ example code for R_{x}R_{y}R_{z} combination. It performs 3 rotations in order of R_{z} (roll), R_{y} (yaw) then R_{x} (pitch). The results of *left*, *up* and *forward* axis can be used to construct GL_MODELVIEW matrix.

```
// minimal implimentation of Vector3 struct
struct Vector3
{
float x;
float y;
float z;
Vector3() : x(0), y(0), z(0) {}; // initialze when created
};
///////////////////////////////////////////////////////////////////////////////
// convert Euler angles(x,y,z) to axes(left, up, forward)
// Each column of the rotation matrix represents left, up and forward axis.
// The order of rotation is Roll->Yaw->Pitch (Rx*Ry*Rz)
// Rx: rotation about X-axis, pitch
// Ry: rotation about Y-axis, yaw(heading)
// Rz: rotation about Z-axis, roll
// Rx Ry Rz
// |1 0 0| | Cy 0 Sy| |Cz -Sz 0| | CyCz -CySz Sy |
// |0 Cx -Sx|*| 0 1 0|*|Sz Cz 0| = | SxSyCz+CxSz -SxSySz+CxCz -SxCy|
// |0 Sx Cx| |-Sy 0 Cy| | 0 0 1| |-CxSyCz+SxSz CxSySz+SxCz CxCy|
///////////////////////////////////////////////////////////////////////////////
void anglesToAxes(const Vector3 angles, Vector3& left, Vector3& up, Vector3& forward)
{
const float DEG2RAD = acos(-1) / 180.0f; // PI/180
float sx, sy, sz, cx, cy, cz, theta;
// rotation angle about X-axis (pitch)
theta = angles.x * DEG2RAD;
sx = sin(theta);
cx = cos(theta);
// rotation angle about Y-axis (yaw)
theta = angles.y * DEG2RAD;
sy = sin(theta);
cy = cos(theta);
// rotation angle about Z-axis (roll)
theta = angles.z * DEG2RAD;
sz = sin(theta);
cz = cos(theta);
// determine left axis
left.x = cy*cz;
left.y = sx*sy*cz + cx*sz;
left.z = -cx*sy*cz + sx*sz;
// determine up axis
up.x = -cy*sz;
up.y = -sx*sy*sz + cx*cz;
up.z = cx*sy*sz + sx*cz;
// determine forward axis
forward.x = sy;
forward.y = -sx*cy;
forward.z = cx*cy;
}
```