Matrix Operations

Now, where a spreadsheet is kind of a free-form matrix, the matrices well be dealing with are a lot more structured, and have all kinds of rules associated with them for what we can do with them and how to do it.

Most instructional material on matrix math that Ive seen takes one of two approaches. The first school describes how to do the operations in detail, using matrices full of seemingly random numbers. You learn the rules, but you have no idea why you are doing certain things or what the result means. Its like playing a game where you arrange the numbers in a pretty pattern.

The second approach is to describe the contents of the matrices in detail and skim over the operation, with vague instructions such as and then you just multiply these two matrices together and get this..., leaving the reader with no idea how this multiplication is done.

To ensure you understand how matrices work, Ive chosen to walk the line between these two methods , starting with presenting some matrices containing meaningful values, and then describing how to manipulate them.

Matrix addition

One of the more common uses of matrices is manipulating 3D points. A 3D point contains a value for x, y, and z positions . We can easily view this as a one by three matrix like so:

 x  y  z 

Now say you want to move this point in space, also called translating the point. What you need to know is how far to move it on each axis. You can put this in a translation matrix . This is another 1—3 matrix that looks something like this:

 dx  dy  dz 

Here, dx , dy , and dz are the distances to move on each axis. Now you need to somehow apply the transformation matrix to the point matrix. This is done with matrix addition, which is pretty simple. You just add each corresponding cell together to make a new matrix containing the sum of each cell . Obviously, to add two matrices, they need to be the same size . For translation, you do this:

 x  y  z   +   dx  dy  dz   = (x + dx)  (y + dy)  (z + dz) 

Here, the resulting matrix could be called x1 , y1 , z1 , and contains the new position of the point after it has been translated. Lets try it with some actual numbers. Say your point was at 100 , 50 , 75 on x , y , z , and you wanted to move it -10 , 20 , -35 . Heres how that would look:

 100  50  75   +   -10  20  -35   =   (100 - 10)  (50 + 20)  (75 - 35) 

Thus, when you perform the addition, you get 90 , 70 , 40 as the points new position. Pretty simple, right? You probably already noticed the correlation to velocity, where the velocity on each axis is added to the position on that axis. Same deal here. Were just looking at it a bit differently.

If you had a larger matrix, you would still carry on the same way, matching up the cells . We wont be dealing with matrix addition for anything larger than three by one matrices here, but Ill give you an abstract example:

 a  b  c       j  k  l       (a + j)  (b + k)  (c + l) d  e  f   +   m  n  o   =   (d + m)  (e + n)  (f + o) g  h  i       p  q  r       (g + p)  (h + q)  (i + r) 

And thats about all you need to know about matrix addition. After I cover matrix multiplication, Ill show you how to put together some actual functions to use in a matrix-based 3D engine.

Matrix multiplication

Much more common for doing 3D transformations is matrix multiplication , which is usually used for scaling and rotating. We wont actually be using 3D scaling in this book, as the examples cover using either points, which cant be scaled, or movie clips, which do not have any 3D thickness and are therefore only scaled in two dimensions. Of course, you could build a more complex engine that could scale an entire 3D solid. Youd then need to write additional functions that would alter the 3D points making up the solid based on the new size. Thats beyond the scope of what were doing here, but since scaling is a very simple and clear demonstration of matrix multiplication, Ill run you through an example.

Scaling with a matrix

First youll need to know an objects existing width, height, and depthin other words, its measurement of size on each of the three axes. This of course creates a 3—1 matrix:

 w  h  d 

As you probably realize, w , h , and d stand for width, height, and depth. Next you need a scaling matrix like the following:

 sx   0   0  0  sy   0  0   0  sz 

Here, sx , sy , and sz are the percentages to scale on that particular axis. These would be in terms of a fraction, so that 1.0 is 100%, 2.0 is 200%, 0.5 is 50%, etc. Youll see why the matrix is laid out this way in a minute.

One thing you need to know about matrix multiplication is that in order to multiply two matrices, the first matrix must have the same number of columns as the second one has rows . The first one can have any number of rows, and the second can have any number of columns, as long as these criteria have been met. In this case, you are fine, as the first matrix has three columns ( w , h , d ), and the scaling matrix has three rows.

So, how do you multiply these things? Let me just go ahead and do it and see if you can see the pattern:

 sx   0   0 w  h  d   *    0  sy   0                0   0  sz 

This produces the following matrix as a result:

 (w*sx + h*0  + d*0)  (w*0  + h*sy + d*0)  (w*0  + h*0  + d*sz) 

