Inverted yaw angle in the view matrix I'm trying to construct a FPS view matrix for my OpenGL renderer using yaw and pitch angles instead of the typical LookAt view matrix.

The view matrix is the inverse of the camera world transform $\mathbf{M}_{\textrm{view}} = (\mathbf{T}\mathbf{R}_p\mathbf{R}_y)^{-1}$, hence:

$$\small\begin{align}
(\mathbf{T}\mathbf{R}_p\mathbf{R}_y)^{-1} &amp;= \mathbf{R}_y^{T}\mathbf{R}_p^{T}\mathbf{T}^{-1} \\
&amp;= \begin{bmatrix}
\cos{y} &amp; 0 &amp; \sin{y} &amp; 0 \\
0 &amp; 1 &amp; 0 &amp; 0 \\
-\sin{y} &amp; 0 &amp; \cos{y} &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}^T
\begin{bmatrix}
1 &amp; 0 &amp; 0 &amp; 0 \\
0 &amp; \cos{p} &amp; -\sin{p} &amp; 0 \\
0 &amp; \sin{p} &amp; \cos{p} &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}^T
\begin{bmatrix}
1 &amp; 0 &amp; 0 &amp; e_0 \\
0 &amp; 1 &amp; 0 &amp; e_1 \\
0 &amp; 0 &amp; 1 &amp; e_2 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}^{-1} \\
&amp;=
\begin{bmatrix}
\cos{y} &amp; 0 &amp; -\sin{y} &amp; 0\\
0 &amp; 1 &amp; 0 &amp; 0 \\
\sin{y} &amp; 0 &amp; \cos{y} &amp; 0\\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
1 &amp; 0 &amp; 0 &amp; 0\\
0 &amp; \cos{p} &amp; \sin{p} &amp; 0\\
0 &amp; -\sin{p} &amp; \cos{p} &amp; 0\\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
1 &amp; 0 &amp; 0 &amp; -e_0\\
0 &amp; 1 &amp; 0 &amp; -e_1\\
0 &amp; 0 &amp; 1 &amp; -e_2\\
0 &amp; 0 &amp; 0 &amp; 1\\
\end{bmatrix} \\
&amp;=
\begin{bmatrix}
\cos{y} &amp; \sin{p}\sin{y} &amp; -\cos{p}\sin{y} &amp; -e_0\cos{y} - e_1\sin{p}\sin{y} + e_2\cos{p}\sin{y}\\
0 &amp; \cos{p} &amp; \sin{p} &amp; -e_0 \cdot 0 - e_1 \cos{p} - e_2 \sin{p}\\
\sin{y} &amp; -\cos{y}\sin{p} &amp; \cos{p}\cos{y} &amp; -e_0\sin{y} + e_1\cos{y}\sin{p} - e_2\cos{p}\cos{y}\\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\end{align}$$

Every step is double checked using WolframAlpha.

The implementation:

inline Matrix4
FPSViewRH(const Vector3&amp; eyePosition, float yaw, float pitch) noexcept
{
  yaw = Utils::Radians(yaw);
  pitch = Utils::Radians(pitch);

  const auto sinYaw = std::sin(yaw);
  const auto cosYaw = std::cos(yaw);

  const auto sinPitch = std::sin(pitch);
  const auto cosPitch = std::cos(pitch);

  const Vector3 i{cosYaw, sinPitch * sinYaw, -cosPitch * sinYaw};
  const Vector3 j{0, cosPitch, sinPitch};
  const Vector3 k{sinYaw, -cosYaw * sinPitch, cosPitch * cosYaw};

  return {
    {i[0], i[1], i[2], -i.Dot(eyePosition)},
    {j[0], j[1], j[2], -j.Dot(eyePosition)},
    {k[0], k[1], k[2], -k.Dot(eyePosition)},
    {0,    0,    0,    1},
  };
}


It works fine except that the yaw is inverted, i.e. increasing the angle causes the object to go right while it should go left.

I can negate the yaw angle or change every $\sin{y}$ to $-\sin{y}$, but I don't really understand why this is happening?
It's happening because they just happened to define the rotation matrix with counterclockwise rotation direction, which is the common convention for polar$\rightarrow$cartesian coordinate system transformation. If you google for the transformation, you'll see that the angle is universally shown to rotate to the counterclockwise direction like below