The purpose of this tutorial is to show an alternative to representing 3D environments in Flash. The method that is most popular and easiest to do is rotating about the x-, y-, and z-axes. The equations for these operations can be derived in a multitude of ways, but this tutorial will assume you already know how to use them. However, the equations will be used very little in this tutorial because they are not all that important in what we will be covering. What is a Camera? For this tutorial a camera is going to be a viewing system to see your 3D environment through. You would specify the camera's position and orientation (direction it is looking and 'spin' of the camera), and from that you would derive a rotation matrix that would transform the points in your environment to their position how they appear to the camera. The concept of a matrix and rotation matrix will be developed later in this tutorial. By the end of this tutorial you will be able to see what the box in the picture below looks like to the camera. |
|
| Why is a Camera better than doing Axis Rotations? Using a camera in a 3D environment is magnitudes more powerful than rotating about the coordinate axes. Using a camera adds flexibility to navigating a 3D world. When using a camera you would keep the position of all the points in your environment fixed and simply move the camera through the world. While moving in a straight line you could easily rotate the camera around to see how your world looks from different positions, or you could simulate a 1st person perspective by moving the camera in the direction it is facing. These are all very difficult tasks to complete by rotating a world about the x-, y-, and z-axis, if not impossible. Rotation about the Coordinate Axes and an Arbitrary Axis Although not the focus of this tutorial, and not even used very much, the equations for rotations around axes should be shown. The derivations and thought process of the equations has been left out since this is simply background information. Rotations around the coordinate axes are the easiest. They can be derived using the sum identity for sine and cosine. Given the ordered triplet (x, y, z) and a rotation angle of q, the rotated ordered triplet (x', y', z') can be found with the following equations: Rotation about the x-axisAn important property to take note of is that a rotation around a certain axis does not affect the value of the axis' coordinate. For example, you rotate around the x-axis but the x-coordinate was not affected. Same goes for the y- and z-axis. This has to do with the fact that the axis at which you rotate about is an eigenvector of the rotation matrix formed. An eigenvector is a vector associated with a square matrix that when multiplied with the matrix it does not change in direction, but only in magnitude (and sometimes not even magnitude). The notion of an eigenvector will not be discussed in this tutorial, but it is still a very important and interesting subject if you wish to explore it on your own. A much more useful method for rotation is the rotation about an arbitrary axis. What if you wanted to rotate around the axis that points from (0, 0, 0) to (2, 1, 3) rather than the coordinate axes. We are going to write the equation in its vector form first. We define x to be the current position of the point to be rotated, a to be the axis the point will rotate about, q to be the angle of rotation, and x' to be the rotated point. The three quantities x, x', and a are all vectors. For the equation to work a must also be a unit vector. If you are unsure of the terminology being used make sure to read the vector tutorial on this site first. x' = p cos q + (a ´ p) sin q + a (a · p) (1 - cos q)Although quit a long equation it can be implemented easily. Remember that the ´ operator is the cross product and it returns a vector, and the · operator is the dot product and it returns a scalar. Later on we will organize these messy equations into simple rotation matrices. Linear Algebra By far the most important subject when studying 3D is linear algebra. Linear algebra is most likely called 'linear' because the entire subject starts off with a systematic way of solving linear systems of equations. When looking to organize many equations containing many unknowns, brilliant mathematicians put the coefficients of the equations in one matrix, the variables in another matrix, and the solution to the equations in yet another matrix. You were then left with one equation that simply had matrices in it, which is just another mathematical object like a vector or scalar. The problem seemed less intimidating now and thus flourished linear algebra. Of course the once-upon-a-time connotation is not fully accurate, but ultimately the subject came about when mathematicians were faced with solving systems of linear equations. Matrices We have already learned of one mathematical object used in linear algebra: the vector. The next important object is the matrix. A matrix is a set of numbers arranged in a rectangular array. A matrix is two dimensional because it has rows and columns. The only size matrix we will be using is three by three and three by one matrices. They look something like this: / e11 e12 e13 \
M = | e21 e22 e23 |
\ e31 e32 e33 /
/ e11 \
M = | e21 |
\ e31 /
The notation of a matrix for us will be an upper-case bold letter, whereas
a vector was a lower-case bold letter, and a scalar was a lower-case italic
letter. To reference an element in a matrix we will use the notation 'e12'
meaning the element in the 1st row and 2nd column.There are only a few operations that we will be concerned with that can be done to matrices: multiplication, inversion, and transposition. Multiplication and transposition will be covered now, but inversion will be covered later. Let us first deal with multiplication because that is what will be used the most. There are three types of multiplication that we are going to deal with. Multiplying a matrix with a scalar, multiplying a matrix with a vector, and multiplying two matrices. Multiplying a matrix with a scalar is by far the easiest operation. You simply multiply every element in the matrix with the scalar. / e11 e12 e13 \
M = | e21 e22 e23 |
\ e31 e32 e33 /
/ e11 e12 e13 \ / s*e11 s*e12 s*e13 \
Multiplying a matrix and a vector together is a little bit trickier. Although
matrix-vector multiplication are not exactly defined, we can imagine that
the vector is simply a three by one matrix. Also, the product of a matrix
and vector is another vector, or three by one matrix depending on how you
look at it. The first thing to do is write out the problem:
/ m11 m12 m13 \
M = | m21 m22 m23 |
\ m31 m32 m33 /
/ v11 \
V = | v21 |
\ v31 /
To find the resulting vector from the above multiplication you multiply
the column matrix (the vector) with every row of the three by three matrix.
When you multiply the vector with the first row of the three by three matrix
you get the first element of the resulting vector, when you multiply the
vector with the second row you get the second element, and so on. Performing
the multiplication above gives you the following vector:
/ v11 * m11 + v21 * m12 + v31 * m13 \
M V = | v11 * m21 + v21 * m22 + v31 * m23 |
\ v11 * m31 + v21 * m32 + v31 * m33 /
The same thing can be done with two dimensional vectors and two by two matrices.
/ m11 m12 \
M = \ m21 m22 /
/ v11 \
V = \ v21 /
Multiply two matrices together is even trickier. To multiply matrix A
and B together you must multiply every row of A with every
column of B. The product of two 3x3 matrices is another 3x3 matrix,
and the product of two 2x2 matrices is another 2x2 matrix. To drive this
home in the simplest way here is how you would multiply two 2x2 matrices:
/ a11 a12 \
A = \ a21 a22 /
/ b11 b12 \
B = \ b21 b22 /
/ b11*a11 + b21*a12 b12*a11 + b22*a12 \
AB = \ b11*a21 + b21*a22 b12*a21 + b22*a22 /
The best way to remember this is to treat B like a vector. If you
simply neglect the second column and only look at the first (a vector since
it is only a column matrix) then the first column of the product is the
same as if you were multiplying a matrix and a vector together. Once you
have the first column of the product matrix you can find the second column
by neglecting the first column of B and only looking at the second
(once again a vector). Multiplying A with that vector will give you
the second column of the product matrix, and then you are done.Multiplying two 3x3 matrices is the same except now you have to do the vector multiplication method three times, once for each column. Because there are so many elements to multiply for the product matrix each element of the product is going to be referenced as AB.e11, AB.e12, and so on. The general product matrix looks like this: / a11 a12 a13 \ A = | a21 a22 a23 |That may seem somewhat cumbersome to memorize so I would not even recommend it. You can always reference this page or anything else so just know what matrix multiplication is, and what dimension matrices are formed from multiplying a matrix with a scalar, vector, or another matrix. The transposition of a 3x3 matrix results in a matrix with the exact same dimensions and elements except with a permutation of the elements. Basically, you switch the eij (where i and j can be any number within the dimensions of the matrix) with the eji element. For example, in a 2x2 matrix the e11 and e22 elements stay the same (since i = j), but the e12 element is switched to e21 and vice versa. / m11 m12 \ M = \ m21 m22 /Take note that the transposition matrix is denoted with a superscript T. The transpose of a 3x3 matrix is nearly the same: / m11 m12 m13 \
M = | m21 m22 m23 |
\ m31 m32 m33 /
Transposition is a very simple operation and will be very powerful later
on.Special Types of Matrices If you were to multiply two matrices, A and B, together and the product was A, B would be called an identity matrix. An identity matrix is a matrix that does not change another matrix when they are multiplied together. Such a matrix is always denoted with I and looks like this: / 1 0 0 \ I = | 0 1 0 |And you can do away with the third row and column to get the 2x2 identity matrix equivalent. To show that the above is really the identity matrix we can multiply it will a general 3x3 matrix: / a11 a12 a13 \ A = | a21 a22 a23 |Before we go on to another type of special matrix we are going to cover inversion of matrices briefly. Inverses of matrices is a very important operation in linear algebra. The reason why we are only briefly covering them will be known in a moment. If you had a matrix, named A, the inverse of A would be such that when you multiplied the two together the product would be the identity matrix. Like this: A-1 A = ITake note that the inverse matrix is denoted with a superscript negative one. We are not going to discuss all the general methods of solving such a problem because that could easily add another fifty pages to this simple tutorial. However, we are going to find a way to get the inverse of a special type of matrices with a very easy operation soon. The next special type of matrix we are going to look at are orthonormal matrices. To show what an orthonormal matrix is we are going to first associate each row of a matrix with a vector. Therefore, a 2x2 matrix is made up of two vectors and a 3x3 matrix is made up of three vectors: a = < a1, a1, a3 >
b = < b1, b2, b3 >
c = < c1, c2, c3 >
/ a1 a2 a3 \
M = | b1 b2 b3 |
\ c1 c2 c3 /
Given the above vectors and matrix, M can only be an orthonormal
matrix if a, b, and c are unit vectors and if the dot
product of each vector with each other vector is zero. Remember that zero
for a dot product meant that the two vectors were perpendicular. Therefore
an orthonormal matrix also means that the vectors a, b, and
c are unit vectors and perpendicular. Also know that if we took the
vectors a, b, and c to be the columns of the matrix
rather than the rows, the test for whether a matrix was orthonormal or not
would still hold, as will be shown now.A very important property of orthonormal matrices is that their transpose is equal to their inverse. Meaning that you can find the inverse of an orthonormal matrix by simply taking its transpose. MT = M-1Usually inverting a matrix is a slow, CPU-intensive computation, but transposition is easily done and rather fast. The inverse of an orthonormal matrix is yet another orthonormal matrix. This is why it does not matter if you use the vectors as the rows or columns and the test for an orthonormal matrix still holds. Another important property of orthonoraml matrices that the product of any two orthonormal matrices is another orthonormal matrix. This simple property will actually help you save CPU calculations, as you will see in the next section on rotation matrices. Rotation Matrices A rotation matrix is simply another name for an orthonormal matrix. If you multiply a vector (column matrix) by an orthonormal matrix you will perform some type of rotation on the vector (except for the trivial case of the identity matrix which does not perform any transformation). The very important link between why a rotation matrix and an orthonormal matrix are the same will be shown later. For right now we are going to simply convert the equations that we came up with before for rotating a point around the x-, y-, and z-axis and an arbitrary axis into rotation matrices. Let us first start with a general rotation matrix and vector and see if we can find the appropriate values: / r11 r12 r13 \
R = | r21 r22 r23 |
\ r31 r32 r33 /
v = < v1, v2, v3 >
Let us quickly look back at what the equations looked like for a rotation
around the x-axis and see if we can find the values of the rotation matrix:
Rotation about the x-axisBy looking at the above equations it would seem that the first row of the rotation matrix would be similar to the identity matrix since the x-component of the vector is unchanged. In fact, the first column would be part of the identity matrix too because the x-component does not show up anywhere in the calculation of the y- and z-component of the rotation vector. Then, only four elements of the 3x3 matrix are left to speculation, but those can been easily shown to come out like this: / 1 0 0 \
Rx = | 0 cos q -sin q |
\ 0 sin q cos q /
Multiply the above with vector v gives you the following (to make
it easier to read the vector is represented as a column matrix):
/ x \
v' = Rx v = | y cos q - z sin q |
\ y sin q + z cos q /
Without discussing them as much as the x-axis rotation matrix, the rotation
matrices for the y- and z-axis can be expressed as follows:
/ cos q 0 sin q \
Ry = | 0 1 0 |
\ -sin q 0 cos q /
/ cos q -sin q 0 \
Rz = | sin q cos q 0 |
\ 0 0 1 /
It is slightly harder to come up with a rotation matrix for an arbitrary
axis so it will not be complete shown. In fact, it takes a few 'far from
common sense' steps to arrive at the matrix. For example, someone had the
cleverness to substitute a cross product with a skew-symmetric matrix (a
skew-symmetric matrix is one in which its transpose is equal to itself multiplied
by the scalar negative one). The matrix looks like this (q
is the rotation angle and a is the axis of rotation):
c = cos q s = sin q t = 1 - cos qNow, from what we know about orthonormal matrices, their properties, and their relationship to rotation matrices, we can now discuss some very useful applications to three dimensional programming. Let us say you have a rotation matrix for rotations about the x-axis. Every frame you multiply a point's position by this matrix, you update the position of the point, and you render it on the screen. What would happen if you rotated by an q, and then you want to undo that angle by rotating back to your old position? Your first instinct may be to simply construct a new rotation matrix with a negative q and then multiply point with that matrix. However, if you could find an inverse of the rotation matrix, a multiplication of that matrix with the point's position would simply undo the rotation and put it back in its original position (since a matrix and its inverse multiplied together produce an identity matrix). Then from what you know about orthonormal matrices you can easily find the inverse matrix without doing any addition sine or cosine calculations. The inverse of the four rotation matrices above are: / 1 0 0 \
RxT = | 0 cos q sin q |
\ 0 -sin q cos q /
/ cos q 0 -sin q \
RyT = | 0 1 0 |
\ sin q 0 cos q /
/ cos q sin q 0 \
RzT = | -sin q cos q 0 |
\ 0 0 1 /
/ tx2 + c txy + sz txz - sy \
RaT = | txy - sz ty2 + c tyz + sx |
\ txz + sy tyz - sx tz2 + c /
Notice that the inverse of the rotation matrices only differ by a sign
change here and there from their original form. i j
/ 1 0 \
S = \ 0 1 /
Let us say we wanted to define a coordinate system that differed a little
from the standard basis. The x-axis vector will now be <2, 1> and
the y-axis will be <0, 3>. This new basis would look like this as
a matrix:
/ 2 0 \ B = \ 1 3 /And that is all there is to constructing a basis. You can do the same for three dimensions. This is what the standard basis looks like for three axes: i j k
/ 1 0 0 \
S = | 0 1 0 |
\ 0 0 1 /
It is also useful to visualize the different coordinate systems. |
|
|
|
The white lines represents the standard basis while the blue lines represents
some arbitrary basis. If you were to print that picture out and plot a
point at (2, 1) relative to the white lines it would approximately be
the equivalent to the point (1.2, .1) relative to the blue lines. This
brings up an important question: how can we find the position of a point
in one coordinate system relative to another coordinate system? This is
the fundamental problem that we will use bases to solve. |
|
|
| Looking at those two coordinate systems we could say that
a point at (1, 1) in the rotated basis (blue) is approximately (.3, 1.4).
Well, it can now be said that the approximation we just made is in fact
an approximation of where a point at (1, 1) in the standard basis will be
when rotated by an angle of q about the origin.
This is because we could say that the blue and white coordinate systems
start of lined up (q = 0). At this moment in
time we plot a point at (1, 1) on the blue coordinate system. Then then
twist the blue coordinate system so that it differs with the white by an
angle of q. When this is done the point stays
plotted relative to the blue axes, which means it rotates too. Finally,
we mark where the point falls on the white coordinate system. If we can
find the position of that mark then we have found the position of (1, 1)
when rotated by an angle of q about the origin;
that is what our approximation did. Now, how can we come up with a general method of finding the coordinate of a point in the standard basis from knowing its position in an arbitrary basis (since we see that it can be very useful)? This is the rather easy part. Simply write out the matrix form of the basis and multiply the position of the point in that basis with the matrix. That will give you the point in the standard basis. For example, let us take the basis that we were dealing with before. We will call the x-axis vector v, where v = <2, 1>, and call the y-axis vector w, where w = <0, 3>. What would the position of the point (4, 2) relative to this new basis be in the standar basis? Here is the work (B is the basis matrix, p is the vector position of the point in B, and p' is the vector position of the point in the standard basis, S): v w
/ 2 0 \
B = \ 1 3 /
Now the basis just shown is not very useful because such a skewed arbitrary
matrix does not represent all that much. The bases we will be most concerned
with are going to be ones that differ from the standard basis by an angle
of q like shown before. For these types of bases
to work you must maintain two important properties of the vectors used:
the vectors of the axes must be unit vectors and all the vectors must be
orthogonal. In short, the basis matrix must be an orthonormal matrix. We can come up with such a basis in two dimensions easily by remembering that the x-component of a unit vector is the cosine of the angle of the vector, and that the y-component of a unit vector is the sine of the angle. This means that already we know the x-axis vector of our new basis: v = < cos q, sin q >. To get a vector that is perpendicular to that vector we just remember a simple rule from algebra. The slope of a line is the change in y divided by the change in x: m = y / x. To get the value of a slope perpendicular to that you take the reciprocal (swap the numerator and denominator) and multiply the numerator by negative one: m^ = -x / y. We can use this same concept to construct and orthogonal vector. Here y is sin q and x is cos q, therefore the perpendicular vector, and happens to be the y-axis of the coordinate system, is: w = <-sin q, cos q>. Finally, the basis of the rotated coordinate system is: / cos q -sin q \ B = \ sin q cos q /Now, if you know a point in the basis B, and you want to find its position in the standard basis, you can multiply it by that matrix. Or, in less mathematical terms, to rotate a point by an angle of q multiply it with the above matrix. Also, if you look closely you will see the above matrix is the exact same as the rotation matrix for about the z-axis. In fact, all the rotation matrices shown earlier are simply bases, each one differing from the standard basis by a mere angle. Before, you thought of it as rotating a point about the different axes with a few equations; now you can think of it as finding the position of a point in the standard basis from its position in a rotated coordinate system. Application to the Camera It is now time to relate the massive amount of information to what we wanted to do originally: develop a camera in Flash. In terms of what we have learned so far, what would best represent a camera? The answer is a basis. A camera is a coordinate system all of its own, where each axis is perpendicular to each other. It has an axis shooting out of the lens, an axis coming out of the top, and an axis out to the side. We are going to give some names to these vectors that will be used from now on: the axis coming out of the side of the camera is going to be the side vector, the vector coming out of the top is going to be the up vector, and the one pointing in the direction the camera is facing is going to be the out vector. Remember that all the axes must be unit vectors. |
|
|
| With some careful thought you can see that it takes really
only two vectors to define a camera. One that points in the direction that
the camera is looking, and another perpendicular to it to show its orientation
around the out vector. If you only had the out vector then
you would have an infinite number of orientations for the camera; you could
simply 'spin' the camera about the out axis. That is what the side
or up vector is for. You do not need both to completely define the
camera, but you do need all three vectors to define the basis of the camera.
Also, from our knowledge of vectors we know that if we are given two perpendicular
vectors we can find a third perpendicular vector by taking the cross product.
This means that if we are provided with any two of the camera's vectors
the third is implied through the use of the cross product. There is one difference in the bases that we talked about earlier and the basis of a camera. Before, all the bases we discussed shared the same point for the origin. This time, however, the bases will not since the camera can move anywhere in a 3D environment. In the following picture we have the point (x, y, z) relative to the origin being at (0, 0, 0). We also have a camera placed at (a, b, c). |
|
|
| Something that will be very important in a moment is to find
the position of the point relative to the origin being at (a, b, c). To
do this all you do is subtract (a, b, c) from (x, y, z). Doing this is pretty
much just finding a vector that goes from (a, b, c) and points to (x, y,
z). It is this vector that we will be interseted in when we want to transform
the point to the camera's coordinate system. Now we will derive the rotation matrix to apply to the vectors pointing from the camera to the points in the standard basis; this will complete the transformation and the points will finally be in the camera's coordinate system, ready to render. Your first instinct may be to simply put the components of the vectors into the columns of the rotation matrix. However, there is a little bit more that you need to do. Before, when dealing with bases, we were going from an arbitrary basis to the standard basis. This time, however, we are going from the standard basis to the camera's basis. This means an inverse transformation must be done, thus you simply take the inverse of the camera's basis for the final rotation matrix. Although it may be hard to believe, you have learned everything you need to know about cameras. After covering all of the mathematics only a few things needed to be stated about cameras. Here is a quick reference of the steps taken to view an environment through a camera. 1.) Position all the points in your environment relative
to the x-, y-, and z-axis.
2.) Position the camera somewhere out in space at (a, b, c).
3.) Define the camera's coordinate axis vectors: side, up, out.
4.) Make sure the camera's axes are orthogonal and unit vectors.
5.) Loop through every point in the environment and subtract
the camera's position vector <a, b, c> from the point's
position vector <x, y, z> and store it in a temporary variable.
6.) Create the rotation matrix from the camera's axis vectors:
The CodeI have provided a starting point for you to use a camera with three classes for vectors, matrices, and cameras. The classes are fully documented so you should read them just as you read this tutorial. Practice using them for a little while, see how I coded it, and I think you will find they are very easy to use. You may even want to write your own if you think of a better way to do things. When viewing the demo file provided remember that this is not the usually rotation about the coordinate axes. It is as if you were a camera man for a television show and you can move the camera around and rotate it to view everything from different angles. It may take a second to see what is going on, but I can guarantee that it is much easier to use, faster, and many times easier to control. In the demo the arrow keys control the orientation of the camera. The up and down arrows rotate the camera about its side axis, and the left and right arrows rotate about the world y-axis. The world y-axis is used because it is a much more natural feeling. If you were developing a flight simulator you would use the camera's up vector because it would rotate around that. The W and S keys translate the camera in the direction of the out vector, the A and D keys translate in the direction of the side vector, and the Q and E keys elevate the camera up and down. Good luck. |