Viewing Systems For 3D Engines by Tom Hammersley

*Note* A correction to this article can be found at the bottom of this
document.

---------------------------------------------------------------------------

Introduction

OK, so perhaps you have an engine running that has a duck, rotating in the
middle of the screen. Very nice, but not much use for doing 'real' things
with. You need a camera. You need to be able to walk around, to view the
duck at different angles, to zoom in. You need a proper viewing system.
---------------------------------------------------------------------------

The XYZ Rotation Angle System

So you think, I know, I'll make a system where my camera has 3 angles, X, Y
and Z rotation. Then I just add on its position. So you build a matrix,
apply that transformation to a model, then put it into camera space. It
seems to work well... but it's rather limited. Specifying an orientation in
terms of X Y and Z angles is tricky, and can cause problems. For example,
once you start rotating around a little, a rotation in the X axis may not
have yield the results you expected. You may also experience "Gimbal Lock",
where rotations can cancel each other out, and so on. In short, this system
is crap.

---------------------------------------------------------------------------

The UVN Vectors System

This is quite a good system. It works by defining 3 vectors, U, V and N.
These vectors are right, up, and viewing direction, respectively. If you
take your left hand, point your index finger forwards, stick your thumb up
to the sky, and point your middle finger to the right, then your middle
finger is U, your thumb is V, and your index finger is N. Imagine that
these vectors orientate the viewing system. So that to rotate your 'head'
to the left, you would rotate about the V vector, to roll, you would rotate
about N, and so on. Also needed to use this system is an origin, the point
of the camera. To use this system, you will need to build a viewing matrix.
This is calculated by multiplying together two matrices. The system is
given by:

Translation matrix =

| 1  0  0  0 |

| 0  1  0  0 |

| 0  0  1  0 |

| -x -y -z 0 |

Rotation matrix =

| Ux Vx Nx 0 |

| Uy Vy Ny 0 |

| Uz Vz Nz 0 |

|  0  0  0 1 |

CameraMatrix = Translation*Rotation

N can also be calculated as:

a = azimuth angle

e = elevation angle

Nx = sin(e)*cos(a)

Ny = sin(e)*sin(a)

Nz = cos(e)

To point at an arbitrary position, you will then need to define N as the
unit vector between the camera and the point. U and V will be guessed at,
and adjusted. To adjust the vector, simply do:

V = V' - (V'*N)*N

Where V' is your guess at V. U is the cross product of N and V.

---------------------------------------------------------------------------

Two Points And A Twist

This is another useful system. The camera is defined at one point, and it
has a focus point. A twist angle is given, which is the angle about F - C
(focus - camera). To build the matrix for this system, you'll need to do
the following:

a, b, c = Normalized direction XYZ

e, f, g = Camera point XYZ

a = twist angle



     |  cos(a)   sin(a)  0  0 |

V1 = | -sin(a)   cos(a)  0  0 |

     |       0        0  1  0 |

     |       0        0  0  1 |

     |       b             -a                |

     | -------------  -------------    a   0 |

     | (1 - c^2)^1/2  (1 - c^2)^1/2          |

     |                                       |

     |      -ac            -bc               |

V2 = | -------------  -------------    b   0 |

     | (1 - c^2)^1/2  (1 - c^2)^1/2          |

     |                                       |

     |       0        (1 - c^2)^1/2    c   0 |

     |       0              0          0   1 |

     | 1  0  0  0 |

V3 = | 0  1  0  0 |

     | 0  0  1  0 |

     | -e -f -g 1 |

Tview = V1*V2*V3

Watch out for when c^2 is 1. Then you get (1 - 1)^1/2, which is zero - an
exception. This'll need a special case.

Understanding How The Camera Model Works

I've had a few people talking to me on IRC, with difficulty understanding
how this system works. Well, I'll give you a full explanation, by breaking
it all down into small pieces, and re-assembling it into a way you can
understand.

Part #1: UVN Vectors

This part alone has caused quite a lot of confusion. In short, UV and N are
3 vectors that are used to orientate the XY and Z values of your points. U
is for the X axis, V is for the Y axis, N is for the Z axis.

Now, we all may go around, merrily saying that a point is at (1, 2, 3). But
what do we really mean when we say this? Simple. The point is 1 unit from
the origin in the X AXIS, the point is 2 units from the origin in the
Y AXIS, and the point is 3 units from the origin in the Z AXIS. Why have I
emphasised the term axis? Because that is the key to understanding the
rotation.

When I say "X axis", what does that mean? Well, an axis can be considered
as a unit vector - a direction. An axis is infinite is usually infinite in
each direction. The X axis has the value (1, 0, 0). Now, imagine that to
get a points X co-ordinate in camera space, we have to map a point onto the
X axis. We would end up with something like:

NewPoint.X = XAxis.x*Point.x + XAxis.y*Point.y + XAxis.z*Point.z

Which simplfies down to:

NewPoint.X = 1*Point.x + 0*Point.y + 0*Point.z

Can you see what has occured? We don't just take the X value, we take the
distance from the origin along the X axis. Now, as the X axis can be
orientated in an arbitrary manner, then as the axis rotates, the point
takes on new values: XY and Z are being combined in different ratios.

Recall that we have similar vectors from V and N - the Y and Z axes. Again,
a similar approach is taken to them: not simply taking the Y or
Z co-ordinate, but taking the distance from the origin along an axis. It is
fundamental that you understand that part.

