Step III: The Projection Plane
INTRODUCTION:
The projection plane (or view plane, or viewing plane) is a flat surface in
front of the camera (or player if you prefer) where images are
projected. The plane usually has dimensions equal to that of the physical
screen, but it can be any size. The camera is situated at a certain distance
behind the plane, which is called it's focal-distance.
The further you look into the distance, the wider your horizon, and thus you
can see more objects (although they'll be smaller, obviously). This area can
can be represented as a pyramid, imaginatively called the projection
pyramid. To make things clearer, take a look at the diagram below:

fig6: The projection pyramid
The above shows a plane that has dimensions of 320x200 units (for
convenience, 1 unit will be equal to 1 pixel) which coincides
with the dimensions of a commonly used VGA mode. The angle marked alpha
is the horizontal field-of-view (or FOV), which determines how much can
be seen. There is no need for a vertical FOV because everything is scaled
according to the horizontal FOV.
Humans have a FOV (both horizontal and vertical) of about 90°, which does
not look right when used for a raycaster. Through trial-and-error, I've found
that the best-looking FOV to use is 60°. So, the angle alpha,
above, will have a value of 60° and the rest can be determined by using
simple trigonometry.
FINDING THE FOCAL-DISTANCE:
The focal-distance is used for scaling, and only needs to be calculated
every time the FOV or plane width changes, which means that once calculated,
it can be stored in a variable until the FOV or plane-width is modified again.
The focal-distance value is used extensively by the engine, so it doesn't pay
to recalculate everytime it's needed; a memory access is a lot quicker.
Here is a 2D drawing of the overhead of the view pyramid. It can be split
into two identical right-angled triangles, as shown in fig7:

fig7: 2D overhead view of the projection pyramid
The length we need to find (the focal-distance) is the one labelled
dist. The width is the width of the projection plane, and
alpha is it's FOV. Taking away the triangle that we're not working on,
we are left with this:

fig8: The triangle for finding the focal-distance
All values are divided by 2 (except dist, obviously) because the two
parts of the full view-triangle were identical. So, to find a value for
dist, we first decide whether to use sine, cosine or tangent;
Pythagoras' theorem can't be used because we only know one length, which is
width / 2.
We use tangent because we want to find adj (which equates to dist
in our calculations), and we only know opp (which is width / 2);
we don't know hyp, which would be needed for sine and cosine. Here's
the equation for finding dist, and where it's derived from:
A few variables: |
alpha = fov / 2, | Using these names makes
opp = width / 2, | everything clearer/shorter
adj = dist |
We start with:
opp | This is the standard
TAN(alpha) = --- | equation for tangent
adj |
Canceling out 'adj' (multiplying both sides by it), we get:
TAN(alpha) * adj = opp | Multiply both sides by 'adj'
But we already know 'opp', so make 'adj' the subject (divide by TAN(alpha)):
opp | The final equation with
adj = ---------- | 'adj' as it's subject
TAN(alpha) |
So there we have it, we've found the formula that calculates adj which
is 'dist', aka the focal-distance. Now we simply have to plug our
values into it, like this:
We start with the core equation:
width / 2
dist = ------------
TAN(FOV / 2)
Now we substitute in the variables' values (from the above diagrams):
320 / 2 = 160
dist = ----------------
TAN(60 / 2 = 30)
= 277.128 (or something close to it, at least)
dist = 277 units
At this stage we've determined that the projection plane is 277 units from the
camera when using a FOV of 60° and a width of 320 units.
We also need to calculate the angle between subsequent rays, which is
just a term to make me sound clever :) Not really, but all it means is how
many degrees there are in each column of the projection plane, recalling that
a ray needs to be cast for every column of the projection plane. Since each
column is equal to 1 unit, then it's easy. If you haven't worked it
out by now (or haven't understood what the hell I'm on about), then here's how
to do it:
FOV
degrees_per_column = ----------------------
projection_plane_width
And using the values from above, that is:
60
degrees_per_column = ---
320
= 0.1875
Since I said that 1 unit would be 1 pixel in this documentation,
and also that the projection plane would be the same size as the physical
screen, that means that every pixel of every row is worth 0.1875°; a full
row would be the FOV (60°). Store this value in a variable also, as
it's used quite frequently, and a divide is by far the most expensive
arithmetic operation a computer can do.
CONCLUSION:
In case you're interested, or perhaps lazy, here's a
C code listing of a function that can calculate
the focal-distance and angle between subsequent rays. It's not
optimized in any way, and it uses floating point variables (whereas you may
wish to use fixed-point if you've got an old machine; more on that later).
There, the first piece of mathematics, and the first piece of code; you can't
say that it wasn't easy, can you ? Anyway, the next step will be the
part where trigonometry is used the most in the engine. It takes you through
finding walls in the raycasting environment [grin].
NEXT PAGE
|
PREVIOUS PAGE
|
|