2.1 Orthogonal Cameras
In this section, we'll explore orthogonal cameras. Previously, we examined perspective cameras, which emulate real-life pinhole cameras where distant objects appear smaller on screen. This perspective effect mirrors our natural visual experience. In contrast, orthogonal cameras maintain objects' original sizes on screen, regardless of their distance from the camera, eliminating perspective distortion.
Launch Playground - 2_01_orthogonal_camerasOrthogonal cameras prove useful in various scenarios, particularly when creating 2D applications using a 3D API, such as image processing tools. In these cases, we want to avoid image distortion due to perspective effects. Orthogonal projection excels in such situations and is also frequently employed in 45-degree top-view video games.
Let's derive the orthogonal projection matrix. Recall that before projection, we convert the coordinate system to view coordinates. In this system, the xy plane is parallel to the screen plane, with the z-axis pointing towards us.
Imagine a screen-aligned bounding box enclosing the 3D scene. Our projection goal is to map this bounding box to NDC (Normalized Device Coordinates) in the range [-1,-1,-1]
to [1,1,1]
for x, y, and z.
This calculation is simpler than perspective projection. Let the right edge of the screen coordinates be r
and the left edge be l
. Given a point p
at (x,y)
in view coordinates, we have:
\begin{aligned}
& l \leq x \leq r \\
& 0 \leq x \leq r-l \\
& 0 \leq \frac{x-l}{r-l} \leq 1 \\
& 0 \leq 2 \times \frac{x-l}{r-l} \leq 2 \\
& -1 \leq 2 \times \frac{x-l}{r-l} -1 \leq 1
\end{aligned}
We've successfully converted the x-coordinate to the range [-1,1]
. Now, we'll refine the calculation to the form Ax + B
, allowing us to express it as matrix multiplication:
\begin{aligned}
& -1 \leq \frac{2x-2l-r+l}{r-l} \leq 1 \\
& -1 \leq \frac{2x}{r-l} - \frac{r+l}{r-l} \leq 1
\end{aligned}
We can derive similar equations for y
and z
. Note that NDC uses a left-handed coordinate system, so we need to flip the z
axis:
\begin{aligned}
x^\prime &= \frac{2x}{r-l} - \frac{r+l}{r-l} \\
y^\prime &= \frac{2y}{t-b} - \frac{t+b}{t-b} \\
z^\prime &= \frac{-2z}{f-n}-\frac{f+n}{f-n}
\end{aligned}
Where t
and b
are the top and bottom of the screen coordinates, and n
and f
are the near and far plane. Now, we can express these calculations as a matrix multiplication:
\begin{pmatrix}
\frac{2}{r-l} & 0 & 0 & 0 \\
0 & \frac{2}{t-b} & 0 & 0 \\
0 & 0 & \frac{-2}{f-n} & 0 \\
-\frac{r+l}{r-l} & - \frac{t+b}{t-b} & -\frac{f+n}{f-n} & 0
\end{pmatrix}
Implementing an orthogonal camera is straightforward. The shader code and most JavaScript logic remain unchanged, so we'll focus on the key elements:
let orthProjMatrix = glMatrix.mat4.ortho(glMatrix.mat4.create(), -320.0, 320.0, 240.0, -240.0, -1000.0, 1000.0);
The orthogonal projection matrix closely resembles the perspective projection matrix. We can easily generate this projection matrix using the glMatrix library. By specifying the viewport's width and height, along with the near and far planes of the view frustum, we obtain the orthogonal projection matrix.
Unlike perspective projection, the view frustum for orthogonal projection is a simple 3D rectangle rather than a cone. The rest of the code remains identical to the perspective projection program.