```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!