When you get rid of all the zeros, it winds up as this:

 (w*sx)  (h*sy)  (d*sz) 

This is pretty logical, as you are multiplying the width (x axis measurement) by the x scaling factor, the height by the y scaling factor, and the depth by the z scaling factor. But, what exactly did we do there? All those zeros are kind of occluding things, so lets abstract it a bit so the pattern is clearer.

 a  b  c u  v  w   *   d  e  f               g  h  i 

Now you can see the pattern emerge in this result:

 (u*a + v*d  + w*g)  (u*b  + v*e + w*h)  (u*c  + v*f  + w*i) 

You can see that you move across the first row of the first matrix (u, v, w) and multiply by each first element in each row of the second (a, d, g) . Adding those together gives you the first element for the first row of the result. Doing the same with the second column of the second matrix (b, e, h) gives you the second column result.

If you have more than one row in the first matrix, you then repeat the actions with that second row, which gives you the second row of the result:

 u  v  w       a  b  c x  y  z   *   d  e  f               g  h  i 

which gives you this 3—2 matrix as a result:

 (u*a + v*d  + w*g)  (u*b  + v*e + w*h)  (u*c  + v*f  + w*i) (x*a + y*d  + z*g)  (x*b  + y*e + z*h)  (x*c  + y*f  + z*i) 

Now lets see some matrix multiplication in something that you will actually usecoordinate rotation. Hopefully the scaling example will make it more clear what were doing.

Coordinate rotation with a matrix

First of all, you need to dig up your 3D point matrix:

 x  y  z 

This will hold the coordinates of the point you want to rotate. Now of course, you need a rotation matrix. As you know, you can rotate on any one of three axes. Youll create each of these types of rotation as separate matrices. Lets start with x axis rotation matrix:

 1    0    0 0   cos  sin 0  -sin  cos 

Now you have some sines and cosines in there, and the obvious question might be, The sine or cosine of what? Well, its the sine or cosine of whatever angle youre rotating by. If youre rotating that point by 45 degrees, it would be the sine and cosine of 45 degrees. (Of course, in code, youd use radians.)

Now, lets perform matrix multiplication with this and a 3D point matrix and see what results you get.

 1    0    0 x  y  z   *   0   cos  sin               0  -sin  cos 

For that, you get

 (x*1 + y*0  + z*0)  (x*0  + y*cos - z*sin)  (x*0  + y*sin  + z*cos) 

Cleaning that up gives you

 (x)  (y*cos - z*sin)  (z*cos + y*sin) 

This translates roughly to the following in ActionScript:

 x = x; y = Math.cos(angle) * y  Math.sin(angle) * z; z = Math.cos(angle) * z + Math.sin(angle) * y; 

Now, if you think back to Chapter 10, where I discussed coordinate rotation, youll see this is exactly how you were accomplishing x axis rotation. This isnt a big surprise, as matrix math is just a different way of looking at and organizing various formulas and equations.

From here, you can easily create a matrix for y axis rotation:

 cos  0  sin   0   1   0 -sin  0  cos 

And finally, one for rotation on the z axis:

 cos  sin  0 -sin  cos  0   0    0   1 

It would be good practice to go ahead and multiply each of these by an x, y, z matrix and verify that you get the same formulas you used for coordinate rotation on those two axes in Chapter 10.

Coding with matrices

OK, you know enough of the basics to start putting this stuff into code. Youll be re-creating a file similar to ch15_12.fla from Chapter 15, so you might want to have that file open as a reference. Actually, you can reuse quite a bit from that file. In ch18_01.fla , I kept the same ball movie clip in the library, exported with the linkage name ball , and then just stripped out the rotation code from ch15_12.fla s code. I replaced that code with a couple of function calls to rotateX and rotateY . Of course, your next step will be to create those functions, but here is your starting point:

 var numBalls:Number = 50; var fl:Number = 250; var vpX:Number = Stage.width / 2; var vpY:Number = Stage.height / 2; init(); function init() {       for (var i:Number = 0; i<numBalls; i++) {             var ball:MovieClip = attachMovie("ball", "ball" + i, i);             ball.x = Math.random() * 200 - 100;             ball.y = Math.random() * 200 - 100;             ball.z = Math.random() * 200 - 100;       } } function onEnterFrame():Void {       for (var i:Number=0;i<numBalls;i++) {             var ball:MovieClip = this["ball" + i];             var angleY:Number = (_xmouse - vpX) * .001;  rotateX(ball, angleX);  var angleX:Number = (_ymouse - vpY) * .001;  rotateY(ball, angleY);  if (ball.z <= -fl) {                   ball._visible = false;             } else {                   ball._visible = true;                   var scale:Number = fl / (fl + ball.z);                   ball._xscale = ball._yscale = scale*100;                   ball._x = vpX + ball.x * scale;                   ball._y = vpY + ball.y * scale;                   ball.swapDepths(-ball.z);             }       } } 

First create the rotateX function. This will take the balls x, y, z coordinates, put these in a 1—3 matrix, and then create an x rotation matrix based on the given angle. These matrices will be in the form of arrays. Finally, it will multiply these two matrices together using the matrixMultiply function, which you also need to create! The result of the multiplication will be another array, so you have to assign those values back to the balls x, y, and z coordinates.

 function rotateX(ball:MovieClip, angle:Number):Void {       var position:Array = [ball.x, ball.y, ball.z];       var sin:Number = Math.sin(angle);       var cos:Number = Math.cos(angle);       var xRotMatrix:Array = new Array();       xRotMatrix[0] = [1,   0,   0 ];       xRotMatrix[1] = [0,  cos, sin];       xRotMatrix[2] = [0, -sin, cos]       var result:Array = matrixMultiply(position, xRotMatrix);       ball.x = result[0];       ball.y = result[1];       ball.z = result[2]; } 

And here is the matrix multiplication function:

 function matrixMultiply(matrixA:Array, matrixB:Array):Array {       var result:Array = new Array();       result[0] = matrixA[0] * matrixB[0][0] +                   matrixA[1] * matrixB[1][0] +                   matrixA[2] * matrixB[2][0];       result[1] = matrixA[0] * matrixB[0][1] +                   matrixA[1] * matrixB[1][1] +                   matrixA[2] * matrixB[2][1];       result[2] = matrixA[0] * matrixB[0][2] +                   matrixA[1] * matrixB[1][2] +                   matrixA[2] * matrixB[2][2];       return result; } 

Now this particular matrix multiplication function is hard-coded to multiply a 3—1 matrix by a 3—3 matrix, since thats what youll be doing in each case. You could use for loops to make a more dynamic function that could handle any sized matrices, but lets keep things simple here.

Finally, create your rotateY function. If you understand the rotateX function, this one should look pretty obvious. You just create a y rotation matrix instead of an x rotation matrix.

 function rotateY(ball:MovieClip, angle:Number):Void {       var position:Array = [ball.x, ball.y, ball.z];       var sin:Number = Math.sin(angle);       var cos:Number = Math.cos(angle);       var yRotMatrix:Array = new Array();       yRotMatrix[0] = [ cos, 0, sin];       yRotMatrix[1] = [  0,  1,  0 ];       yRotMatrix[2] = [-sin, 0, cos]       var result:Array = matrixMultiply(position, yRotMatrix);       ball.x = result[0];       ball.y = result[1];       ball.z = result[2]; } 

And there you have it. You could also create a rotateZ function if you want. Since we dont actually need that for this example, Ill leave it as an exercise for you to do on your own.

Now if you run ch18_01.fla and compare it to ch15_12.fla , I think youll find that the original from Chapter 15 runs a lot smoother. The one using matrix math may have a bit of noticeable choppiness on your computer, as it does on mine. The reason for this is that youre already performing quite extensive math for the 3D rotations , scaling, etc. When you get into matrix math, you wind up doing a whole lot of extra calculations. When you start multiplying the matrices, youre actually doing four multiply-times-zero operations, and adding the four results to other numbers. Thats eight math operations that essentially do nothing at all. Multiply that times 50 objects, and two rotations per frame, and you get 800 superfluous calculations per frame! I guess that explains the choppiness.

What Im trying to say is that the use of matrices of 3D in Flash is not very efficient for large numbers of objects at this time. Some people still prefer to use matrices for 3D though, and it works fine for a small number of objects.

Even if you dont use matrices for 3D, youll still find them useful for other purposes, and Ill cover these next. Use of matrices in 3D provides a nice introduction, as you can see how they relate to formulas you already know. Also, matrices are used extensively for 3D in other languages that are far more efficient than ActionScript currently. In these languages, you can afford to spend a few CPU cycles in order to gain the neat organization that matrices can offer your code. If you wind up attempting 3D animation in anything other than Flash, you are bound to run into matrices again. And, who knows where the Flash player will be in a few years ? There may come a day when these techniques are perfectly suitable for Flash.



Foundation ActionScript. Animation. Making Things Move
Foundation Actionscript 3.0 Animation: Making Things Move!
ISBN: 1590597915
EAN: 2147483647
Year: 2005
Pages: 137
Authors: Keith Peters

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net