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} &= \mathbf{R}_y^{T}\mathbf{R}_p^{T}\mathbf{T}^{-1} \\ &= \begin{bmatrix} \cos{y} & 0 & \sin{y} & 0 \\ 0 & 1 & 0 & 0 \\ -\sin{y} & 0 & \cos{y} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}^T \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos{p} & -\sin{p} & 0 \\ 0 & \sin{p} & \cos{p} & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}^T \begin{bmatrix} 1 & 0 & 0 & e_0 \\ 0 & 1 & 0 & e_1 \\ 0 & 0 & 1 & e_2 \\ 0 & 0 & 0 & 1 \end{bmatrix}^{-1} \\ &= \begin{bmatrix} \cos{y} & 0 & -\sin{y} & 0\\ 0 & 1 & 0 & 0 \\ \sin{y} & 0 & \cos{y} & 0\\ 0 & 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & \cos{p} & \sin{p} & 0\\ 0 & -\sin{p} & \cos{p} & 0\\ 0 & 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & -e_0\\ 0 & 1 & 0 & -e_1\\ 0 & 0 & 1 & -e_2\\ 0 & 0 & 0 & 1\\ \end{bmatrix} \\ &= \begin{bmatrix} \cos{y} & \sin{p}\sin{y} & -\cos{p}\sin{y} & -e_0\cos{y} - e_1\sin{p}\sin{y} + e_2\cos{p}\sin{y}\\ 0 & \cos{p} & \sin{p} & -e_0 \cdot 0 - e_1 \cos{p} - e_2 \sin{p}\\ \sin{y} & -\cos{y}\sin{p} & \cos{p}\cos{y} & -e_0\sin{y} + e_1\cos{y}\sin{p} - e_2\cos{p}\cos{y}\\ 0 & 0 & 0 & 1 \end{bmatrix} \end{align}$$ Every step is double checked using WolframAlpha. The implementation: <!-- language: lang-cpp --> inline Matrix4 FPSViewRH(const Vector3& 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_? or if there is an interpretation for this phenomena?