3D Programming and Simple Camera Movement
A Nice Easy Beginners' Guide with only simple maths
Right, this article stems from a request by a friend who wanted to know
how to control camera movement when doing 3D systems. In fact there are
several ways of controlling the ‘camera’ depending on the effect you wish
to create; it’s a bit like directing a feature-film. Hence most games use
an “in-car” viewpoint, which is slightly different from most demos. However,
most of the mathematics behind this is the same.
Some sort of basic maths knowledge would be very useful here. If you
don’t know about x,y and z axes, matrices or multiplication, stop here,
or write to us and we’ll do another article on the maths. My maths is pretty
poor because I’m not sure when to use matrices, vectors or points.
But the principles behind it are fairly safe.
However, I’ve purposely generalised the maths so it’s not specialised
to people who want to do this kind of thing in assembler. My apologies
for any errors which might creep in: this doc is pretty old and was first
worked out when I was a little boy so it's a bit creaky...
Part One: Basic mathematical principles
(given just so you can understand Part Two!)
3D Point Representation
Any 3D point in our 3D system will of course have 3 co-ordinates, one for
each axis. We shall denote this in the form of a 1x3 matrix:
The x and y coordinates are similar to x and y on your normal 2D screen.
The z distance here denotes distance away from the origin, where a positive
z coordinate is “forwards” and a negative behind the viewer.
P = [px]
3D Point Movement
To move a 3D point, we simply add on the amounts of x,y and z, to our point
P. This simply translates our 3D in the given offsets of x,y and z eg.
A point P, moved by (-30,+60,-90) becomes:
NewP = P + [ -30 ]
[ +60 ]
[ -90 ]
3D Rotation round the origins
To rotate a given point around any one of the x,y or z axes, we multiply
it by a special matrix (the ‘rotation matrix’) To rotate about more than
one axis at once, we can either:
IMPORTANT NOTE: the sequence of rotation round axes IS important e.g. rotating
30 degrees round x, then 40 degrees round y is NOT the same as rotating
40deg round y, then 30 degrees round x.
(a) rotate about axis 1, then take the result and rotate this around axis
(b) combine the two rotation axes by multiplying them together. We then
must only do one matrix multiplication rather than two.
Here are the individual 3x3 matrices for rotation about the x,y and z
Rotation of angle A round X:
Rotation of angle B round Y:
MA= [ 1 0
[ 0 cosA
[ 0 sinA
Rotation of angle C round Z:
MB= [ cosB 0 -sinB
1 0 ]
[ sinB 0
And this is what you get if you calculate MA.MB.MC: (ie. Rotate about Z,
then Y then X):
MC= [ cosC –sinC 0
[ sinC cosC
0 1 ]
MA.MB.MC = [ cosBcosC
+cosAcosC+sinAsinBsinC –sinAcosB ]
+sinAcosC-cosAsinBsinC +cosAcosB ]
..and a point P rotated round these angles becomes:
NewP = MA.MB.MC.P = MA.MB.MC.[ px ]
[ py ]
[ pz ]
(If you don’t understand this fully, don’t worry yet. All could still
be revealed in part two. All you need to know is that you multiply two
matrices to combine two rotations.)
3D Perspectivising to 2D screens
To convert any given point into 3D perspective, we calculate a scaling
value s dependent on the z-coordinate part of the given point (pz). The
usual formula for this is:
so that S decreases as Z (the distance away) increases.
S = 1 / pz
This works if your 3D system is set up so that you want the far distance
(ie the horizon) to tend towards +infinity. If it goes the other way,
So the screen coordinates become:
S = 1
(I've just realised that this is "illegal" in proper maths, but I think
you understand the meaning. Must get round to revising my mathematics knowledge
[sx] = [px] * s
Important Notes for this Model
Both the point rotation and point perspectivisation rely on the idea that
our centre of rotation and the centre for viewpoints (that is, our
camera position) is at coordinate (0,0,0) or the origin O.
(See the picture that is included with this article)
The big problem is that in our 3D world system, we will need to add
some modifications. This is because our centres of rotation will be different
depending on what we must rotate, and our “camera” will appear move about
the 3D world. This is what we must address in part Two.
Part Two: Applying the maths to a 3D world
Now all this maths is quite simple (!) but when it is applied to any 3D
system, we can have problems.
Let’s take a simple 3D system. Our “world” is made up of many “objects”.
Each “object” has a central point (its ‘origin’) about which it is rotated
on its own.
Then all the objects in the world are also rotated, depending on the
angle at which we look at them with our camera.
(look at the article’s picture 2)
The model we use to control the camera and movement depends on how we
want to. We shall look at two models:
Model One: The “Camera-in-object” Model
In this model all the objects rotate about our camera. If we imagine that
our camera is flying through a 3D world just like one of the objects in
it, and rotating, we can build up the maths quite easily from what we already
In fact we only need a few pieces of information:-
(see picture 3)
The object centre and rotation matrix for each object (OC and OR)
The camera centre and rotation matrix (CC and CR)
The first step is to rotate all the object’s coordinates about its centre.
We assume that the object’s centre is 0,0,0 and all the points in the object
are stored as offsets from O, so the coordinates of our rotated object
In our 3D space, we then translate the point so that it is centre around
the object centre OC:
Po = OR.[px]
Now we need to rotate the resulting points around the camera. However the
camera centre is not at (0,0,0), so first we must find the offset of the
new rotated point (Po) from the centre (CC). We then rotate this value
the camera rotation CR. The final object coordinate is then:
Po2 = OR.[px] + OC
We can optimise this calculation quite a lot by using the fact that most
of the calculations here will be used more than once (eg. OC-CC is a constant
for each object), but this is our basic method of calculating a 3D point.
Po3 = rot_round_camera.( offset_from_objpoint_to_camera)
Po3 = CR.( Po2-CC )
= CR. ( OR.[px]
+ OC – CC )
This method works for all cases where our camera is like one of the
objects (e.g. a flight simulator’s cockpit view) What happens if the “universe”
does not rotate about our camera position?
Model Two: The “Camera-point-at” Model
This is the model is similar to the one most often used in demos, probably
because it is quite straightforward to program in its simplest form (ie.
when there is no universe rotation). In demos it is used when just displaying
one object, usually in the centre of the screen.
This model is a very simple extension of the one above. Instead of taking
the CC as the centre of rotation, we chose a point that we want to “focus
on” as the centre of our world, round which all our views rotate. If you
look at Avena’s Fried Bits 3 demo, in the 3D world, this focus point is
usually the little spaceship that is flying around. This point we will
call the Focus. Its coordinate will be FC (focus centre), and our rotation
round it FR (focus rotation).
If we then substitute these values in for OC and OR in the formula above
we will then appear to be “inside” the object we are looking at. What we
want to do instead is pull back some way from the point of interest. We
do this by translating all the rotated points in the z-direction using
a vector such as “FD” (focus distance) in the form
By changing “dist” we can zoom in and out of the action at will too.
FD = [ 0 ] , where “dist”
is the distance away.
[ dist ]
This change is easy to make to our rotation model. The additional translation
In practice this model is very useful for creating 3D animations. To follow
an object which is moving, we set the focus centre to be the same as the
object’s centre, for example. To pan across from one object to another,
we simply take the two objects’ centre points and “morph” between them.
By applying rotation effects too, we can come up with lots of nice tricks
to control animation and movement.
Po3 = rot_round_focus.( offset_from_objpoint_to_focus)
Po3 = FR.( Po2-FC ) + FD
= FR. ( OR.[px]
+ OC – FC ) + FD
Although these are not the only two ways of controlling camera movement
in 3D, they are probably the simplest both to program and understand. Both
have drawbacks, depending on which application you use them for (e.g. how
do I move around the 3D world using the first technique?) and advantages,
but that’s for you to find out if you want to use them...
Zed's excellent document on graphics