3
$\begingroup$

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:

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?

$\endgroup$
1
$\begingroup$

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

enter image description here

$\endgroup$
  • $\begingroup$ Only the yaw is inverted, the pitch works as expected. $\endgroup$ – user5488 Nov 16 '16 at 20:41
  • $\begingroup$ Are you saying that the rotation doesn't happen to the counterclockwise direction with increasing angles in your coordinate system? $\endgroup$ – JarkkoL Nov 16 '16 at 20:55
  • $\begingroup$ It is counterclockwise on the Y axis (the yaw), i.e. increasing the angle (or looking right) causes the fixed object the camera is looking at to go right, but clockwise on the X axis (the pitch), increasing the angle (looking up) causes the object to go down as expected. $\endgroup$ – user5488 Nov 16 '16 at 21:09
  • $\begingroup$ What's the coordinate system you are using (x=right, etc)? $\endgroup$ – JarkkoL Nov 17 '16 at 22:18
  • $\begingroup$ Right handed system with +x is right, +y is up $\endgroup$ – user5488 Nov 17 '16 at 22:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.