Now, UV and N are always perpendicular to each other, ie they will form the
corner of a cube, regardless of rotation, the angles between each other
will remain the same; just the orientation changes. To visualise this, take
your left hand. Point out your index finger, stick your thumb upwards to
the sky, and stick your middle finger out to the right. Your index finger
is N, your thumb V, and your middle finger U. Rotate your hand a bit. As
you can see, the vectors rotate around, changing the rotation of the
camera, but still remain at the same angle to each other.

Camera Position

Camera position has also given a little trouble. What you have to remember
is that camera position is specified in world co-ordinates, and when we
perform the translation, we map the world back to the camera, not map the
camera into the world. So, when we translate, the world will be moved
towards the camera. To do that, we need to translate by a negative vector.
And that vector is the camera position. Going back to my "hand" metaphor,
imagine that the position of your hand is the position of the camera

Space, (0, 0, 0), And Other Such Things

Consider what happens when we apply -camera.pos to every co-ordinate in the
space. They all get translated by the same amount, including the camera,
which gets placed at (0, 0, 0) -- the origin. So, you can think of the
camera position as being the origin of the world. However world space
co-ordinates are not defined relative to that point, they are defined
relative to (0, 0, 0) (NOT THE CAMERA POINT MIND!). So, the translation by
-camera.pos moves the co-ordinates to be relative to the camera; in fact,
you could make any point the centre of the world using such a system.

Also, consider what the rotation is doing. Try to think not so much of the
camera itself rotating; rather the world surrounding it rotating, being
backward mapped into the universe. IE we don't take the horse to market, we
bring the market to the horse.

I hope this explains it clearly enough for you; bear in mind though that
I can't put the thoughts directly into your brain, you have to work out the
bits inbetween for yourself!

Tom Hammersley, tomh@globalnet.co.uk

This information was derived from 3D Computer Graphics, by Alan Watt

---------------------------------------------------------------------------
Correction:

Visit the following document :
http://www.tc.cornell.edu/Visualization/Education/cs417/

They are the ones that posted the sheet. I have tried to contact Alan Watt
at the University of Sheffield but to no avail - I can't find his email
address to ask him specific questions about the matrix in question. 

The article Tom posted contains information from pages 61-63 of "3d
computer graphics by Alan Watt" - and the matrix on p62 which is in Tom's
article is incorrect. I have run it by several people I used to work with
( all in the computer graphics industry ) and have tried several ways to
prove it myself - no one could come up with the same matrix. 
If this matrix truely represented a "rotation" then it would be
orthonormal and the cross product of any two column vectors would yeild
the third column vector of the matrix. The matrix on p.62 of "3d
computer graphics by Alan Watt" which appears in Tom's article does not
adhear to this property therefore does not represent a rotation and is
incorrect. I have looked for a possible answer to this matrix presented on
p.62 for the last year wondering if there was something perhaps I was
missing but after taking it to several people, looking in several computer
graphics and mathematics books, and trying to prove it to myself - I have
come to the conclusion it is wrong - the final blow came when someone on
the usenet told me about the erata sheet at cornell - once I saw that, it
put the nail in the coffin - and ended my doubt. I just wonder how
such a major mistake made it into a book - which is why I kept trying to
figure it out for so long. 

I'm posting this because I don't want anyone to go through the frustration
that I have gone through trying to prove the stupid thing. Conclusion -
books aren't perfect. Oh well.

I hope this helps,
Don ;)

--------------------------------------------------------------------------

Corrections from the book 3D Computer Graphics, by Alan Watt

Errata for Watt, "3D Computer Graphics"
Second Edition, Addison Wesley

The bulleted numbers refer to page number.

18
    The first equation on the page has two mistakes. V^2 should read
    |V|^2. Also VW should read V dot W.

60
    The third row, second column entry of T_view should be sin(phi)
    not sin(theta).

62
    The first 4x4 matrix is incorrect. It is not orthonormal and thus
    cannot be the product of two rotations.

72
    The second constraint in the middle of the page should read:
    "Normalizing the range of zs values so that the range of
    d<=zv<=f maps into the range 0<=zs<=1."

73
    Matrix equation (3.1) has an incorrect last COLUMN.
    It should read [0,0,1,0].

100
    H=(L+V)/2 should read H=norm(L+V).

116
    Equation (4.8) should have a set of brackets so that the "1/2"
    multiplies the entire expression.
117
    Figure 4.27 is confusing at best. I think that the N vector should
    be H and the R vector should be V.

118
    The third equation on the page gives mu as a function of Fo. The
    mu should be eta, the index of refraction. The equation
    is just a rearranged version of the one above it.

118
    The second numbered bullet should read: "These values of eta ... "

120
    Note that in the code the index of refraction is refered to as
    "mu".

130
    In figure 5.4 the notation "Nt dot (P(t)-X)<0 implies S in
    inside" should read "F is inside".

138
    In Equation (5.2), the last "y2" in the equation for Nb should
    be "ys". The "Ns" on the right of the equation for Ns should
    be "Na".

187
    In Figure 6.21 the parametric directions u and v are reversed. 

----------------------------------------------------------------------

Discuss this article in the forums


Date this article was posted to GameDev.net: 7/16/1999
(Note that this date does not necessarily correspond to the date the article was written)

See Also:
Matrices

© 1999-2011 Gamedev.net. All rights reserved. Terms of Use Privacy Policy
Comments? Questions? Feedback? Click here!