// HACKER NEWS — CYBERSECURITY
Divide by depth for instant 3D
When I first started working on games, I used high level frameworks that would give you a Camera that just kind of worked. But as I learned more and wanted to apply more creative techniques, I struggled to even have the vocabulary to search for what I wanted to do, and only after writing lower level graphics code did I understand cameras are based around kind of really simple math.
In the excellent One Formula That Demystifies 3D Graphics (via @tsoding), we’re presented with the following:
In essence, if we say \(y\) is up and \(z\) is forward, 3D coordinates \((x, y, z)\) can be projected into 2D coordinates \((x', y')\) by dividing \(x\) and \(y\) by \(z\). For example, if we have a series of 3D points that only vary in depth, as depth increases, their projected positions get closer to vanishing point \((0,0)\):
This can be demonstrated by a ball that moves and scales with depth as it orbits the camera’s up axis, offset along the \(z\) axis by forward:
Using the same principle, we can even draw more sophisticated “geometry” in the same way!
Obviously, these are very constrained and naive examples that are largely impractical in all but the simplest scenarios. When we do any kind of 3D work, we typically need to involve things like the direction the camera’s pointing in, it’s position, it’s field of view, etc. While we could in theory hack those shaders to support these features, there is a way that’s less effort and more practical. It’s called the perspective projection matrix, and it’s the magic behind the mighty Camera.
There are a few ways to construct a perspective projection matrix, depending on your use case. Computer vision and graphics for example, have slightly different conventions for layout, which is why it’s hard to point to a single Wikipedia article and expect a universal form. That being said, in triangle-based graphics, a common convention that’s often followed involves parameterization of field of view, aspect ratio, and near and far clipping planes. These values are all very important because they also double as a way to easily know what’s in frame and what isn’t, which lets us render our scenes in performant ways, such as through culling off-screen geometry and rendering only what’s visible.
While this varies across different coordinate conventions (little consensus around which axes correspond to up, right, and forward), the general structure is mostly consistent:
This describes a camera with focal scale \(f\) (derived from vertical fov angle \(\theta\)) and aspect ratio \(a\):
Where \(A\) and \(B\) represent depth mapping, derived from near and far clipping planes \(n\) and \(F\) respectively: