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:
 
P = [px]
    [py]
    [pz]
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.

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.
 

Example Data

Here are the individual 3x3 matrices for rotation about the x,y and z
axes:

Rotation of angle A round X:
 

MA= [    1      0      0     ]
    [    0    cosA  -sinA    ]
    [    0    sinA   cosA    ]
Rotation of angle B round Y:
 
MB= [  cosB     0   -sinB    ]
    [    0      1      0     ]
    [  sinB     0    cosB    ]
Rotation of angle C round Z:
 
MC= [  cosC  –sinC     0     ]
    [  sinC   cosC     0     ]
    [    0      0      1     ]
And this is what you get if you calculate MA.MB.MC: (ie. Rotate about Z, then Y then X):
 
MA.MB.MC = [ cosBcosC              -cosBsinC              -sinB     ]
           [ cosAsinC-sinAsinBcosC +cosAcosC+sinAsinBsinC –sinAcosB ]
           [ sinAsinC+cosAsinBcosC +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:
 
S = 1 / pz
so that S decreases as Z (the distance away) increases.
 

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,
 

           S = 1 / -pz.
So the screen coordinates become:
 
[sx] = [px] * s
[sy]   [py]
(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 some time.)

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 know.

In fact we only need a few pieces of information:-
 

(see picture 3)

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 will become:
 

      Po = OR.[px]
              [py]
              [pz]
In our 3D space, we then translate the point so that it is centre around the object centre OC:
 
 Po2 = OR.[px] + OC
          [py]
          [pz]
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:
      Po3 = rot_round_camera.( offset_from_objpoint_to_camera)
      Po3 = CR.( Po2-CC )
          = CR. ( OR.[px] + OC – CC )
                     [py]
                     [pz]
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.

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
 

    FD = [   0  ]  , where “dist” is the distance away.
         [   0  ]
         [ dist ]
By changing “dist” we can zoom in and out of the action at will too.

This change is easy to make to our rotation model. The additional translation gives us:
 

      Po3 = rot_round_focus.( offset_from_objpoint_to_focus)
                  + focus_distance
      Po3 = FR.( Po2-FC ) + FD
          = FR. ( OR.[px] + OC – FC ) + FD
                     [py]
                     [pz]
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.

Conclusion

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...

tat
19/4/97

References

Zed's excellent document on graphics
 
 
 
Page maintained by Steven Tattersall